From ffe5cb3b9ce624c4310d994bf7768a57dd7734db Mon Sep 17 00:00:00 2001 From: Nurfet Becirevic Date: Sat, 30 Sep 2017 00:46:48 +0200 Subject: [PATCH 1/8] Add image aliases --- features/image.js | 7 +++++++ features/volume.js | 2 ++ helpers.js | 5 ++++- package.json | 6 +++--- profitbricks.js | 3 ++- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/features/image.js b/features/image.js index 4071032..3775cee 100644 --- a/features/image.js +++ b/features/image.js @@ -50,6 +50,13 @@ function processImage(params) { pbclient.deleteImage(params.id, helpers.printInfo) } break + case 'aliases': + if (!params.location) { + console.error('Please provide Location Id -l [location]') + process.exit(code = 5) + } + pbclient.getLocation(params.location, helpers.printInfo) + break default: params.outputHelp() break diff --git a/features/volume.js b/features/volume.js index 06ce8e3..a84ee3f 100644 --- a/features/volume.js +++ b/features/volume.js @@ -92,6 +92,8 @@ function createVolume(params) { data.properties.licenceType = params.licencetype if (params.imageid) data.properties.image = params.imageid + if (params.imagealias) + data.properties.imageAlias = params.imagealias if (params.type) data.properties.type = params.type else { diff --git a/helpers.js b/helpers.js index bfff062..af86146 100644 --- a/helpers.js +++ b/helpers.js @@ -77,7 +77,7 @@ function printInfo(error, response, body) { printResults('Volume', [printVolume(info)]) break case 'image': - printResults('Volume', [printImage(info)]) + printResults('Image', [printImage(info)]) break case 'snapshot': printResults('Snapshot', [printSnapshot(info)]) @@ -100,6 +100,9 @@ function printInfo(error, response, body) { case 'collection': printCollection(info) break + case 'location': + printResults('Image Alias', info.properties.imageAliases) + break case 'request-status': if (!isJson) { console.log("Status: " + info.metadata.targets[0].status) diff --git a/package.json b/package.json index 265a56d..bac1781 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,19 @@ { "name": "profitbricks-cli", - "version": "3.1.0", + "version": "4.0.0", "license": "Apache-2.0", "scripts": { "start": "node profitbricks.js", "test": "node ./test/tests.js" }, - "preferGlobal": "true", + "preferGlobal": true, "bin": { "profitbricks": "./profitbricks" }, "dependencies": { "commander": "^2.7.1", "console.table": "^0.4.0", - "libprofitbricks": "3.0.2", + "libprofitbricks": "4.0.1", "prompt": "^0.2.14", "request": "^2.53.0" }, diff --git a/profitbricks.js b/profitbricks.js index 1393390..3010441 100644 --- a/profitbricks.js +++ b/profitbricks.js @@ -38,7 +38,7 @@ parseParameters() function initializeCli() { program - .version('3.1.0') + .version('4.0.0') .usage('[Options]') .option('setup', 'Configures credentials for ProfitBricks CLI') .option('datacenter, [env]', 'Data center operations') @@ -72,6 +72,7 @@ function initializeCli() { .option('--volumesize [env]', 'Volume size') .option('--volumename [env]', 'Volume name') .option('--imageid [env]', 'Image id') + .option('--imagealias [env]', 'Image alias') .option('-b --bus [env]', 'Bus type (VIRTIO or IDE)') .option('-t --type [env]', 'The disk type.') .option('--imagepassword [env]', 'One-time password is set on the Image for the appropriate account. Password has to contain 8-50 characters. Only these characters are allowed: [abcdefghjkmnpqrstuvxABCDEFGHJKLMNPQRSTUVX23456789]') From c6420164a93d91e067ac2a743c8e1e84805ee3dc Mon Sep 17 00:00:00 2001 From: Nurfet Becirevic Date: Thu, 5 Oct 2017 07:46:22 +0200 Subject: [PATCH 2/8] User management and IP failover features --- features/group.js | 133 +++++++++++++++++++++++++++++++++++++++++++ features/lan.js | 15 +++++ features/resource.js | 36 ++++++++++++ features/share.js | 93 ++++++++++++++++++++++++++++++ features/user.js | 132 ++++++++++++++++++++++++++++++++++++++++++ helpers.js | 94 ++++++++++++++++++++++++++++-- profitbricks.js | 38 ++++++++++++- 7 files changed, 534 insertions(+), 7 deletions(-) create mode 100644 features/group.js create mode 100644 features/resource.js create mode 100644 features/share.js create mode 100644 features/user.js diff --git a/features/group.js b/features/group.js new file mode 100644 index 0000000..6504934 --- /dev/null +++ b/features/group.js @@ -0,0 +1,133 @@ +var pbclient = require('libprofitbricks') +var prompt = require('prompt') +var helpers = require('../helpers') +var fs = require('fs') + +exports.process = processGroup + +function processGroup(params) { + switch (params.group) { + case 'list': + pbclient.listGroups(helpers.printInfo) + break + case 'get': + case 'show': + if (!params.id || params.id == true) { + console.error("Group ID is a required field. -i [env]") + process.exit(code = 5) + } + pbclient.getGroup(params.id, helpers.printInfo) + break + case 'create': + createGroup(params) + break + case 'update': + updateGroup(params) + break + case 'delete': + if (!params.id || params.id == true) { + console.error("Group ID is a required field. -i [env]") + process.exit(code = 5) + } + + if (!global.force) { + pbclient.getGroup(params.id, function(error, response, body) { + if (response.statusCode > 299) { + console.log("Object you are trying to delete does not exist") + + } else { + var info = JSON.parse(body) + + console.log('You are about to delete "' + info.properties.name + '" Group. Do you want to proceed? (y/n)') + prompt.get(['yes'], function(err, result) { + if (result.yes == 'yes' || result.yes == 'y' || result.yes == '') + pbclient.deleteGroup(params.id, helpers.printInfo) + else + process.exit(code = 0) + }) + } + }) + } else + pbclient.deleteGroup(params.id, helpers.printInfo) + break + case 'user': + if (!params.id || params.id == true) { + console.error("Group ID is a required field. -i [env]") + process.exit(code = 5) + } + if (!params.adduser && !params.removeuser) { + console.error("User ID is a required field. --adduser [env] | --removeuser [env]") + process.exit(code = 5) + } + if (params.adduser) { + user = {} + user.id = params.adduser + pbclient.addGroupUser(params.id, user, helpers.printInfo) + } else + pbclient.removeGroupUser(params.id, params.removeuser, helpers.printInfo) + break + case 'users': + if (!params.id || params.id == true) { + console.error("Group ID is a required field. -i [env]") + process.exit(code = 5) + } + pbclient.listGroupUsers(params.id, helpers.printInfo) + break + default: + params.outputHelp() + break + } +} + +function createGroup(params) { + var data = {} + try { + if (params.path) { + data = JSON.parse(fs.readFileSync(params.path, 'utf8')) + } else { + data.properties = {} + if (params.name) + data.properties.name = params.name + else { + console.error("Name is a required field.") + process.exit(code = 5) + } + if (params.createdatacenter) + data.properties.createDataCenter = params.createdatacenter + if (params.createsnapshot) + data.properties.createSnapshot = params.createsnapshot + if (params.reserveip) + data.properties.reserveIp = params.reserveip + if (params.accessactlog) + data.properties.accessActivityLog = params.accessactlog + } + } finally { + pbclient.createGroup(data, helpers.printInfo) + } +} + +function updateGroup(params) { + var data = {} + + if (!params.id) { + console.error("Group Id is a required field.") + process.exit(code = 5) + } + data.properties = {} + if (params.name) + data.properties.name = params.name + else { + console.error("Name is a required field.") + process.exit(code = 5) + } + if (params.createdatacenter) + data.properties.createDataCenter = params.createdatacenter + if (params.createsnapshot) + data.properties.createSnapshot = params.createsnapshot + if (params.reserveip) + data.properties.reserveIp = params.reserveip + if (params.accessactlog) + data.properties.accessActivityLog = params.accessactlog + + pbclient.updateGroup(params.id, data, helpers.printInfo) +} diff --git a/features/lan.js b/features/lan.js index d4feb5b..574f992 100644 --- a/features/lan.js +++ b/features/lan.js @@ -66,6 +66,21 @@ function updateLan(params) { data.public = true } } + if (params.ipfailover) { + data.ipFailover = [] + var fg = params.ipfailover.split(";") + for (var i = 0; i < fg.length; i++) { + var pair = fg[i].split(",") + if (pair.length != 2) { + console.error('Failover group must be formated as "ip1,nicid1;ip2,nicid2;ip3,nicid3...", e.g. "208.94.36.95,2793c08f-1548-4903-87f8-fcad40b2680a;208.94.36.99,510d24b1-f363-4dbb-8e97-f3572a884719"') + process.exit(code = 5) + } + var lanFailover = {} + lanFailover.ip = pair[0].trim() + lanFailover.nicUuid = pair[1].trim() + data.ipFailover.push(lanFailover) + } + } pbclient.patchLan(params.datacenterid, params.id, data, helpers.printInfo) } diff --git a/features/resource.js b/features/resource.js new file mode 100644 index 0000000..6e65085 --- /dev/null +++ b/features/resource.js @@ -0,0 +1,36 @@ +var pbclient = require('libprofitbricks') +var prompt = require('prompt') +var helpers = require('../helpers') +var fs = require('fs') + +exports.process = processResources + +// listing resources may be time-consuming +pbclient.setdepth(1) + + +function processResources(params) { + switch (params.resource) { + case 'list': + if (params.resourcetype) + pbclient.listResourcesByType(params.resourcetype, helpers.printInfo) + else + pbclient.listResources(helpers.printInfo) + break; + case 'get': + case 'show': + if (!params.resourcetype || params.resourcetype == true) { + console.error("Resource type is a required field. --resourcetype [env]") + process.exit(code = 5) + } + if (!params.id || params.id == true) { + console.error("Resource ID is a required field. -i [env]") + process.exit(code = 5) + } + pbclient.getResourceByType(params.resourcetype, params.id, helpers.printInfo) + break; + default: + params.outputHelp() + break + } +} diff --git a/features/share.js b/features/share.js new file mode 100644 index 0000000..a90068e --- /dev/null +++ b/features/share.js @@ -0,0 +1,93 @@ +var pbclient = require('libprofitbricks') +var prompt = require('prompt') +var helpers = require('../helpers') +var fs = require('fs') + +exports.process = processShare + +function processShare(params) { + if (!params.groupid || params.groupid == true) { + console.error("Group ID is a required field. --groupid [env]") + process.exit(code = 5) + } + switch (params.share) { + case 'list': + pbclient.listShares(params.groupid, helpers.printInfo) + break + case 'get': + case 'show': + if (!params.id || params.id == true) { + console.error("Share ID is a required field. -i [env]") + process.exit(code = 5) + } + pbclient.getShare(params.groupid, params.id, helpers.printInfo) + break + case 'add': + case 'create': + addShare(params) + break + case 'update': + updateShare(params) + break + case 'delete': + case 'remove': + if (!params.id || params.id == true) { + console.error("Share ID is a required field. -i [env]") + process.exit(code = 5) + } + + if (!global.force) { + pbclient.getShare(params.groupid, params.id, function(error, response, body) { + if (response.statusCode > 299) { + console.log("Resource you are trying to unshare does not exist") + + } else { + var info = JSON.parse(body) + + console.log('You are about to unshare "' + info.id + '" Resource. Do you want to proceed? (y/n)') + prompt.get(['yes'], function(err, result) { + if (result.yes == 'yes' || result.yes == 'y' || result.yes == '') + pbclient.removeShare(params.groupid, params.id, helpers.printInfo) + else + process.exit(code = 0) + }) + } + }) + } else + pbclient.removeShare(params.id, helpers.printInfo) + break + default: + params.outputHelp() + break + } +} + +function addShare(params) { + var data = {} + data.properties = {} + if (!params.resourceid || params.resourceid == true) { + console.error("ID of the resource to share is a required field. --resourceid [env]") + process.exit(code = 5) + } + if (params.editprivilege) + data.properties.editPrivilege = params.editprivilege + if (params.shareprivilege) + data.properties.sharePrivilege = params.shareprivilege + + pbclient.addShare(params.groupid, params.resourceid, data, helpers.printInfo) +} + +function updateShare(params) { + if (!params.id || params.id == true) { + console.error("Share ID is a required field. -i [env]") + process.exit(code = 5) + } + var data = {} + data.properties = {} + if (params.editprivilege) + data.properties.editPrivilege = params.editprivilege + if (params.shareprivilege) + data.properties.sharePrivilege = params.shareprivilege + + pbclient.updateShare(params.groupid, params.id, data, helpers.printInfo) +} diff --git a/features/user.js b/features/user.js new file mode 100644 index 0000000..d4bdf14 --- /dev/null +++ b/features/user.js @@ -0,0 +1,132 @@ +var pbclient = require('libprofitbricks') +var prompt = require('prompt') +var helpers = require('../helpers') +var fs = require('fs') + +exports.process = processUser + +function processUser(params) { + switch (params.user) { + case 'list': + pbclient.listUsers(helpers.printInfo) + break + case 'get': + case 'show': + if (!params.id || params.id == true) { + console.error("User ID is a required field. -i [env]") + process.exit(code = 5) + } + pbclient.getUser(params.id, helpers.printInfo) + break + case 'create': + createUser(params) + break + case 'update': + updateUser(params) + break + case 'delete': + if (!params.id || params.id == true) { + console.error("User ID is a required field. -i [env]") + process.exit(code = 5) + } + + if (!global.force) { + pbclient.getUser(params.id, function(error, response, body) { + if (response.statusCode > 299) { + console.log("Object you are trying to delete does not exist") + + } else { + var info = JSON.parse(body) + + console.log('You are about to delete "' + info.properties.firstname + ' ' + info.properties.lastname + '" User. Do you want to proceed? (y/n)') + prompt.get(['yes'], function(err, result) { + if (result.yes == 'yes' || result.yes == 'y' || result.yes == '') + pbclient.deleteUser(params.id, helpers.printInfo) + else + process.exit(code = 0) + }) + } + }) + } else + pbclient.deleteUser(params.id, helpers.printInfo) + break + default: + params.outputHelp() + break + } +} + +function createUser(params) { + var data = {} + try { + if (params.path) { + data = JSON.parse(fs.readFileSync(params.path, 'utf8')) + } else { + data.properties = {} + if (params.firstname) + data.properties.firstname = params.firstname + else { + console.error("First name is a required field.") + process.exit(code = 5) + } + if (params.lastname) + data.properties.lastname = params.lastname + else { + console.error("Last name is a required field.") + process.exit(code = 5) + } + if (params.email) + data.properties.email = params.email + else { + console.error("Email is a required field.") + process.exit(code = 5) + } + if (params.password) + data.properties.password = params.password + else { + console.error("Password is a required field.") + process.exit(code = 5) + } + if (params.admin) + data.properties.administrator = params.admin + if (params.forcesecauth) + data.properties.forceSecAuth = params.forcesecauth + } + } finally { + pbclient.createUser(data, helpers.printInfo) + } +} + +function updateUser(params) { + var data = {} + + if (!params.id || params.id == true) { + console.error("User Id is a required field.") + process.exit(code = 5) + } + data.properties = {} + if (params.firstname) + data.properties.firstname = params.firstname + else { + console.error("First name is a required field.") + process.exit(code = 5) + } + if (params.lastname) + data.properties.lastname = params.lastname + else { + console.error("Last name is a required field.") + process.exit(code = 5) + } + if (params.email) + data.properties.email = params.email + else { + console.error("Email is a required field.") + process.exit(code = 5) + } + if (params.admin) + data.properties.administrator = params.admin + if (params.forcesecauth) + data.properties.forceSecAuth = params.forcesecauth + + pbclient.updateUser(params.id, data, helpers.printInfo) +} diff --git a/helpers.js b/helpers.js index af86146..889b221 100644 --- a/helpers.js +++ b/helpers.js @@ -68,7 +68,10 @@ function printInfo(error, response, body) { if (body) { switch (info.type) { case 'datacenter': - printResults('Datacenter', [printDc(info)]) + if (info.href.indexOf('um/resources/datacenter') > -1) + printResults('Resource', [printResource(info)]) + else + printResults('Datacenter', [printDc(info)]) break case 'server': printResults('Server', [printServer(info)]) @@ -77,10 +80,16 @@ function printInfo(error, response, body) { printResults('Volume', [printVolume(info)]) break case 'image': - printResults('Image', [printImage(info)]) + if (info.href.indexOf('um/resources/image') > -1) + printResults('Resource', [printResource(info)]) + else + printResults('Image', [printImage(info)]) break case 'snapshot': - printResults('Snapshot', [printSnapshot(info)]) + if (info.href.indexOf('um/resources/snapshot') > -1) + printResults('Resource', [printResource(info)]) + else + printResults('Snapshot', [printSnapshot(info)]) break case 'loadbalancer': printResults('Loadbalancer', [printLoadbalancer(info)]) @@ -89,7 +98,10 @@ function printInfo(error, response, body) { printResults('Nic', [printNic(info)]) break case 'ipblock': - printResults('IP Block', [printIpblock(info)]) + if (info.href.indexOf('um/resources/ipblock') > -1) + printResults('Resource', [printResource(info)]) + else + printResults('IP Block', [printIpblock(info)]) break case 'lan': printResults('LAN', [printLan(info)]) @@ -98,11 +110,23 @@ function printInfo(error, response, body) { printResults('Firewall Rule', [printFW(info)]) break case 'collection': - printCollection(info) + if (info.id == 'resources') + printResourceCollection(info) + else + printCollection(info) break case 'location': printResults('Image Alias', info.properties.imageAliases) break + case 'group': + printResults('Group', [printGroup(info)]) + break + case 'user': + printResults('User', [printUser(info)]) + break + case 'resource': + printResults('Shared resource', [printShare(info)]) + break case 'request-status': if (!isJson) { console.log("Status: " + info.metadata.targets[0].status) @@ -246,6 +270,45 @@ function printLocation(info) { } } +function printGroup(info) { + return { + Id: info.id, + Name: info.properties.name, + CreateDC: info.properties.createDataCenter, + CreateSnapshot: info.properties.createSnapshot, + ReserveIP: info.properties.reserveIp, + AccessActLog: info.properties.accessActivityLog + } +} + +function printUser(info) { + return { + Id: info.id, + FirstName: info.properties.firstname, + LastName: info.properties.lastname, + Email: info.properties.email, + Admin: info.properties.administrator + } +} + +function printShare(info) { + return { + Id: info.id, + EditPrivilege: info.properties.editPrivilege, + SharePrivilege: info.properties.sharePrivilege + } +} + +function printResource(info) { + return { + Id: info.id, + Type: info.type, + Created: info.metadata.createdDate, + By: info.metadata.createdBy, + State: info.metadata.state + } +} + function printCollection(info) { var dc = [] var type = '' @@ -296,11 +359,32 @@ function printCollection(info) { type = info.items[i].type dc.push(printFW(info.items[i])) break + case 'group': + type = info.items[i].type + dc.push(printGroup(info.items[i])) + break + case 'user': + type = info.items[i].type + dc.push(printUser(info.items[i])) + break + case 'resource': + type = 'Shared ' + info.items[i].type + dc.push(printShare(info.items[i])) + break } } printResults(type.capitalize() + 's', dc) } +function printResourceCollection(info) { + var data = [] + + for (var i = 0; i < info.items.length; i++) { + data.push(printResource(info.items[i])) + } + printResults('Resources', data) +} + function printResults(title, value) { if (isJson) console.log(JSON.stringify(value)) diff --git a/profitbricks.js b/profitbricks.js index 3010441..68ba1ae 100644 --- a/profitbricks.js +++ b/profitbricks.js @@ -27,6 +27,10 @@ var images = require('./features/image') var request = require('./features/request') var location = require('./features/location') var firewall = require('./features/firewall') +var group = require('./features/group') +var user = require('./features/user') +var share = require('./features/share') +var resource = require('./features/resource') global.force = false @@ -54,6 +58,10 @@ function initializeCli() { .option('lan, [env]', 'LAN operations') .option('request, [env]', 'Request operations') .option('location, [env]', 'Location operations') + .option('group, [env]', 'Group operations') + .option('user, [env]', 'User operations') + .option('share, [env]', 'Share operations') + .option('resource, [env]', 'Resource operations') .option('-i, --id [env]', 'Id') .option('-n, --name [env]', 'Name') .option('-l, --location [env]', 'Location') @@ -93,6 +101,7 @@ function initializeCli() { .option('--cpufamily [env]', 'Sets the CPU type. "AMD_OPTERON" or "INTEL_XEON". Defaults to "AMD_OPTERON".') .option('--lan [env]', 'The LAN ID the NIC will sit on. If the LAN ID does not exist it will be created.') .option('--public [env]', 'Boolean indicating if the LAN faces the public Internet or not.') + .option('--ipfailover [env]', 'IP failover group, e.g. "ip1,nicid1;ip2,nicid2;ip3,nicid3..."') .option('--requestid [env]', 'Request UUID') .option('--nicid [env]', 'Network Interface UUID') .option('--nat', 'NIC Network Address Translation') @@ -107,9 +116,26 @@ function initializeCli() { .option('--portRangeEnd [env]', 'Defines the end range of the allowed port (from 1 to 65534) if protocol TCP or UDP is chosen. Leave portRangeStart and portRangeEnd value null to allow all ports.') .option('--icmpType [env]', 'Defines the allowed type (from 0 to 254) if the protocol ICMP is chosen. Value null allows all types.') .option('--icmpCode [env]', 'Defines the allowed code (from 0 to 254) if protocol ICMP is chosen. Value null allows all codes.') + .option('--groupid [env]', 'Group UUID') + .option('--resourceid [env]', 'Resource UUID') + .option('--resourcetype [env]', 'Resource type. "datacenter", "snapshot", "ipblock" or "image".') + .option('--editprivilege [env]', 'The group has permission to edit privileges on the resource.') + .option('--shareprivilege [env]', 'The group has permission to share the resource.') + .option('--createdatacenter [env]', 'Group will be allowed to create virtual data centers.') + .option('--createsnapshot [env]', 'Group will be allowed to create snapshots.') + .option('--reserveip [env]', 'Group will be allowed to reserve IP addresses.') + .option('--accessactlog [env]', 'Group will be allowed to access the activity log.') + .option('--firstname [env]', 'A first name for the user.') + .option('--lastname [env]', 'A last name for the user.') + .option('--email [env]', 'An email for the user.') + .option('--password [env]', 'A password for the user.') + .option('--admin [env]', 'Indicates if the user has administrative rights.') + .option('--forcesecauth [env]', 'Indicates if secure (two-factor) authentication should be forced for the user.') .option('--json', 'Print results as JSON string') - .option('--addip [env]','Add IP') - .option('--removeip [env]','Remove IP') + .option('--addip [env]','Add IP') + .option('--removeip [env]', 'Remove IP') + .option('--adduser [env]', 'UUID of the user to add to a group') + .option('--removeuser [env]', 'UUID of the user to remove from a group') .option('-f, --force', 'Forces execution') .parse(process.argv) } @@ -188,6 +214,14 @@ function parseParameters() { firewall.process(program) else if (program.request) request.process(program) + else if (program.group) + group.process(program) + else if (program.user) + user.process(program) + else if (program.share) + share.process(program) + else if (program.resource) + resource.process(program) else if (program.location){ location.process(program) } From 51a4da48a5e190bfed4bbf12c69020fdcc2c164a Mon Sep 17 00:00:00 2001 From: Nurfet Becirevic Date: Thu, 5 Oct 2017 22:34:49 +0200 Subject: [PATCH 3/8] Enable reading json from --path for lAN update --- features/lan.js | 50 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/features/lan.js b/features/lan.js index 574f992..e1e15bd 100644 --- a/features/lan.js +++ b/features/lan.js @@ -58,31 +58,37 @@ function processLan(params) { function updateLan(params) { var data = {} - data.name = params.name - if (params.public) { - if (params.public == 'false') { - data.public = false - } else if (params.public == 'true') { - data.public = true - } - } - if (params.ipfailover) { - data.ipFailover = [] - var fg = params.ipfailover.split(";") - for (var i = 0; i < fg.length; i++) { - var pair = fg[i].split(",") - if (pair.length != 2) { - console.error('Failover group must be formated as "ip1,nicid1;ip2,nicid2;ip3,nicid3...", e.g. "208.94.36.95,2793c08f-1548-4903-87f8-fcad40b2680a;208.94.36.99,510d24b1-f363-4dbb-8e97-f3572a884719"') - process.exit(code = 5) + try { + if (params.path) { + data = JSON.parse(fs.readFileSync(params.path, 'utf8')) + } else { + data.name = params.name + if (params.public) { + if (params.public == 'false') { + data.public = false + } else if (params.public == 'true') { + data.public = true + } + } + if (params.ipfailover) { + data.ipFailover = [] + var fg = params.ipfailover.split(";") + for (var i = 0; i < fg.length; i++) { + var pair = fg[i].split(",") + if (pair.length != 2) { + console.error('Failover group must be formated as "ip1,nicid1;ip2,nicid2;ip3,nicid3...", e.g. "208.94.36.95,2793c08f-1548-4903-87f8-fcad40b2680a;208.94.36.99,510d24b1-f363-4dbb-8e97-f3572a884719"') + process.exit(code = 5) + } + var lanFailover = {} + lanFailover.ip = pair[0].trim() + lanFailover.nicUuid = pair[1].trim() + data.ipFailover.push(lanFailover) + } } - var lanFailover = {} - lanFailover.ip = pair[0].trim() - lanFailover.nicUuid = pair[1].trim() - data.ipFailover.push(lanFailover) } + } finally { + pbclient.patchLan(params.datacenterid, params.id, data, helpers.printInfo) } - - pbclient.patchLan(params.datacenterid, params.id, data, helpers.printInfo) } function createLan(params) { From 8636c33cf8ee6197e4fd0a2a64c20486a5983d86 Mon Sep 17 00:00:00 2001 From: Nurfet Becirevic Date: Thu, 5 Oct 2017 22:35:44 +0200 Subject: [PATCH 4/8] Update README with API v4 features --- README.md | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 202 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0fc0c84..6f67ef9 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,11 @@ * [NIC](#nic) * [Firewall Rules](#firewall) * [IP Block](#ip-block) - * [LAN](#lan) + * [LAN](#lan) + * [User](#user) + * [Group](#group) + * [Share](#share) + * [Resource](#resource) * [Support](#support) ## Concepts @@ -70,9 +74,9 @@ Run `profitbricks` or `profitbricks -h` or `profitbricks --help`: ``` Usage: profitbricks [Options] + Options: - -h, --help output usage information -V, --version output the version number setup Configures credentials for ProfitBricks CLI datacenter, [env] Data center operations @@ -88,6 +92,10 @@ Run `profitbricks` or `profitbricks -h` or `profitbricks --help`: lan, [env] LAN operations request, [env] Request operations location, [env] Location operations + group, [env] Group operations + user, [env] User operations + share, [env] Share operations + resource, [env] Resource operations -i, --id [env] Id -n, --name [env] Name -l, --location [env] Location @@ -106,6 +114,7 @@ Run `profitbricks` or `profitbricks -h` or `profitbricks --help`: --volumesize [env] Volume size --volumename [env] Volume name --imageid [env] Image id + --imagealias [env] Image alias -b --bus [env] Bus type (VIRTIO or IDE) -t --type [env] The disk type. --imagepassword [env] One-time password is set on the Image for the appropriate account. Password has to contain 8-50 characters. Only these characters are allowed: [abcdefghjkmnpqrstuvxABCDEFGHJKLMNPQRSTUVX23456789] @@ -126,9 +135,10 @@ Run `profitbricks` or `profitbricks -h` or `profitbricks --help`: --cpufamily [env] Sets the CPU type. "AMD_OPTERON" or "INTEL_XEON". Defaults to "AMD_OPTERON". --lan [env] The LAN ID the NIC will sit on. If the LAN ID does not exist it will be created. --public [env] Boolean indicating if the LAN faces the public Internet or not. + --ipfailover [env] IP failover group, e.g. "ip1,nicid1;ip2,nicid2;ip3,nicid3..." --requestid [env] Request UUID --nicid [env] Network Interface UUID - --nat NIC Network Address Translation. + --nat NIC Network Address Translation --protocol [env] The protocol for the rule: TCP, UDP, ICMP, ANY. --sourceMac [env] Only traffic originating from the respective MAC address is allowed. Valid format: aa:bb:cc:dd:ee:ff. Value null allows all source MAC address. --sourceIp [env] Only traffic originating from the respective IPv4 address is allowed. Value null allows all source IPs. @@ -140,10 +150,28 @@ Run `profitbricks` or `profitbricks -h` or `profitbricks --help`: --portRangeEnd [env] Defines the end range of the allowed port (from 1 to 65534) if protocol TCP or UDP is chosen. Leave portRangeStart and portRangeEnd value null to allow all ports. --icmpType [env] Defines the allowed type (from 0 to 254) if the protocol ICMP is chosen. Value null allows all types. --icmpCode [env] Defines the allowed code (from 0 to 254) if protocol ICMP is chosen. Value null allows all codes. + --groupid [env] Group UUID + --resourceid [env] Resource UUID + --resourcetype [env] Resource type. "datacenter", "snapshot", "ipblock" or "image". + --editprivilege [env] The group has permission to edit privileges on the resource. + --shareprivilege [env] The group has permission to share the resource. + --createdatacenter [env] Group will be allowed to create virtual data centers. + --createsnapshot [env] Group will be allowed to create snapshots. + --reserveip [env] Group will be allowed to reserve IP addresses. + --accessactlog [env] Group will be allowed to access the activity log. + --firstname [env] A first name for the user. + --lastname [env] A last name for the user. + --email [env] An email for the user. + --password [env] A password for the user. + --admin [env] Indicates if the user has administrative rights. + --forcesecauth [env] Indicates if secure (two-factor) authentication should be forced for the user. --json Print results as JSON string --addip [env] Add IP --removeip [env] Remove IP + --adduser [env] UUID of the user to add to a group + --removeuser [env] UUID of the user to remove from a group -f, --force Forces execution + -h, --help output usage information ``` ## Configuration @@ -251,6 +279,18 @@ Id Name Size Licence Bus State d7dc58a1-9505-48f5-9db4-22cff0659cf8 null 12 LINUX VIRTIO BUSY ``` +We can also use image aliases instead of non-constant image IDs to create new volumes. Use `image aliases` command to find out available image aliases for a particular location. + +``` +node profitbricks volume create --datacenterid 3fc832b1-558f-48a4-bca2-af5043975393 --name "Test Alias" --imagealias ubuntu:latest --size 20 --bus VIRTIO --type SSD --sshkey [ssh_key_string] + +Volume +------------------------------------------------------------------------------ +Id Name Size Licence Bus State +------------------------------------ ---------- ---- ------- ------ ----- +e7a6e51e-824f-4733-8ae2-30da817a9cbe Test Alias 20GB null VIRTIO BUSY +``` + ## Attach Volume The volume we've created is not yet connected or attached to a server. To accomplish that we'll use the `dcid` and `serverid` values returned from the previous commands: @@ -558,6 +598,12 @@ $ profitbricks image update -i [imageid] --name [name] ---description [descripti $ profitbricks image delete -i [imageid] ``` +### List Image Aliases + +``` +$ profitbricks image aliases -l [locationid] +``` + ## NIC ### List NICs @@ -682,13 +728,17 @@ profitbricks lan list --datacenterid [dcid] ### Create LAN ``` +profitbricks lan create --datacenterid [dcid] -p [path_to_json] + profitbricks lan create --datacenterid [dcid] --name [name] --public [boolean] ``` ### Update LAN ``` -profitbricks lan update --datacenterid [dcid] --name [name] --public [boolean] -i [lanid] +profitbricks lan update --datacenterid [dcid] -p [path_to_json] + +profitbricks lan update --datacenterid [dcid] --name [name] --public [boolean] -i [lanid] --ipfailover [ip1,nicid1;ip2,nicid2;...] ``` ### Get LAN @@ -697,7 +747,155 @@ profitbricks lan update --datacenterid [dcid] --name [name] --public [boolean] - profitbricks lan show --datacenterid [dcid] --id [lanid] ``` +## User + +### List Users + +``` +$ profitbricks user list +``` + +### Create User + +``` +$ profitbricks user create -p [path_to_json] + +$ profitbricks user create --firstname [firstname] --lastname [lastname] --email [email] --password [password] --admin [boolean] --forcesecauth [boolean] +``` + +### Get Specific User + +``` +$ profitbricks user get -i [userid] + +$ profitbricks user show -i [userid] +``` + +### Update User + +``` +$ profitbricks user update -i [userid] --firstname [firstname] --lastname [lastname] --email [email] --admin [boolean] --forcesecauth [boolean] +``` + +### Delete User + +``` +$ profitbricks user delete -i [userid] +``` + +## Group + +### List Groups + +``` +$ profitbricks group list +``` + +### Create Group + +``` +$ profitbricks group create -p [path_to_json] + +$ profitbricks group create --name [name] --createdatacenter [boolean] --createsnapshot [boolean] --reserveip [boolean] --accessactlog [boolean] +``` + +### Get Specific Group + +``` +$ profitbricks group get -i [groupid] + +$ profitbricks group show -i [groupid] +``` + +### Update Group + +``` +$ profitbricks group update -i [groupid] --name [name] --createdatacenter [boolean] --createsnapshot [boolean] --reserveip [boolean] --accessactlog [boolean] +``` +### Delete Group + +``` +$ profitbricks group delete -i [groupid] +``` + +### List Group Users + +``` +$ profitbricks group users -i [groupid] +``` + +### Add Group User + +``` +$ profitbricks group user --adduser [userid] -i [groupid] +``` + +### Remove Group User + +``` +profitbricks group user --removeuser [userid] -i [groupid] +``` + +## Share + +### List Shares + +``` +$ profitbricks share list --groupid [groupid] +``` + +### Add Share + +``` +$ profitbricks share add --groupid [groupid] --resourceid [resourceid] --editprivilege [boolean] --shareprivilege [boolean] + +$ profitbricks share create --groupid [groupid] --resourceid [resourceid] --editprivilege [boolean] --shareprivilege [boolean] +``` + +### Get Specific Share + +``` +$ profitbricks share get --groupid [groupid] -i [shareid] + +$ profitbricks share show --groupid [groupid] -i [shareid] +``` + +### Update Share + +``` +$ profitbricks share update --groupid [groupid] -i [shareid] --editprivilege [boolean] --shareprivilege [boolean] +``` + +### Remove Share + +``` +$ profitbricks share delete --groupid [groupid] -i [shareid] + +$ profitbricks share remove --groupid [groupid] -i [shareid] +``` + +## Resource + +### List All Resources + +``` +$ profitbricks resource list +``` + +### List Specific Type Resources + +``` +$ profitbricks resource list --resourcetype [datacenter|snapshot|image|ipblock] +``` + +### Get Specific Type Resource + +``` +$ profitbricks resource get --resourcetype [datacenter|snapshot|image|ipblock] -i [resourceid] + +$ profitbricks resource show --resourcetype [datacenter|snapshot|image|ipblock] -i [resourceid] +``` ## Support From 531a30490065b8cc9003c17c3a4c5028016433da Mon Sep 17 00:00:00 2001 From: ericknauer Date: Mon, 9 Oct 2017 11:55:07 -0700 Subject: [PATCH 5/8] Minor adjustments to the docs --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6f67ef9..35d3ae1 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,11 @@ ## Concepts -The ProfitBricks CLI wraps the [ProfitBricks REST API](https://devops.profitbricks.com/api/rest/) allowing you to interact with it from a command-line interface. +The ProfitBricks CLI wraps the [ProfitBricks Cloud API](https://devops.profitbricks.com/api/cloud/) allowing you to interact with it from a command-line interface. ## Getting Started -Before you begin you will need to have [signed-up](https://www.profitbricks.com/signup/) for a ProfitBricks account. The credentials you establish during sign-up will be used to authenticate against the [ProfitBricks API](https://devops.profitbricks.com/api/rest/). +Before you begin you will need to have [signed-up](https://www.profitbricks.com/signup/) for a ProfitBricks account. The credentials you establish during sign-up will be used to authenticate against the [ProfitBricks Cloud API](https://devops.profitbricks.com/api/cloud/). ## Installation @@ -59,7 +59,7 @@ Please utilize one of the following URL's to retrieve an install script that is [GitHub - ProfitBricks Windows Install](https://github.com/profitbricks/profitbricks-cli/tree/master/install/windows/install.bat) -If you prefer, you may install `nodejs` and `npm` manually. Then run the following to to install the ProfitBricks CLI module globally: +If you prefer, you may install `nodejs` and `npm` manually. Then run the following to install the ProfitBricks CLI module globally: ``` npm install -g profitbricks-cli @@ -176,7 +176,7 @@ Run `profitbricks` or `profitbricks -h` or `profitbricks --help`: ## Configuration -Before using the ProfitBrick's CLI to perform any operations, we'll need to set our credentials: +Before using the CLI to perform any operations, we'll need to set our credentials: ``` $ profitbricks setup @@ -198,7 +198,7 @@ These examples assume that you don't have any resources provisioned under your a ## Create Data Center -We need to supply some parameters to get our first data center created. In this case, we will set the location to 'us/las' so that this data center is created under the [DevOps Data Center](https://devops.profitbricks.com/tutorials/devops-data-center-information/). Other valid locations can be determined by reviewing the [REST API Documentation](https://devops.profitbricks.com/api/rest/#locations). That documentation is an excellent resource since that is what the ProfitBricks CLI is calling to complete these operations. +We need to supply some parameters to get our first data center created. In this case, we will set the location to 'us/las'. Other valid locations can be determined by reviewing the [Cloud API Documentation](https://devops.profitbricks.com/api/cloud/v4/#locations). That documentation is an excellent resource since that is what the ProfitBricks CLI is calling to complete these operations. ``` $ profitbricks datacenter create --name "Demo" --description "CLI Demo Data Center" --location "us/las" @@ -633,7 +633,7 @@ $ profitbricks nic update -i [nicid] --datacenterid [dcid] --serverid [serverid] $ profitbricks nic update --datacenterid [dc] --serverid [server] -i [nicid] --addip 1.1.1.1 $ profitbricks nic update --datacenterid [dc] --serverid [server] -i [nicid] --removeip 1.1.1.1 ``` - + ### Delete NIC @@ -667,7 +667,7 @@ $ profitbricks nic detach --datacenterid [dcid] --loadbalancerid [lbid] -i [nici $profitbricks firewall list --datacenterid [dcid] --serverid [serverid] --nicid [nicid] ``` -### Get Specific Firewall Rule +### Get Specific Firewall Rule ``` $profitbricks firewall get --datacenterid [dcid] --serverid [serverid] --nicid [nicid] --id [firewallid] From ccce80198c263ca78304dba0423bdb7b1eb777f6 Mon Sep 17 00:00:00 2001 From: Nurfet Becirevic Date: Mon, 9 Oct 2017 21:37:31 +0200 Subject: [PATCH 6/8] Fix missing request ID issue when using --json format. --- helpers.js | 62 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/helpers.js b/helpers.js index 889b221..382e3f9 100644 --- a/helpers.js +++ b/helpers.js @@ -65,49 +65,56 @@ function printInfo(error, response, body) { } } + // handle request ID for JSON output, if exists + var requestId = null + if (location) { + splice = location.split("/") + requestId = splice[6] + } + if (body) { switch (info.type) { case 'datacenter': if (info.href.indexOf('um/resources/datacenter') > -1) - printResults('Resource', [printResource(info)]) + printResults('Resource', [printResource(info)], requestId) else - printResults('Datacenter', [printDc(info)]) + printResults('Datacenter', [printDc(info)], requestId) break case 'server': - printResults('Server', [printServer(info)]) + printResults('Server', [printServer(info)], requestId) break case 'volume': - printResults('Volume', [printVolume(info)]) + printResults('Volume', [printVolume(info)], requestId) break case 'image': if (info.href.indexOf('um/resources/image') > -1) - printResults('Resource', [printResource(info)]) + printResults('Resource', [printResource(info)], requestId) else - printResults('Image', [printImage(info)]) + printResults('Image', [printImage(info)], requestId) break case 'snapshot': if (info.href.indexOf('um/resources/snapshot') > -1) - printResults('Resource', [printResource(info)]) + printResults('Resource', [printResource(info)], requestId) else - printResults('Snapshot', [printSnapshot(info)]) + printResults('Snapshot', [printSnapshot(info)], requestId) break case 'loadbalancer': - printResults('Loadbalancer', [printLoadbalancer(info)]) + printResults('Loadbalancer', [printLoadbalancer(info)], requestId) break case 'nic': - printResults('Nic', [printNic(info)]) + printResults('Nic', [printNic(info)], requestId) break case 'ipblock': if (info.href.indexOf('um/resources/ipblock') > -1) - printResults('Resource', [printResource(info)]) + printResults('Resource', [printResource(info)], requestId) else - printResults('IP Block', [printIpblock(info)]) + printResults('IP Block', [printIpblock(info)], requestId) break case 'lan': - printResults('LAN', [printLan(info)]) + printResults('LAN', [printLan(info)], requestId) break case 'firewall-rule': - printResults('Firewall Rule', [printFW(info)]) + printResults('Firewall Rule', [printFW(info)], requestId) break case 'collection': if (info.id == 'resources') @@ -116,16 +123,16 @@ function printInfo(error, response, body) { printCollection(info) break case 'location': - printResults('Image Alias', info.properties.imageAliases) + printResults('Image Alias', info.properties.imageAliases, requestId) break case 'group': - printResults('Group', [printGroup(info)]) + printResults('Group', [printGroup(info)], requestId) break case 'user': - printResults('User', [printUser(info)]) + printResults('User', [printUser(info)], requestId) break case 'resource': - printResults('Shared resource', [printShare(info)]) + printResults('Shared resource', [printShare(info)], requestId) break case 'request-status': if (!isJson) { @@ -138,10 +145,12 @@ function printInfo(error, response, body) { } } - if (location) { - splice = location.split("/") + if (requestId) { if (!isJson) - console.log("RequestID: " + splice[6]) + console.log("RequestID: " + requestId) + else + if (!body) + console.log('{"RequestID":"' + requestId + '"}') } } @@ -373,7 +382,7 @@ function printCollection(info) { break } } - printResults(type.capitalize() + 's', dc) + printResults(type.capitalize() + 's', dc, null) } function printResourceCollection(info) { @@ -382,12 +391,15 @@ function printResourceCollection(info) { for (var i = 0; i < info.items.length; i++) { data.push(printResource(info.items[i])) } - printResults('Resources', data) + printResults('Resources', data, null) } -function printResults(title, value) { - if (isJson) +function printResults(title, value, requestId) { + if (isJson) { + if (requestId) + value[0].RequestID = requestId console.log(JSON.stringify(value)) + } else console.table(title, value) } From 6f3440858512066e4136de38fbcb3bd29576366a Mon Sep 17 00:00:00 2001 From: Nurfet Becirevic Date: Tue, 10 Oct 2017 12:00:38 +0200 Subject: [PATCH 7/8] Support for authentication from environment variables --- README.md | 7 +++++++ helpers.js | 9 ++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 68e31e3..85f8810 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,13 @@ You will be notified with the following message if you have provided incorrect c After successful authentication you will no longer need to provide credentials unless you want to change them. They are stored as a BASE64 encoded string in a '.profitbricks-auth' file in your home directory. +You may provide your credentials in the environment variables as well. The CLI will always check for the credentials in the environment variables before attempting to read `.profitbricks-auth` file. + +``` +export PROFITBRICKS_USERNAME="YourProfitBricksUsername" +export PROFITBRICKS_PASSWORD="YourProfitBricksPassword" +``` + # How To's: These examples assume that you don't have any resources provisioned under your account. The first thing we will want to do is create a data center to hold all of our resources. diff --git a/helpers.js b/helpers.js index 701f9bf..b5a0d45 100644 --- a/helpers.js +++ b/helpers.js @@ -28,14 +28,17 @@ function writeAuthData(authData) { } function getAuthData() { + var user = process.env.PROFITBRICKS_USERNAME + var pass = process.env.PROFITBRICKS_PASSWORD + + if (user && pass) + return new Buffer(user + ':' + pass, 'ascii').toString('base64') + if (fs.existsSync(authFile)) return fs.readFileSync(authFile).toString() } function printInfo(error, response, body) { - /*console.log(body) - console.log(error)*/ - if (response.headers) { location = response.headers.location } From bdb81ced6c9315e0cb49fb9b73415ef293c8da3c Mon Sep 17 00:00:00 2001 From: Nurfet Becirevic Date: Tue, 10 Oct 2017 12:00:38 +0200 Subject: [PATCH 8/8] Update install scripts and autocomplete --- autocomplete | 2 +- install/linux/install.sh | 22 ++++++++++++++-------- install/mac/install.sh | 24 +++++++++++++++--------- install/windows/install.bat | 4 ++-- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/autocomplete b/autocomplete index 0dd6e34..f60b4c9 100644 --- a/autocomplete +++ b/autocomplete @@ -1 +1 @@ -complete -W "-h --help -V --version setup datacenter server volume snapshot loadbalancer nic ipblock drives image lan get show create delete update attach detach start stop reboot -i --id -n --name -l --location -d --description -p --path --datacenterid -r --ram -c --cores -a --availabilityzone --licencetype --bootVolume --bootCdrom --volumeid --volumesize --volumename --imageid -b --bus -s --size --cpuHotPlug --cpuHotUnplug --ramHotPlug --ramHotUnplug --nicHotPlug --nicHotUnplug --discVirtioHotPlug --discVirtioHotUnplug --discScsiHotPlug --discScsiHotUnplug --ip --dhcp --serverid --lan --public --json -f --force" profitbricks \ No newline at end of file +complete -W "-h --help -V --version setup datacenter server volume snapshot loadbalancer nic firewall ipblock drives image lan request location group user share resource -i --id -n --name -l --location -d --description -p --path --datacenterid --loadbalancerid -r --ram -c --cores -a --availabilityzone --licencetype --sshkey --bootVolume --bootCdrom --volumeid --volumesize --volumename --imageid --imagealias -b --bus -t --type --imagepassword -s --size --cpuHotPlug --cpuHotUnplug --ramHotPlug --ramHotUnplug --nicHotPlug --nicHotUnplug --discVirtioHotPlug --discVirtioHotUnplug --discScsiHotPlug --discScsiHotUnplug --ip --dhcp --serverid --cpufamily --lan --public --ipfailover --requestid --nicid --nat --protocol --sourceMac --sourceIp --sourceIp --targetIp --targetIp --portRangeStart --portRangeEnd --portRangeEnd --icmpType --icmpCode --groupid --resourceid --resourcetype --editprivilege --shareprivilege --createdatacenter --createsnapshot --reserveip --accessactlog --firstname --lastname --email --password --admin --forcesecauth --json --addip --removeip --adduser --removeuser -f --force" profitbricks \ No newline at end of file diff --git a/install/linux/install.sh b/install/linux/install.sh index bb8b3e7..a7af9a1 100755 --- a/install/linux/install.sh +++ b/install/linux/install.sh @@ -71,14 +71,20 @@ fi npm install -g -s profitbricks-cli cli_complete="complete -W '-h --help -V --version setup datacenter server \ -volume snapshot loadbalancer nic ipblock drives image lan list get show create \ -delete update attach detach start stop reboot -i --id -n --name -l --location \ --d --description -p --path --datacenterid -r --ram -c --cores -a \ ---availabilityzone --licencetype --bootVolume --bootCdrom --volumeid \ ---volumesize --volumename --imageid -b --bus -s --size --cpuHotPlug \ ---cpuHotUnplug --ramHotPlug --ramHotUnplug --nicHotPlug --nicHotUnplug \ ---discVirtioHotPlug --discVirtioHotUnplug --discScsiHotPlug \ ---discScsiHotUnplug --ip --dhcp --serverid --lan --public --json -f --force' \ +volume snapshot loadbalancer nic firewall ipblock drives image lan request \ +location group user share resource -i --id -n --name -l --location \ +-d --description -p --path --datacenterid --loadbalancerid -r --ram -c --cores \ +-a --availabilityzone --licencetype --sshkey --bootVolume --bootCdrom --volumeid \ +--volumesize --volumename --imageid --imagealias -b --bus -t --type --imagepassword \ +-s --size --cpuHotPlug --cpuHotUnplug --ramHotPlug --ramHotUnplug --nicHotPlug \ +--nicHotUnplug --discVirtioHotPlug --discVirtioHotUnplug --discScsiHotPlug \ +--discScsiHotUnplug --ip --dhcp --serverid --cpufamily --lan --public --ipfailover \ +--requestid --nicid --nat --protocol --sourceMac --sourceIp --sourceIp --targetIp \ +--targetIp --portRangeStart --portRangeEnd --portRangeEnd --icmpType --icmpCode \ +--groupid --resourceid --resourcetype --editprivilege --shareprivilege \ +--createdatacenter --createsnapshot --reserveip --accessactlog --firstname \ +--lastname --email --password --admin --forcesecauth --json --addip --removeip \ +--adduser --removeuser -f --force' \ profitbricks" # Enable profitbricks-cli auto-completion to the user environment diff --git a/install/mac/install.sh b/install/mac/install.sh index 8a35ffb..8aaa437 100755 --- a/install/mac/install.sh +++ b/install/mac/install.sh @@ -5,7 +5,7 @@ if [ "$(id -u)" != "0" ]; then exec sudo "$0" "$@" fi -NODEJS_VERSION="0.12.2" +NODEJS_VERSION="8.6.0" # If the node command does not exist, download and install Node.js command -v node > /dev/null 2>&1 @@ -28,14 +28,20 @@ fi npm install -g -s profitbricks-cli cli_complete="complete -W '-h --help -V --version setup datacenter server \ -volume snapshot loadbalancer nic ipblock drives image lan list get show create \ -delete update attach detach start stop reboot -i --id -n --name -l --location \ --d --description -p --path --datacenterid -r --ram -c --cores -a \ ---availabilityzone --licencetype --bootVolume --bootCdrom --volumeid \ ---volumesize --volumename --imageid -b --bus -s --size --cpuHotPlug \ ---cpuHotUnplug --ramHotPlug --ramHotUnplug --nicHotPlug --nicHotUnplug \ ---discVirtioHotPlug --discVirtioHotUnplug --discScsiHotPlug \ ---discScsiHotUnplug --ip --dhcp --serverid --lan --public --json -f --force' \ +volume snapshot loadbalancer nic firewall ipblock drives image lan request \ +location group user share resource -i --id -n --name -l --location \ +-d --description -p --path --datacenterid --loadbalancerid -r --ram -c --cores \ +-a --availabilityzone --licencetype --sshkey --bootVolume --bootCdrom --volumeid \ +--volumesize --volumename --imageid --imagealias -b --bus -t --type --imagepassword \ +-s --size --cpuHotPlug --cpuHotUnplug --ramHotPlug --ramHotUnplug --nicHotPlug \ +--nicHotUnplug --discVirtioHotPlug --discVirtioHotUnplug --discScsiHotPlug \ +--discScsiHotUnplug --ip --dhcp --serverid --cpufamily --lan --public --ipfailover \ +--requestid --nicid --nat --protocol --sourceMac --sourceIp --sourceIp --targetIp \ +--targetIp --portRangeStart --portRangeEnd --portRangeEnd --icmpType --icmpCode \ +--groupid --resourceid --resourcetype --editprivilege --shareprivilege \ +--createdatacenter --createsnapshot --reserveip --accessactlog --firstname \ +--lastname --email --password --admin --forcesecauth --json --addip --removeip \ +--adduser --removeuser -f --force' \ profitbricks" # Enable profitbricks-cli auto-completion to the user environment diff --git a/install/windows/install.bat b/install/windows/install.bat index 1ec7fc1..6df48df 100644 --- a/install/windows/install.bat +++ b/install/windows/install.bat @@ -5,11 +5,11 @@ if errorlevel 0 GOTO :finish :download if "%PROCESSOR_ARCHITECTURE%"=="AMD64" goto 64BIT -bitsadmin.exe /transfer "Downloading nodejs" http://nodejs.org/dist/v0.12.2/node-v0.12.2-x86.msi "%cd%\nodejs.msi" +bitsadmin.exe /transfer "Downloading nodejs" http://nodejs.org/dist/v8.6.0/node-v8.6.0-x86.msi "%cd%\nodejs.msi" GOTO :install :64BIT -bitsadmin.exe /transfer "Downloading nodejs" http://nodejs.org/dist/v0.12.2/x64/node-v0.12.2-x64.msi "%cd%\nodejs.msi" +bitsadmin.exe /transfer "Downloading nodejs" http://nodejs.org/dist/v8.6.0/node-v8.6.0-x64.msi "%cd%\nodejs.msi" GOTO :install :install