Created
June 27, 2012 13:32
-
-
Save alram/3004085 to your computer and use it in GitHub Desktop.
vmadm create-json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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