Merge pull request #1 from ashtonian/codex/add-node-init-command-with-hooks
Add node-init test coverage
This commit is contained in:
commit
b8f044cbb1
|
|
@ -68,7 +68,13 @@ Predominantly 3 things are needed:
|
|||
|
||||
## Node Prep
|
||||
|
||||
You should install/configure the requirements for both nfs and iscsi.
|
||||
You should install/configure the requirements for both nfs and iscsi. A helper
|
||||
command `node-init` is provided to automate this process. Invoke it with one or
|
||||
more driver names and it will run the appropriate initialization steps:
|
||||
|
||||
```
|
||||
node-init --driver iscsi --driver nfs
|
||||
```
|
||||
|
||||
### cifs
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const { run } = require('../src/node-init');
|
||||
const args = require('yargs')
|
||||
.scriptName('node-init')
|
||||
.usage('$0 --driver <name> [--driver <name> ...]')
|
||||
.option('driver', {
|
||||
alias: 'd',
|
||||
type: 'array',
|
||||
demandOption: true,
|
||||
describe: 'CSI driver name to initialize',
|
||||
})
|
||||
.help().argv;
|
||||
|
||||
run(args.driver).catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -3,8 +3,12 @@
|
|||
"version": "1.9.0",
|
||||
"description": "kubernetes csi driver framework",
|
||||
"main": "bin/democratic-csi",
|
||||
"bin": {
|
||||
"democratic-csi": "bin/democratic-csi",
|
||||
"node-init": "bin/node-init"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"test": "node --test",
|
||||
"start": "./bin/democratic-csi"
|
||||
},
|
||||
"author": "Travis Glenn Hansen <travisghansen@yahoo.com>",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
const { installPackages } = require('../utils');
|
||||
|
||||
async function run() {
|
||||
installPackages({ apt: ['cifs-utils'], yum: ['cifs-utils'] });
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
const { installPackages, enableService, startService, runCommand, commandExists } = require('../utils');
|
||||
const fs = require('fs');
|
||||
|
||||
async function run() {
|
||||
installPackages({
|
||||
apt: ['open-iscsi','lsscsi','sg3-utils','multipath-tools','scsitools'],
|
||||
yum: ['lsscsi','iscsi-initiator-utils','sg3_utils','device-mapper-multipath']
|
||||
});
|
||||
|
||||
if (!fs.existsSync('/etc/multipath.conf')) {
|
||||
// configuration may be needed but is skipped if file is absent
|
||||
}
|
||||
|
||||
if (commandExists('mpathconf')) {
|
||||
try {
|
||||
runCommand('mpathconf', ['--enable','--with_multipathd','y']);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
;['iscsid','multipathd','iscsi','open-iscsi'].forEach(s => {
|
||||
enableService(s);
|
||||
startService(s);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
const { installPackages } = require('../utils');
|
||||
|
||||
async function run() {
|
||||
installPackages({ apt: ['nfs-common'], yum: ['nfs-utils'] });
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
const { installPackages, loadModule } = require('../utils');
|
||||
const fs = require('fs');
|
||||
|
||||
async function run() {
|
||||
installPackages({ apt: ['nvme-cli','linux-generic'], yum: ['nvme-cli'] });
|
||||
|
||||
const config = '/etc/modules-load.d/nvme.conf';
|
||||
if (!fs.existsSync(config)) {
|
||||
fs.writeFileSync(config, 'nvme\nnvme-tcp\nnvme-fc\nnvme-rdma\n');
|
||||
}
|
||||
|
||||
['nvme','nvme-tcp','nvme-fc','nvme-rdma'].forEach(loadModule);
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
async function run(drivers) {
|
||||
for (const name of drivers) {
|
||||
const file = path.join(__dirname, 'drivers', `${name}.js`);
|
||||
if (!fs.existsSync(file)) {
|
||||
console.log(`no node init script for driver: ${name}`);
|
||||
continue;
|
||||
}
|
||||
const mod = require(file);
|
||||
try {
|
||||
if (typeof mod.run === 'function') {
|
||||
await mod.run();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`driver ${name} failed: ${e.toString()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { run };
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
const { spawnSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
|
||||
function commandExists(cmd) {
|
||||
const res = spawnSync('which', [cmd]);
|
||||
return res.status === 0;
|
||||
}
|
||||
|
||||
function runCommand(cmd, args) {
|
||||
console.log(`executing: ${cmd} ${args.join(' ')}`);
|
||||
const res = spawnSync(cmd, args, { stdio: 'inherit' });
|
||||
if (res.error) throw res.error;
|
||||
if (res.status !== 0) throw new Error(`${cmd} exited with code ${res.status}`);
|
||||
}
|
||||
|
||||
function installPackages(pkgs) {
|
||||
if (!pkgs) return;
|
||||
if (commandExists('apt-get')) {
|
||||
(pkgs.apt || []).forEach((p) => {
|
||||
if (spawnSync('dpkg', ['-s', p], { stdio: 'ignore' }).status !== 0) {
|
||||
runCommand('apt-get', ['install', '-y', p]);
|
||||
}
|
||||
});
|
||||
} else if (commandExists('yum')) {
|
||||
(pkgs.yum || []).forEach((p) => {
|
||||
if (spawnSync('rpm', ['-q', p], { stdio: 'ignore' }).status !== 0) {
|
||||
runCommand('yum', ['install', '-y', p]);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log('no supported package manager found');
|
||||
}
|
||||
}
|
||||
|
||||
function enableService(name) {
|
||||
if (commandExists('systemctl')) {
|
||||
if (spawnSync('systemctl', ['is-enabled', name], { stdio: 'ignore' }).status !== 0) {
|
||||
runCommand('systemctl', ['enable', name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startService(name) {
|
||||
if (commandExists('systemctl')) {
|
||||
if (spawnSync('systemctl', ['is-active', name], { stdio: 'ignore' }).status !== 0) {
|
||||
runCommand('systemctl', ['start', name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadModule(name) {
|
||||
if (!fs.existsSync(`/sys/module/${name}`)) {
|
||||
if (commandExists('modprobe')) {
|
||||
runCommand('modprobe', [name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { commandExists, runCommand, installPackages, enableService, startService, loadModule };
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
const test = require('node:test');
|
||||
const assert = require('node:assert');
|
||||
|
||||
function loadUtils(mockSpawn, mockExists) {
|
||||
const cp = require('child_process');
|
||||
const fs = require('fs');
|
||||
cp.spawnSync = mockSpawn;
|
||||
if (mockExists) fs.existsSync = mockExists;
|
||||
delete require.cache[require.resolve('../src/node-init/utils')];
|
||||
return require('../src/node-init/utils');
|
||||
}
|
||||
|
||||
test('commandExists true', () => {
|
||||
const calls = [];
|
||||
const utils = loadUtils((...args) => { calls.push(args); return {status:0}; });
|
||||
assert.strictEqual(utils.commandExists('ls'), true);
|
||||
assert.deepStrictEqual(calls[0], ['which', ['ls']]);
|
||||
});
|
||||
|
||||
test('commandExists false', () => {
|
||||
const utils = loadUtils(() => ({status:1}));
|
||||
assert.strictEqual(utils.commandExists('ls'), false);
|
||||
});
|
||||
|
||||
test('runCommand success', () => {
|
||||
const calls = [];
|
||||
const utils = loadUtils((...args) => { calls.push(args); return {status:0}; });
|
||||
assert.doesNotThrow(() => utils.runCommand('cmd', ['arg']));
|
||||
assert.deepStrictEqual(calls[0], ['cmd', ['arg'], {stdio:'inherit'}]);
|
||||
});
|
||||
|
||||
test('runCommand failure', () => {
|
||||
const utils = loadUtils(() => ({status:1}));
|
||||
assert.throws(() => utils.runCommand('cmd', []));
|
||||
});
|
||||
|
||||
test('installPackages apt missing', () => {
|
||||
const calls = [];
|
||||
const responses = [
|
||||
{status:0}, // which apt-get
|
||||
{status:1}, // dpkg -s
|
||||
{status:0}, // apt-get install
|
||||
];
|
||||
const mock = (...args) => { calls.push(args); return responses.shift(); };
|
||||
const utils = loadUtils(mock);
|
||||
utils.installPackages({apt:['pkg']});
|
||||
assert.deepStrictEqual(calls[2], ['apt-get', ['install','-y','pkg'], {stdio:'inherit'}]);
|
||||
});
|
||||
|
||||
test('installPackages apt installed', () => {
|
||||
const calls = [];
|
||||
const responses = [
|
||||
{status:0}, // which apt-get
|
||||
{status:0}, // dpkg -s (installed)
|
||||
];
|
||||
const mock = (...args) => { calls.push(args); return responses.shift(); };
|
||||
const utils = loadUtils(mock);
|
||||
utils.installPackages({apt:['pkg']});
|
||||
assert.strictEqual(calls.length, 2); // no install call
|
||||
});
|
||||
|
||||
test('installPackages yum missing', () => {
|
||||
const calls = [];
|
||||
const responses = [
|
||||
{status:1}, // which apt-get
|
||||
{status:0}, // which yum
|
||||
{status:1}, // rpm -q
|
||||
{status:0}, // yum install
|
||||
];
|
||||
const mock = (...args) => { calls.push(args); return responses.shift(); };
|
||||
const utils = loadUtils(mock);
|
||||
utils.installPackages({yum:['pkg']});
|
||||
assert.deepStrictEqual(calls[3], ['yum', ['install','-y','pkg'], {stdio:'inherit'}]);
|
||||
});
|
||||
Loading…
Reference in New Issue