Skip to content

Instantly share code, notes, and snippets.

@alram
Created June 27, 2012 13:32
Show Gist options
  • Save alram/3004085 to your computer and use it in GitHub Desktop.
Save alram/3004085 to your computer and use it in GitHub Desktop.
vmadm create-json
diff --git a/src/vm/node_modules/VM.js b/src/vm/node_modules/VM.js
index 1dbbbdb..2a44fe8 100644
--- a/src/vm/node_modules/VM.js
+++ b/src/vm/node_modules/VM.js
@@ -34,6 +34,7 @@
*
* console(uuid, callback)
* create(properties, callback)
+ * create-json(file, callback)
* delete(uuid, callback)
* flatten(vmobj, key)
* info(uuid, types, callback)
@@ -7321,3 +7322,298 @@ exports.console = function (uuid, callback)
}
});
};
+
+/*
+ * validate and write a set prop
+ * - shell.type: main, add
+ * - shell.context: main, disks, nics, filesystems
+ * - prop: Array[0]: property, Array[1]: value
+ * - zonedef: JSON file
+ * - callback: error
+ */
+//TODO: case were a set prop is a list (e.g. resolvers). Do an add prop ?
+
+function writeSetPropToJSON(shell, prop, zonedef, callback) {
+
+ if (!prop[1]) {
+ return callback('Error: No value specified');
+ }
+
+ var field = prop[0].replace(/('|"| )/g, '');
+ var value = prop[1].replace(/('|"| )/g, '');
+
+
+ //zone brand first
+ if (typeof zonedef.brand === 'undefined' && field !== 'brand') {
+ return callback('Error: You must specify a zone brand first');
+ }
+
+ if (field === 'brand') {
+ if (typeof BRAND_OPTIONS[value] !== 'undefined') {
+ zonedef.brand = value;
+ }
+ else {
+ return callback('Error: ' + value + ' is not a correct brand.');
+ }
+ }
+
+ // nic, disk and fs payloads are added with `add`
+ if (field.match(/(nics|disks|filesystems)/g)) {
+ return callback('You must use add (disk|net|fs) to setup this property');
+ }
+
+
+ //brand is setup we can accept allowed and required payloads
+ if (shell.type === 'main' && zonedef.brand !== 'undefined') {
+
+ // Allowed/Required and create-able for this brand ?
+ if ((BRAND_OPTIONS[zonedef.brand].allowed_properties.hasOwnProperty(field)
+ && BRAND_OPTIONS[zonedef.brand].allowed_properties[field].indexOf('create') !== -1)
+ ||(BRAND_OPTIONS[zonedef.brand].required_properties.hasOwnProperty(field)
+ && BRAND_OPTIONS[zonedef.brand].required_properties[field].indexOf('create') !== -1)) {
+
+ if (field === 'brand' && !BRAND_OPTIONS.hasOwnProperty(value)) {
+ return callback('Error: ' + value + ' is not a correct brand.');
+ }
+
+ zonedef[field] = value;
+
+ } else {
+ return callback('Error: ' + field + ' is not a valide property.');
+ }
+
+ } else if (shell.type === 'add') {
+
+ var prefix = shell.context + '.*.'
+
+ //nothing required, only allowed
+ if (!BRAND_OPTIONS[zonedef.brand].allowed_properties.hasOwnProperty(prefix+field)) {
+ return callback('Error: ' + field + ' is not a valide property.');
+ }
+
+ // add property at (length - 1)
+ var pointer = zonedef[shell.context].length - 1;
+ zonedef[shell.context][pointer][field] = value;
+
+ }
+
+ callback(null);
+};
+
+
+function zonedefFileLoad(filename, callback) {
+ fs.stat(filename, function (err, stats) {
+ if (err) {
+ callback(null, filename + ' does not exists.\nUse \'set brand\' to begin.');
+ } else {
+ if (stats.isFile()) {
+ //TODO: Read file; check for syntax; check for brand; cb()
+ callback();
+ } else {
+ callback('Error: ' + filename + ' is not a file.');
+ }
+ }
+ });
+}
+
+function zonedefShell(filename, callback) {
+
+ var zonedef = {};
+
+ /*
+ * shell.type is where we are globaly
+ * to know what command are allowed
+ * - main: add, commit, info, remove, set, quit
+ * - add: cancel, end, info, set
+ * shell.context is what we add (disks, nics, filesystems)
+ */
+ var shell = {
+ type: 'main',
+ context: 'main'
+ };
+
+ var rl = readline.createInterface(process.stdin, process.stdout);
+ var prefix = 'zonedef> ';
+ rl.setPrompt(prefix, prefix.length);
+ rl.prompt();
+
+ rl.on('line', function (input) {
+ var cmd = [];
+ cmd[0] = input.trim().split(' ')[0];
+ cmd[1] = '';
+ for (var i = 1; i < input.trim().split(' ').length; i++) {
+ cmd[1] += input.trim().split(' ')[i];
+ }
+
+ if (shell.type === 'main') {
+
+ //TODO: Missing zonecfg commands (e.g remove)
+
+ switch (cmd[0]) {
+
+ case 'set':
+ var prop = cmd[1].split('=');
+ writeSetPropToJSON(shell, prop, zonedef, function (err) {
+ if(err) {
+ console.error(err);
+ }
+ rl.prompt();
+ });
+ break;
+
+ case 'add':
+ if (typeof zonedef.brand === 'undefined') {
+ console.error('Error: You must specify a zone brand first!');
+
+ } else if(cmd[1] !== 'disk' && cmd[1] !== 'net' && cmd[1] !== 'fs') {
+ console.error('Error: ' + cmd[1] + ' is not a valid command.');
+
+ } else {
+ shell.type = 'add';
+ shell.context = cmd[1];
+
+ if (cmd[1] === 'disk') {
+ shell.context = 'disks';
+ } else if (cmd[1] === 'net') {
+ shell.context = 'nics';
+ } else if (cmd[1] === 'fs') {
+ shell.context = 'filesystems';
+ }
+
+
+ //Can't add a disk in a zone
+ //Can't use fs in a VM
+ if (shell.context === 'disks' && zonedef.brand !== 'kvm') {
+ shell.type = shell.context = 'main';
+ console.error('Error: Adding a disk is only supported on KVM VM. Use add fs instead');
+ } else if (shell.context === 'filesystems' && zonedef.brand === 'kvm') {
+ shell.type = shell.context = 'main';
+ console.error('Error: Filesystems features is not supported on KVM VM. Use add disk instead')
+ } else {
+ if (typeof zonedef[shell.context] === 'undefined') {
+ zonedef[shell.context] = [];
+ }
+
+ zonedef[shell.context].push({});
+
+ var prefix = 'zonedef:' + cmd[1] + '> ';
+ rl.setPrompt(prefix, prefix.length);
+ }
+ }
+ rl.prompt();
+
+ break;
+
+ case 'verify':
+ // Verify does *not* verify type of prop. Only required_properties
+ if (typeof zonedef.brand === 'undefined') {
+ console.error('Error: Missing property: brand');
+ } else {
+ for (var prop in BRAND_OPTIONS[zonedef.brand].required_properties) {
+ if (typeof zonedef[prop] === 'undefined') {
+ console.error('Error: Missing property: ' + prop);
+ }
+ }
+ }
+ rl.prompt();
+ break;
+
+ case 'commit':
+ fs.writeFile(filename, JSON.stringify(zonedef), 'utf-8', function (err) {
+ if(err) {
+ console.error('Error: ' + err);
+ } else {
+ console.log('Succesfully written zone definication file ' + filename + '.')
+ }
+ rl.prompt();
+ });
+ break;
+
+ case 'info':
+ console.log(zonedef);
+ rl.prompt();
+ break;
+
+ case 'quit':
+ rl.close();
+ callback();
+ break;
+
+ default:
+ console.error('Error: unknown command ' + cmd[0] + '.');
+ rl.prompt();
+ break;
+ }
+
+ } else if (shell.type === 'add') {
+
+ switch (cmd[0]) {
+
+ case 'cancel':
+ zonedef[shell.context].pop();
+ if (zonedef[shell.context].length === 0) {
+ delete zonedef[shell.context];
+ }
+
+ case 'end':
+ var prefix = 'zonedef> ';
+ rl.setPrompt(prefix, prefix.length);
+ rl.prompt();
+ shell.type = 'main';
+ shell.context = 'main';
+ break;
+
+ case 'info':
+ var length = zonedef[shell.context].length;
+ console.log(zonedef[shell.context][length-1]);
+ rl.prompt();
+ break;
+
+ case 'set':
+ var prop = cmd[1].split('=');
+ writeSetPropToJSON(shell, prop, zonedef, function (err) {
+ if(err) {
+ console.error(err);
+ }
+ rl.prompt();
+ });
+ break;
+
+ default:
+ console.error('Error: unknown command ' + cmd[0] + '.');
+ rl.prompt();
+ break;
+
+ }
+ }
+
+ });
+
+}
+
+/*
+ * vmadm create-json is a zonecfg(1M) like command
+ * which allows to create the json file
+ * used by `vmadm create`.
+ * TODO: needs mod to load zonedef file if already exists
+ */
+var readline = require('readline');
+exports.createJson = function (filename, callback) {
+
+ zonedefFileLoad(filename, function (err, message) {
+ if (err) {
+ callback(err);
+ } else {
+ if (message) console.log(message);
+ zonedefShell(filename, function (err, message) {
+ if (err) {
+ callback(err);
+ } else {
+ callback(message);
+ }
+ });
+ }
+ });
+
+}
+
diff --git a/src/vm/sbin/vmadm.js b/src/vm/sbin/vmadm.js
index a3d6b7a..1561ba4 100755
--- a/src/vm/sbin/vmadm.js
+++ b/src/vm/sbin/vmadm.js
@@ -34,7 +34,7 @@ var sprintf = require('sprintf').sprintf;
var tty = require('tty');
var util = require('util');
-// VM.DEBUG=true;
+VM.DEBUG=true;
var COMMANDS = [
'start', 'boot',
@@ -52,7 +52,8 @@ var COMMANDS = [
'receive', 'recv',
'send',
'sysrq',
- 'update'
+ 'update',
+ 'create-json'
];
/*
@@ -121,6 +122,7 @@ function usage(message, code)
out('Usage: ' + process.argv[1] + ' <command> [options]');
out('');
out('create [-f <filename>]');
+ out('create-json [-f <filename>]');
out('console <uuid>');
out('delete <uuid>');
out('get <uuid>');
@@ -322,6 +324,7 @@ function addCommandOptions(command, opts, shorts)
shorts['1'] = ['--unique'];
break;
case 'create':
+ case 'create-json':
case 'receive':
case 'recv':
case 'update':
@@ -855,7 +858,22 @@ function main(callback)
}
});
break;
- default:
+ case 'create-json':
+ if (parsed.hasOwnProperty('file') && parsed.file !== '-') {
+ filename = parsed.file;
+ }
+ else {
+ callback('Error: no file specified.');
+ }
+ VM.createJson(filename, function (err) {
+ if (err) {
+ callback(err);
+ } else {
+ callback();
+ }
+ });
+ break;
+ default:
callback();
break;
}
@@ -877,3 +895,4 @@ onlyif.rootInSmartosGlobal(function (err) {
process.exit(0);
});
});
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment