From 358826ce4886a3cfd0e79aa584107a093e674d60 Mon Sep 17 00:00:00 2001 From: taoqf Date: Wed, 24 Apr 2019 18:11:53 +0800 Subject: [PATCH 1/3] rewrite with typescript --- .gitignore | 1 + .npmignore | 3 + index.js | 172 ++- lib/glance.js | 341 ----- lib/heat.js | 243 ---- lib/keystone.js | 637 ---------- lib/mangler.js | 11 - lib/neutron.js | 1638 ------------------------ lib/nova.js | 1254 ------------------- lib/octavia.js | 1122 ----------------- lib/os-request.js | 366 ------ lib/os-utils.js | 43 - package.json | 19 +- src/glance.ts | 212 ++++ src/heat.ts | 173 +++ src/index.ts | 74 ++ src/keystone.ts | 503 ++++++++ src/neutron.ts | 859 +++++++++++++ src/nova.ts | 601 +++++++++ src/octavia.ts | 494 ++++++++ src/os-request.ts | 415 ++++++ src/utils.ts | 16 + test/glance-test.js | 377 +++--- test/heat-test.js | 340 +++-- test/keystone-test.js | 1042 ++++++++------- test/neutron-test.js | 2781 ++++++++++++++++++++--------------------- test/nova-test.js | 2106 +++++++++++++++---------------- test/octavia-test.js | 545 ++++---- test/os-utils-test.js | 55 +- tsconfig.json | 57 + tslint.json | 72 ++ 31 files changed, 7050 insertions(+), 9522 deletions(-) create mode 100644 .npmignore delete mode 100644 lib/glance.js delete mode 100644 lib/heat.js delete mode 100644 lib/keystone.js delete mode 100644 lib/mangler.js delete mode 100644 lib/neutron.js delete mode 100644 lib/nova.js delete mode 100644 lib/octavia.js delete mode 100644 lib/os-request.js delete mode 100644 lib/os-utils.js create mode 100644 src/glance.ts create mode 100644 src/heat.ts create mode 100644 src/index.ts create mode 100644 src/keystone.ts create mode 100644 src/neutron.ts create mode 100644 src/nova.ts create mode 100644 src/octavia.ts create mode 100644 src/os-request.ts create mode 100644 src/utils.ts create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.gitignore b/.gitignore index 299aea9..67efb94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ npm-debug.log node_modules .DS_Store +dist/ diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..19ae04a --- /dev/null +++ b/.npmignore @@ -0,0 +1,3 @@ +/node_modules +/src +/test diff --git a/index.js b/index.js index 877dc92..6238843 100644 --- a/index.js +++ b/index.js @@ -1,109 +1,97 @@ -var Keystone = require('./lib/keystone'); -var Glance = require('./lib/glance'); -var Neutron = require('./lib/neutron'); -var Octavia = require('./lib/octavia'); -var Nova = require('./lib/nova'); -var Heat = require('./lib/heat'); +var Keystone = require('./dist/keystone'); +var Glance = require('./dist/glance'); +var Neutron = require('./dist/neutron'); +var Octavia = require('./dist/octavia'); +var Nova = require('./dist/nova'); +var Heat = require('./dist/heat'); //A convenience method for quick/dirty work for those that already have a project_id //calls back with (error, project) where project already has all the individual objects setup //ie: project.nova, project.glance, etc.. -function getSimpleProject(username, password, project_id, keystone_url, cb) -{ - var keystone = new Keystone(keystone_url); - var return_object = {}; - var glance_url = ''; - var neutron_url = ''; - var nova_url = ''; - var octavia_url = ''; - var heat_url = ''; - var catalog_array = []; - var n = 0; - var j = 0; - var endpoint_type = ''; +function getSimpleProject(username, password, project_id, keystone_url, cb) { + var keystone = new Keystone(keystone_url); + var return_object = {}; + var glance_url = ''; + var neutron_url = ''; + var nova_url = ''; + var octavia_url = ''; + var heat_url = ''; + var catalog_array = []; + var n = 0; + var j = 0; + var endpoint_type = ''; - keystone.getToken(username, password, function(error, token){ - if(error) - { - cb(error); - return; - } + keystone.getToken(username, password, function (error, token) { + if (error) { + cb(error); + return; + } - //else - keystone.getProjectToken(token.token, project_id, function(error, project_token){ - if(error) - { - cb(error); - return; - } + //else + keystone.getProjectToken(token.token, project_id, function (error, project_token) { + if (error) { + cb(error); + return; + } - //else - catalog_array = project_token.catalog; - for(n = 0; n < catalog_array.length; n++) - { - //ELS Puppet sometimes screws up Keystone and puts in duplicate service entries - //that have no endpoints.. ignore these. - if(!catalog_array[n].endpoints || !catalog_array[n].endpoints.length) - { - continue; - } + //else + catalog_array = project_token.catalog; + for (n = 0; n < catalog_array.length; n++) { + //ELS Puppet sometimes screws up Keystone and puts in duplicate service entries + //that have no endpoints.. ignore these. + if (!catalog_array[n].endpoints || !catalog_array[n].endpoints.length) { + continue; + } - endpoints_array = catalog_array[n].endpoints; - endpoint_type = catalog_array[n].type; + endpoints_array = catalog_array[n].endpoints; + endpoint_type = catalog_array[n].type; - for(j = 0; j < endpoints_array.length; j++) - { - if(endpoints_array[j].interface == 'public') - { - endpoints_array[j].url = endpoints_array[j].url.replace(/\/$/, "");//yank any trailing /'s, + for (j = 0; j < endpoints_array.length; j++) { + if (endpoints_array[j].interface == 'public') { + endpoints_array[j].url = endpoints_array[j].url.replace(/\/$/, "");//yank any trailing /'s, - if(endpoint_type == 'image') - { - //we have to add the v2 to the end to get the most current functionality - glance_url = endpoints_array[j].url + '/v2.0'; - } - else if(endpoint_type == 'network') - { - //we have to add the v2 to the end to get the most current functionality - neutron_url = endpoints_array[j].url + '/v2.0'; - } - else if(endpoint_type == 'compute') - { - nova_url = endpoints_array[j].url; - } - else if (endpoint_type == 'load-balancer') - { - octavia_url = endpoints_array[j].url; - } - else if (endpoint_type == 'orchestration') - { - heat_url = endpoints_array[j].url; - } - break; - } - } - } + if (endpoint_type == 'image') { + //we have to add the v2 to the end to get the most current functionality + glance_url = endpoints_array[j].url + '/v2.0'; + } + else if (endpoint_type == 'network') { + //we have to add the v2 to the end to get the most current functionality + neutron_url = endpoints_array[j].url + '/v2.0'; + } + else if (endpoint_type == 'compute') { + nova_url = endpoints_array[j].url; + } + else if (endpoint_type == 'load-balancer') { + octavia_url = endpoints_array[j].url; + } + else if (endpoint_type == 'orchestration') { + heat_url = endpoints_array[j].url; + } + break; + } + } + } - return_object.general_token = token; - return_object.project_token = project_token; - return_object.glance = new Glance(glance_url, project_token.token); - return_object.neutron = new Neutron(neutron_url, project_token.token); - return_object.nova = new Nova(nova_url, project_token.token); - return_object.octavia = new Octavia(octavia_url, project_token.token); - return_object.heat = new Heat(heat_url, project_token.token); - cb(null, return_object); - }); - }); + return_object.general_token = token; + return_object.project_token = project_token; + return_object.glance = new Glance(glance_url, project_token.token); + return_object.neutron = new Neutron(neutron_url, project_token.token); + return_object.nova = new Nova(nova_url, project_token.token); + return_object.octavia = new Octavia(octavia_url, project_token.token); + return_object.heat = new Heat(heat_url, project_token.token); + cb(null, return_object); + }); + }); } module.exports = { - Glance: Glance, - Keystone: Keystone, - Neutron: Neutron, - Octavia: Octavia, - Nova: Nova, - Heat: Heat, - getSimpleProject: getSimpleProject + Glance: Glance, + Keystone: Keystone, + Neutron: Neutron, + Octavia: Octavia, + Nova: Nova, + Heat: Heat, + getSimpleProject: getSimpleProject } diff --git a/lib/glance.js b/lib/glance.js deleted file mode 100644 index 8ad091a..0000000 --- a/lib/glance.js +++ /dev/null @@ -1,341 +0,0 @@ -var Request = require('./os-request'); - - -//constructor - should be the only export -function Glance(endpoint_url, auth_token) -{ - //set this way purely to facilitate unit test dependency injetion - this.request = Request; - - //this is an optional lib that we override to normalfy the openstack responses - leave as is for no munging - this.mangler = require('./mangler'); - this.mangleObject = this.mangler.mangleObject; - - //endpoint_url should come from the keystone projectInfo call - also yank all the trailing slashes in case folks get clever - this.url = endpoint_url.replace(/\/$/, ""); - - //auth_token should be the scoped token from the projectInfo call - this.token = auth_token; - - //default the timeout to false - this forces the static value to be used - this.timeout = 9000; - - //default request id to blank - should represent the incomming request id - this.request_id = ''; - - //default to a blank user_name - this.user_name = ''; - - //logger should default to null - might consider checking for a logMetric function in that obj too? - this.logger = null; -} - - -//setters for individual obj/call usage -//just set these prior to doing things and your good to go until you want to change it -Glance.prototype.setTimeout = function(new_timeout) -{ - this.timeout = new_timeout; -}; - -Glance.prototype.setRequestID = function(request_id) -{ - this.request_id = request_id; -}; - -Glance.prototype.setUserName = function(user_name) -{ - this.user_name = user_name; -}; - -Glance.prototype.setLogger = function(logger) -{ - this.logger = logger; -}; - -//this should only be used for dependency injection -Glance.prototype.setRequest = function(request_lib) -{ - this.request = request_lib; -} - -//lets us mangle/sanitize/make sane the various responses from openstack -//any replacement must simply support a static mangleObject that supports the following types [ie mangleObject(type, object)] -//Image -Glance.prototype.setMangler = function(mangle_lib) -{ - this.mangler = mangle_lib; - this.mangleObject = this.mangler.mangleObject; -} - - - -//returns an formatted options object - just makes the code below a little less repetitious -//path should begin with a "/" -//json_value should be almost certainly be true if you don't have an actual object you want to send over -Glance.prototype.getRequestOptions = function(path, json_value, extra_headers) -{ - var return_object = { - uri: this.url + path, - headers:{'X-Auth-Token': this.token}, - json: json_value, - timeout: this.timeout, - metricRequestID: this.request_id, - metricUserName: this.user_name, - metricLogger: this.logger - }; - - //add the extra header info if it exists - if(typeof extra_headers != 'undefined') - { - for(var key in extra_headers) - { - if(extra_headers.hasOwnProperty(key)) - { - return_object.headers[key] = extra_headers[key]; - } - } - } - - return return_object; -}; - - - -//makes a callback cb(error, images_array) with a list of all of the available images for a given project/user -//NOTE: harding pagination for now - change at will (just be aware it will break backwards compat so update version accordingly) -Glance.prototype.listImages = function(cb) -{ - var self = this; - var request_options = this.getRequestOptions('/images?member_status=all&limit=200', true); - request_options.metricPath = 'remote-calls.glance.images.list'; //if you override the request obj you can use this for logging purposes - request_options.validateStatus = true; - request_options.requireBodyObject = 'images'; - - this.request.get(request_options, function(error, response, body){ - var images_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - for (n = 0; n < body.images.length; n++) - { - images_array[n] = self.mangleObject('Image', body.images[n]); - } - - cb(null, images_array); - }); -} - - - -//gets info on a specific image given the id -//takes an image id ex: '8ab808ed-d2aa-471c-9af0-0d3287061670' -//and callback with 2 params (error, image_info_object) -Glance.prototype.getImage = function(id, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/images/' + escape(id), true); - request_options.metricPath = 'remote-calls.glance.images.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'id'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Image', body)); - }); -} - - - -//This might create a temporary id/placeholder for us to upload new images into -//...or it may bring the end of times through dark titual.... probably 50/50 -//callback takes 2 params (error, data) where data seems to include the id of the result of queuing...er posting... er whatever -Glance.prototype.queueImage = function(data, cb) -{ - var self = this; - var post_data = {}; - var request_options = {}; - - //first pull the valid options out of data - I think this is done for security purposes...as opposed to just tossing in 'data'? - if(data.name) - { - post_data.name = data.name; - } - if(data.visibility) - { - post_data.visibility = data.visibility; - } - if(data.tags) - { - post_data.tags = data.tags; - } - if(data.disk_format) - { - post_data.disk_format = data.disk_format; - } - if(data.container_format) - { - post_data.container_format = data.container_format; - } - - request_options = this.getRequestOptions('/images', post_data); - request_options.metricPath = 'remote-calls.glance.images.queue'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'id'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Image', body)); - }); -} - - - -//uploads a new image to openstack -//takes the new image id(from the queue call above?) -//a stream object... don't really get that one (download result?) -//and a callback w/2 params (error, response) I think response here is the result of the upload call -Glance.prototype.uploadImage = function(id, stream, cb) -{ - var http; - var upload; - var url = this.url + '/images/' + escape(id) + '/file'; - var opt = urllib.parse(url); //sadly I didn't get this working with the request object.... yet! - opt.method = 'PUT'; - opt.headers = { - 'X-Auth-Token': this.token, - 'Content-Type': 'application/octet-stream', - 'Connection' : 'close' - }; - - if(opt.protocol == 'https:') - { - http = require('https'); - } - else - { - http = require('http'); - } - - upload = http.request(opt, function(res){ - var response = ''; - - res.on('data', function(chunk){ - response += chunk; - }); - - res.on('end', function(){ - cb(null, response); - }); - }); - - upload.on('error', function(e) { - cb(e); - }); - - stream.pipe(upload); -} - - - -//calls back with (error, image) after updating the data on an image -//data should be an object with only the deltas to be tweaked - the following are supposed -/* - data.name - data.visibility - data.protected - data.tags -*/ -Glance.prototype.updateImage = function(id, data, cb) -{ - var self = this; - var request_options = {}; - var patch_data = []; - - if(data.name) - { - patch_data.push({'op': 'replace', 'path': '/name', 'value': data.name}); - } - if(data.visibility) - { - patch_data.push({'op': 'replace', 'path': '/visibility', 'value': data.visibility}); - } - //data.protected is a boolean so the normal if(thing) mechanism won't work - hence typeof - if(typeof data.protected != 'undefined') - { - patch_data.push({'op': 'replace', 'path': '/protected', 'value': !!data.protected}); - } - if(data.tags) - { - patch_data.push({'op': 'replace', 'path': '/tags', 'value': data.tags}); - } - - //we have an additional header here due to the patch command - request_options = this.getRequestOptions('/images/' + escape(id), patch_data, {'Content-Type': 'application/openstack-images-v2.1-json-patch'}); - request_options.metricPath = 'remote-calls.glance.images.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'id'; - - this.request.patch(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Image', body)); - }); -} - - - -//calls back with (error) after attempting to remove an openstack image -Glance.prototype.removeImage = function(id, cb) -{ - var request_options = this.getRequestOptions('/images/' + escape(id), true); - request_options.metricPath = 'remote-calls.glance.images.remove'; - request_options.validateStatus = true; - - //are we not giving this a cb for some reason sometimes??? - function noop() - { - //this does absolutely nothing - and thats just the way we like it! - } - if(!cb) - { - cb = noop; - } - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -} - - -module.exports = Glance; diff --git a/lib/heat.js b/lib/heat.js deleted file mode 100644 index b674f40..0000000 --- a/lib/heat.js +++ /dev/null @@ -1,243 +0,0 @@ -//Class to handle all Heat methdology -//NOTE: This class was created after v2.1.10 -//and so mangling is no longer supported or required to be programmed in below - -var OSUtils = require('./os-utils'); -var Request = require('./os-request'); - - - -//constructor - should be the only export -function Heat(endpoint_url, auth_token) -{ - //set this way purely to facilitate unit test dependency injetion - this.request = Request; - - //endpoint_url should come from the keystone projectInfo call - also yank all the trailing slashes in case folks get clever - this.url = endpoint_url.replace(/\/$/, ""); - - //auth_token should be the scoped token from the projectInfo call - this.token = auth_token; - - //default the timeout to false - this forces the static value to be used - this.timeout = 9000; - - //default request id to blank - should represent the incomming request id - this.request_id = ''; - - //default to a blank user_name - this.user_name = ''; - - //logger should default to null - might consider checking for a logMetric function in that obj too? - this.logger = null; -} - - - -//setters for individual obj/call usage -//just set these prior to doing things and your good to go until you want to change it -Heat.prototype.setTimeout = function(new_timeout) -{ - this.timeout = new_timeout; -}; - -Heat.prototype.setRequestID = function(request_id) -{ - this.request_id = request_id; -}; - -Heat.prototype.setUserName = function(user_name) -{ - this.user_name = user_name; -}; - -Heat.prototype.setLogger = function(logger) -{ - this.logger = logger; -}; - -//this should only be used for dependency injection -Heat.prototype.setRequest = function(request_lib) -{ - this.request = request_lib; -} - - - -//returns an formatted options object - just makes the code below a little less repetitious -//path should begin with a "/" -//json_value should be almost certainly be true if you don't have an actual object you want to send over -Heat.prototype.getRequestOptions = function(path, json_value, extra_headers) -{ - var return_object = { - uri: this.url + path, - headers:{'X-Auth-Token': this.token}, - json: json_value, - timeout: this.timeout, - metricRequestID: this.request_id, - metricUserName: this.user_name, - metricLogger: this.logger - }; - //add the extra header info if it exists - if(typeof extra_headers != 'undefined') - { - for(var key in extra_headers) - { - if(extra_headers.hasOwnProperty(key)) - { - return_object.headers[key] = extra_headers[key]; - } - } - } - return return_object; -}; - - - -//gets a list of all stacks for the given project/tenant -//calls back with cb(error, stack_array) -//the options object can be a blank obj {} or used to specify filters using key/values, e.g.: -//{ -// id: string, -// status: string, -// name: string, -// action: string, -// tenant: string, -// username: string, -// owner_id: string -//} -Heat.prototype.listStacks = function(options, cb) -{ - var request_options = this.getRequestOptions('/stacks', true); - request_options.qs = options; - request_options.metricPath = 'remote-calls.heat.stacks.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'stacks'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else just send back the result (no mangling going forward) - - cb(null, body.stacks); - }); -} - - - -//show output of a stack for the given key name -//calls back with cb(error, output_object) -Heat.prototype.showStackOutput = function(name, id, outputKey, cb) -{ - var request_options = this.getRequestOptions('/stacks/' + escape(name) + '/' + escape(id) + '/outputs/' + escape(outputKey), true); - request_options.metricPath = 'remote-calls.heat.stack.showStackOutput'; - request_options.validateStatus = true; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else just send back the result (no mangling going forward) - - cb(null, body.output); - }); -} - - -//creates a stack with the given name -//calls back with cb(error, stack_object) -// options: -// { -// disable_rollback: boolean, -// environment: object, -// files: object, -// parameters: object, -// tags: string, -// template: object, -// template_url: string, -// timeout_mins: number -//} -//note: either template or template_url must be defined -Heat.prototype.createStack = function(name, options, cb) -{ - var request_options = this.getRequestOptions('/stacks', options); - request_options.metricPath = 'remote-calls.heat.stacks.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'stack'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else just send back the result (no mangling going forward) - - cb(null, body.stack); - }); -} - - -//updates the stack with the given name and id, using HTTP PATCH -//calls back with cb(error, stack_object) -// options: -// { -// clear_parameters: array, -// disable_rollback: boolean, -// environment: object, -// environment_files: object, -// files: object, -// parameters: object, -// tags: string, -// template: object, -// template_url: string, -// timeout_mins: number, -// converge: boolean -//} -//note: either template or template_url must be defined -Heat.prototype.updateStack = function(name, id, options, cb) -{ - var request_options = this.getRequestOptions('/stacks/' + escape(name) + '/' + escape(id), options); - request_options.metricPath = 'remote-calls.heat.stacks.update'; - request_options.validateStatus = true; - - this.request.patch(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else just call back w/no error as the result is just a message telling us it worked (when it worked) - - cb(); - }); -} - - - -//deletes the stack with the given name and id -Heat.prototype.deleteStack = function(name, id, cb) -{ - var request_options = this.getRequestOptions('/stacks/' + escape(name) + '/' + escape(id), true); - request_options.metricPath = 'remote-calls.heat.stack.delete'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else just call back w/no error - - cb(); - }); -} - - -module.exports = Heat; \ No newline at end of file diff --git a/lib/keystone.js b/lib/keystone.js deleted file mode 100644 index d7a23de..0000000 --- a/lib/keystone.js +++ /dev/null @@ -1,637 +0,0 @@ -var Request = require('./os-request'); - - -//constructor - should be the only export -function Keystone(endpoint_url) -{ - //set this way purely to facilitate unit test dependency injetion - this.request = Request; - - //this is an optional lib that we override to normalfy the openstack responses - leave as is for no munging - this.mangler = require('./mangler'); - this.mangleObject = this.mangler.mangleObject; - - //Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes - this.url = endpoint_url.replace(/\/$/, ""); - - //default the timeout to false - this forces the static value to be used - this.timeout = 9000; - - //default request id to blank - should represent the incomming request id - this.request_id = ''; - - //default to a blank user_name - this.user_name = ''; - - //logger should default to null - might consider checking for a logMetric function in that obj too? - this.logger = null; -} - - -//setters for individual obj/call usage -//just set these prior to doing things and your good to go until you want to change it -Keystone.prototype.setTimeout = function(new_timeout) -{ - this.timeout = new_timeout; -}; - -Keystone.prototype.setRequestID = function(request_id) -{ - this.request_id = request_id; -}; - -Keystone.prototype.setUserName = function(user_name) -{ - this.user_name = user_name; -}; - -Keystone.prototype.setLogger = function(logger) -{ - this.logger = logger; -}; - -//this should only be used for dependency injection -Keystone.prototype.setRequest = function(request_lib) -{ - this.request = request_lib; -} - -//lets us mangle/sanitize/make sane the various responses from openstack -//any replacement must simply support a static mangleObject that supports the following types [ie mangleObject(type, object)] -//Project, Role, Assignment -Keystone.prototype.setMangler = function(mangle_lib) -{ - this.mangler = mangle_lib; - this.mangleObject = this.mangler.mangleObject; -} - - - -//returns an formatted options object - just makes the code below a little less repetitious -//auth_token can be either a generic or project scoped token depending what your doing -//json_value should be almost certainly be true if you don't have an actual object you want to send over -//NOTE: because keystone is non-project specific this function is different than all the other classes with it -Keystone.prototype.getRequestOptions = function(auth_token, path, json_value) -{ - //start w/the instance timeout - var request_timeout = this.timeout; - if(!request_timeout) - { - //override with the static value if no instance value was given - request_timeout = Keystone.timeout; - } - var return_object = { - uri: this.url + path, - headers:{'X-Auth-Token': auth_token}, - json: json_value, - timeout: this.timeout, - metricRequestID: this.request_id, - metricUserName: this.user_name, - metricLogger: this.logger - }; - - return return_object; -}; - - - -//authorizes the users against the specified keystone -//can be called with 3 or 4 params (domain is optional, cb is not) -//calls back with (error, token) where token is an object containing all the token info -//NOTE: the actual token value normally comes back in the header - i'm modifying this to token.token for easier consumption -Keystone.prototype.getToken = function(username, password, domain, cb) -{ - //handle domain not being passed in for backwards compat - if(arguments.length === 3) - { - cb = domain; - domain = 'Default' - } - - var self = this; - var auth_data = { - auth:{ - identity:{ - methods: ['password'], - 'password': {user: {domain: {name: domain}, name: username, 'password': password}} - } - } - } - var request_options = this.getRequestOptions('bogus', '/auth/tokens', auth_data); - request_options.headers = {}; //we don't want the normal auth header due to bogus token - request_options.metricPath = 'remote-calls.keystone.tokens.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'token'; - - //auth-token will come back in the header for some reason as x-subject-token (used to come back in the body all nice like) - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error) - return; - } - //else - - //tiny hack here to put the actual token string back into the object - body.token.token = response.headers['x-subject-token']; - - //now we good - cb(null, self.mangleObject('Token', body.token)); - }); -}; - - - -//make a callback(error, project_authorization) with all of the data on a project and an access token for further calls on it -//NOTE: this is not the admin function that gets project details - you have to do this so I'm not bothering with that -Keystone.prototype.getProjectTokenForReal = function(auth_data, cb) -{ - var self = this; - - //use the normal getRequestOptions but send in a bogus token and nullfiy the header - //the token will get passed in the data in this call - var request_options = this.getRequestOptions('bogus', '/auth/tokens', auth_data); - request_options.headers = {}; - request_options.metricPath = 'remote-calls.keystone.tokens.get-project'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'token'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - //hack to put the actual token value back into the body - body.token.token = response.headers['x-subject-token']; - - cb(null, self.mangleObject('ProjectToken', body.token)); - }); -}; - - - -//make a callback(error, project_authorization) with all of the data on a project and an access token for further calls on it -//NOTE: this is not the admin function that gets project details - you have to do this so I'm not bothering with that -Keystone.prototype.getProjectToken = function(access_token, project_id, cb) -{ - var auth_data = { - auth:{ - identity:{ - methods: ['token'], - token: {id: access_token} - }, - scope: { - project: {id: project_id} - } - } - }; - - this.getProjectTokenForReal(auth_data, cb); -}; - - - -//passthru function for future stuff -Keystone.prototype.getProjectTokenById = Keystone.prototype.getProjectToken; - - - -//make a callback(error, project_authorization) with all of the data on a project and an access token for further calls on it -//NOTE: this is not the admin function that gets project details - you have to do this so I'm not bothering with that -Keystone.prototype.getProjectTokenByName = function(access_token, domain_id, project_name, cb) -{ - var auth_data = { - auth:{ - identity:{ - methods: ['token'], - token: {id: access_token} - }, - scope: { - project: { - domain: {id: domain_id}, - name: project_name - } - } - } - }; - - this.getProjectTokenForReal(auth_data, cb); -}; - - - -//gets a list of all projects in the system -//calls back with cb(error, project_array) -//***NOTE: admin_access_token is a scoped token from a project you have admin rights on - yes this is weird -Keystone.prototype.listProjects = function(admin_access_token, cb) -{ - var self = this; - var request_options = this.getRequestOptions(admin_access_token, '/projects', true); - request_options.metricPath = 'remote-calls.keystone.projects.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'projects'; - - this.request.get(request_options, function(error, response, body){ - var projects_array =[]; - if(error) - { - cb(error); - return; - } - - for(var n = 0; n < body.projects.length; n++) - { - projects_array[n] = self.mangleObject('Project', body.projects[n]); - } - - //tack these on for easy consupmtion and in case we ever need pagination - projects_array.self = body.links.self; - projects_array.previous = body.links.previous; - projects_array.next = body.links.next; - - cb(null, projects_array); - }); -}; - - - - -//gets a list of projects the given token is authorized to have some access to -//calls back with (error, projects_array) and self, previous, and null are tacked on as properties of the array -Keystone.prototype.listUserProjects = function(username, access_token, cb) -{ - var self = this; - var request_options = this.getRequestOptions(access_token, '/users/' + username + '/projects', true); - request_options.metricPath = 'remote-calls.keystone.projects.list-user'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'projects'; - - this.request.get(request_options, function(error, response, body){ - var projects_array =[]; - if(error) - { - cb(error); - return; - } - //else - - for(var n = 0; n < body.projects.length; n++) - { - projects_array[n] = self.mangleObject('Project', body.projects[n]); - } - - //tack these on for easy consupmtion and in case we ever need pagination - projects_array.self = body.links.self; - projects_array.previous = body.links.previous; - projects_array.next = body.links.next; - - cb(null, projects_array); - }); -}; - - - -//gets the details of a specific project by name -//calls back with cb(error, project_array) -//***NOTE: admin_access_token is a scoped token from a project you have admin rights on - yes this is weird -//***NOTE: this will return an error if 2 projects are named the same - not usable unless distinct projects are configured/required. -Keystone.prototype.getProjectByName = function(admin_access_token, project_name, cb) -{ - var self = this; - var request_options = this.getRequestOptions(admin_access_token, '/projects?name=' + project_name, true); - request_options.metricPath = 'remote-calls.keystone.projects.get-by-name'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'projects'; - - this.request.get(request_options, function(error, response, body){ - var project_object = {}; - if(error) - { - cb(error); - return; - } - //else - - if(body.projects.length > 1) - { - //kind of an error... in theory - cb(new Error('Found multiple projects with same name')); - return; - } - //else - - if(body.projects.length == 0) - { - //not an error but no data either - cb(null, project_object); - return; - } - //else - - //we are good - project_object = self.mangleObject('Project', body.projects[0]); - cb(null, project_object); - }); -}; - - - -//gets a list of roles for the given project (specified by token ...kinda weird) -//calls back with (error, roles_array) and self, previous, and null are tacked on as properties of the array -//NOTE: this needs a project token scoped in our system - this may vary depending on how the security is setup -Keystone.prototype.listRoles = function(project_token, cb) -{ - var self = this; - var request_options = this.getRequestOptions(project_token, '/roles', true); - request_options.metricPath = 'remote-calls.keystone.roles.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'roles'; - - this.request.get(request_options, function(error, response, body){ - //console.log('roles', body); - var n = 0; - var roles_array = []; - - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.roles.length; n++) - { - roles_array[n] = self.mangleObject('Role', body.roles[n]); - } - - //tack these on for easy consupmtion and in case we ever need pagination - roles_array.self = body.links.self; - roles_array.previous = body.links.previous; - roles_array.next = body.links.next; - - cb(null, roles_array); - }); -}; - - - -//make a callback(error, assignments_array) with all of the role assignments for a project -//NOTE: this is only works if the user is authed as an admin or projectAdmin -Keystone.prototype.listRoleAssignments = function(project_token, project_id, cb) -{ - var self = this; - var request_options = this.getRequestOptions(project_token, '/role_assignments?scope.project.id=' + project_id, true); - request_options.metricPath = 'remote-calls.keystone.role-assigments.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'role_assignments'; - - this.request.get(request_options, function(error, response, body){ - var cb_error = null; - var assignments_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.role_assignments.length; n++) - { - assignments_array[n] = self.mangleObject('RoleAssignment', body.role_assignments[n]); - } - - //tack these on for easy consupmtion and in case we ever need pagination - assignments_array.self = body.links.self; - assignments_array.previous = body.links.previous; - assignments_array.next = body.links.next; - - cb(cb_error, assignments_array); - }); -}; - - - -//make a callback(error) after adding a specific role assignment to a project (either a user or a group) -//NOTE: this is only works if the user is authed as an admin or projectAdmin -Keystone.prototype.addRoleAssignment = function(project_token, project_id, entry_id, entry_type, role_id, cb) -{ - var request_options = {}; - var entry_type_path = 'users'; - - if(entry_type == 'group') - { - entry_type_path = 'groups'; - } - request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/' + entry_type_path + '/' + entry_id + '/roles/' + role_id, true); - request_options.metricPath = 'remote-calls.keystone.role-assignments.add'; - request_options.validateStatus = true; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else the body comes back as undefined instead of containing the new role assingment - lame - //so just call back with no error and we should be good - - cb(); - }); -}; - - - -//make a callback(error) after removing a specific role assignments on a project(either a user or a group) -//NOTE: this is only works if the user is authed as an admin or projectAdmin -Keystone.prototype.removeRoleAssignment = function(project_token, project_id, entry_id, entry_type, role_id, cb) -{ - var request_options = {}; - var entry_type_path = 'users'; - - if(entry_type == 'group') - { - entry_type_path = 'groups'; - } - - request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/' + entry_type_path + '/' + entry_id + '/roles/' + role_id, true); - request_options.metricPath = 'remote-calls.keystone.role-assignments.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -//gets a list of all regions in the system -//calls back with cb(error, region_array) -Keystone.prototype.listRegions = function(access_token, cb) -{ - var self = this; - var regions_array =[]; - var request_options = this.getRequestOptions(access_token, '/regions', true); - request_options.metricPath = 'remote-calls.keystone.regions.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'regions'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //No mangling - //You should handle input and output mangling outside of this lib going forward - regions_array = body.regions; - - //tack these on for easy consupmtion and in case we ever need pagination - regions_array.self = body.links.self; - regions_array.previous = body.links.previous; - regions_array.next = body.links.next; - - cb(null, regions_array); - }); -}; - - - -//THE FOLLOWING ARE ONLY USEFUL WITHIN GODADDY (and are prioprietary functions until/if the project meta data work is adopted) -//THUS THEY AREN"T DOCUMENTED -//-------------------------------------------------------------------------- -//make a callback(error) after retrieving all of the possible environments for the project/server meta data -//calls back with cb(error, environments_array) -Keystone.prototype.listMetaEnvironments = function(auth_token, cb) -{ - var self = this; - var request_options = {}; - var environments_array = []; - var n = 0; - - request_options = this.getRequestOptions(auth_token, '/meta_values/environment', true); - request_options.metricPath = 'remote-calls.keystone.meta-environments.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'environments'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.environments.length; n++) - { - //this is a little silly since its just id/name but meh... - environments_array[n] = self.mangleObject('MetaEnvironment', body.environments[n]); - } - cb(null, environments_array); - }); -}; - - -//make a callback(error) after retrieving all of the possible ownsers for the project/server meta data -//calls back with cb(error, owning_groups_array) -Keystone.prototype.listMetaOwningGroups = function(auth_token, cb) -{ - var self = this; - var request_options = {}; - var owning_groups_array = []; - var n = 0; - - request_options = this.getRequestOptions(auth_token, '/meta_values/owning_group', true); - request_options.metricPath = 'remote-calls.keystone.meta-owninggroups.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'owning_groups'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.owning_groups.length; n++) - { - //this is a little silly since its just id/name but meh... - owning_groups_array[n] = self.mangleObject('MetaOwningGroups', body.owning_groups[n]); - } - - cb(null, owning_groups_array); - }); -}; - - -//make a callback(error) after listing all of the project meta data -//calls back with cb(error, meta_object) -Keystone.prototype.listProjectMeta = function(project_token, project_id, cb) -{ - var self = this; - var request_options = {}; - var meta_object = {}; - - request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/meta', true); - request_options.metricPath = 'remote-calls.keystone.projects.meta.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'meta'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - meta_object = self.mangleObject('ProjectMeta', body.meta); - cb(null, meta_object); - }); -}; - - -//make a callback(error) after updating the project meta data -//meta_data should be an object with key-value pairs ie: {environment: 'dev', group: 'marketing'} -//calls back with cb(error, meta_object) -Keystone.prototype.updateProjectMeta = function(project_token, project_id, new_meta, cb) -{ - var self = this; - var request_options = {}; - var meta_data = {meta: new_meta} - var meta_object = {}; - - request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/meta', meta_data); - request_options.metricPath = 'remote-calls.keystone.projects.meta.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'meta'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - meta_object = self.mangleObject('ProjectMeta', body.meta); - cb(null, meta_object); - }); -}; - - - - -module.exports = Keystone; diff --git a/lib/mangler.js b/lib/mangler.js deleted file mode 100644 index 67f4d30..0000000 --- a/lib/mangler.js +++ /dev/null @@ -1,11 +0,0 @@ -//this default mangler object does nothing at all - just returns what you give it -//feel free to mangle at your own desire to help improve openstacks sort of randmized response types -function mangleObject(obj_type, obj) -{ - return obj; -} - - -module.exports = { - mangleObject: mangleObject -} diff --git a/lib/neutron.js b/lib/neutron.js deleted file mode 100644 index e532bc6..0000000 --- a/lib/neutron.js +++ /dev/null @@ -1,1638 +0,0 @@ -var OSUtils = require('./os-utils'); -var Request = require('./os-request'); - - -//constructor - should be the only export -function Neutron(endpoint_url, auth_token) -{ - //set this way purely to facilitate unit test dependency injetion - this.request = Request; - - //this is an optional lib that we override to normalfy the openstack responses - leave as is for no munging - this.mangler = require('./mangler'); - this.mangleObject = this.mangler.mangleObject; - - //Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes - this.url = endpoint_url.replace(/\/$/, ""); - - //auth_token should be the scoped token from the projectInfo call - this.token = auth_token; - - //default the timeout to false - this forces the static value to be used - this.timeout = 9000; - - //default request id to blank - should represent the incomming request id - this.request_id = ''; - - //default to a blank user_name - this.user_name = ''; - - //logger should default to null - might consider checking for a logMetric function in that obj too? - this.logger = null; -} - - -//setters for individual obj/call usage -//just set these prior to doing things and your good to go until you want to change it -Neutron.prototype.setTimeout = function(new_timeout) -{ - this.timeout = new_timeout; -}; - -Neutron.prototype.setRequestID = function(request_id) -{ - this.request_id = request_id; -}; - -Neutron.prototype.setUserName = function(user_name) -{ - this.user_name = user_name; -}; - -Neutron.prototype.setLogger = function(logger) -{ - this.logger = logger; -}; - -//this should only be used for dependency injection -Neutron.prototype.setRequest = function(request_lib) -{ - this.request = request_lib; -} - - -//lets us mangle/sanitize/make sane the various responses from openstack -//any replacement must simply support a static mangleObject that supports the following types [ie mangleObject(type, object)] -//SecurityGroup, SecurityRule, etc.. -Neutron.prototype.setMangler = function(mangle_lib) -{ - this.mangler = mangle_lib; - this.mangleObject = this.mangler.mangleObject; -} - - - -//returns an formatted options object - just makes the code below a little less repetitious -//path should begin with a "/" -//json_value should be almost certainly be true if you don't have an actual object you want to send over -Neutron.prototype.getRequestOptions = function(path, json_value) -{ - //start w/the instance timeout - var request_timeout = this.timeout; - if(!request_timeout) - { - //override with the static value if no instance value was given - request_timeout = Neutron.timeout; - } - var return_object = { - uri: this.url + path, - headers:{'X-Auth-Token': this.token}, - json: json_value, - timeout: this.timeout, - metricRequestID: this.request_id, - metricUserName: this.user_name, - metricLogger: this.logger - }; - - return return_object; -}; - - - -//gets a list of all networks for the given project/tenant -//calls back with cb(error, network_array) -Neutron.prototype.listNetworks = function(cb){ - var self = this; - var network_array = []; - var n = 0; - var request_options = this.getRequestOptions('/networks', true); - request_options.metricPath = 'remote-calls.neutron.networks.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'networks'; - //request_options.debug = true; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - //can't tell at this point if an empty result would come back with a blank array or just no ports at all so... - if(body.networks && body.networks.length) - { - for(n = 0; n < body.networks.length; n++) - { - network_array[n] = self.mangleObject('Network', body.networks[n]); - } - } - else - { - //leave an empty array as the result and log an issue.... that might not be an issue... or might be... - console.error('No networks found for this project - returning blank array'); - } - - cb(null, network_array); - }); -}; - - - -//gets a network by id (within the current project/tenant) -//calls back with cb(error, network_obj) -Neutron.prototype.getNetwork = function(network_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/networks/' + network_id, true); - request_options.metricPath = 'remote-calls.neutron.networks.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'network'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Network', body.network)); - }); -}; - - - - -//gets a list of all networks for the given project/tenant -//calls back with cb(error, network_array) -Neutron.prototype.listSubnets = function(cb){ - var self = this; - var subnet_array = []; - var n = 0; - var request_options = this.getRequestOptions('/subnets', true); - request_options.metricPath = 'remote-calls.neutron.subnets.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'subnets'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //error - - //can't tell at this point if an empty result would come back with a blank array or just no ports at all so... - if(body.subnets && body.subnets.length) - { - for(n = 0; n < body.subnets.length; n++) - { - subnet_array[n] = self.mangleObject('Subnet', body.subnets[n]); - } - } - else - { - //leave an empty array as the result and log an issue.... that might not be an issue... or might be... - console.error('No subnets found for this project - returning blank array'); - } - - cb(null, subnet_array); - }); -}; - - - -//gets a subnet by id (within the current project/tenant) -//calls back with cb(error, subnet_obj) -Neutron.prototype.getSubnet = function(subnet_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/subnets/' + subnet_id, true); - request_options.metricPath = 'remote-calls.neutron.subnets.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'subnet'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Subnet', body.subnet)); - }); -}; - - -//gets a list of all routers for the given project/tenant -//calls back with cb(error, router_array) -Neutron.prototype.listRouters = function(cb){ - var self = this; - var router_array = []; - var n = 0; - var request_options = this.getRequestOptions('/routers', true); - request_options.metricPath = 'remote-calls.neutron.routers.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'routers'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - //can't tell at this point if an empty result would come back with a blank array or just no ports at all so... - if(body.routers && body.routers.length) - { - for(n = 0; n < body.routers.length; n++) - { - router_array[n] = self.mangleObject('Router', body.routers[n]); - } - } - else - { - //leave an empty array as the result and log an issue.... that might not be an issue... or might be... - console.error('No routers found for this project - returning blank array'); - } - - cb(null, router_array); - }); -}; - - - -//gets a specific router by id -//calls back with cb(error, router_obj) -Neutron.prototype.getRouter = function(router_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/routers/' + router_id, true); - request_options.metricPath = 'remote-calls.neutron.routers.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'router'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Router', body.router)); - }); -}; - - - -//------------------------FLOATING IPS------------------------------ -//Creates(allocates) a new floating ip from a given ip pool(floating_network_id) -//calls back with cb(error, obj) -Neutron.prototype.createFloatingIp = function(floating_network_id, cb){ - var self = this; - var request_options = {}; - - request_options = this.getRequestOptions('/floatingips', {floatingip: {'floating_network_id': floating_network_id}}); - request_options.metricPath = 'remote-calls.neutron.floating-ips.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floatingip'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - - cb(null, self.mangleObject("NeutronFloatingIp", body.floatingip)); - }); -}; - - - -//gets a list of all floating ip's for the given project/tenant -//calls back with cb(error, ip_array) -//takes optional object that contains any filters to apply to request -// i.e. -//{ -// filters: -// { -// 'device_id': 'abcdef123567' -// } -//} -Neutron.prototype.listFloatingIps = function(options, cb){ - var self = this; - var ip_array = []; - var n = 0; - var request_options = this.getRequestOptions('/floatingips', true); - // get the actual args passed in as this function can be overloaded - var args = OSUtils.getArgsWithCallback(this.listFloatingIps.length, arguments); - options = args[0] || {}; - cb = args[1]; - request_options.metricPath = 'remote-calls.neutron.floating-ips.list'; - request_options.qs = options.filters; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floatingips'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - - //can't tell at this point if an empty result would come back with a blank array or just no ports at all so... - if(body.floatingips && body.floatingips.length) - { - for(n = 0; n < body.floatingips.length; n++) - { - ip_array[n] = self.mangleObject('NeutronFloatingIp', body.floatingips[n]); - } - } - else - { - //leave an empty array as the result and log an issue.... that might not be an issue... or might be... - console.error('No floating ips found for given project - returning blank array'); - } - - //NOTE: for some reason there is no pagination or self url for floating ips - I guess they don't expect that many of em - cb(null, ip_array); - }); -}; - - - -//gets a specific floating ip by id -//calls back with cb(error, ip_obj) -Neutron.prototype.getFloatingIp = function(ip_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/floatingips/' + ip_id, true); - request_options.metricPath = 'remote-calls.neutron.floating-ips.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floatingip'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('NeutronFloatingIp', body.floatingip)); - }); -}; - - - -//updates the port_id on a floating ip (its the only thing we can update) -//calls back with cb(error, ip_obj) -Neutron.prototype.updateFloatingIp = function(ip_id, port_id, cb){ - var self = this; - var request_options = {}; - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/floatingips/' + ip_id, {'floatingip': {'port_id': port_id}}); - request_options.metricPath = 'remote-calls.neutron.floating-ips.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floatingip'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('NeutronFloatingIp', body.floatingip)); - }); -}; - - - -//removes a floating ip by id -//calls back with cb(error) -Neutron.prototype.removeFloatingIp = function(ip_id, cb){ - var self = this; - var request_options = {}; - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/floatingips/' + ip_id); - request_options.metricPath = 'remote-calls.neutron.floating-ips.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null); - }); -}; - - - -//calls back with (error, ports) for the tenant/project of the current token -//takes optional object that contains any filters to apply to request -// i.e. -//{ -// filters: -// { -// 'device_id': 'abcdef123567' -// } -//} -Neutron.prototype.listPorts = function(options, cb){ - var self = this; - var ports_array = []; - var request_options = self.getRequestOptions('/ports', true); - // get the actual args passed in as this function can be overloaded - var args = OSUtils.getArgsWithCallback(this.listPorts.length, arguments); - options = args[0] || {}; - cb = args[1]; - - request_options.qs = options.filters; - request_options.metricPath = 'remote-calls.neutron.ports.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'ports'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - //can't tell at this point if an empty result would come back with a blank array or just no ports at all so... - if(body.ports && body.ports.length) - { - body.ports.forEach(function(port){ - ports_array.push(self.mangleObject('Port', port)); - }); - } - else - { - //leave an empty array as the result and log an issue.... that might not be an issue... or might be... - console.error('No Ports group found for given project - returning blank array'); - } - - //NOTE: for some reason there is no pagination or self url for ports - I guess they don't expect that many of em - cb(null, ports_array); - }); -}; - - - - -//gets the port with the specified id -Neutron.prototype.getPort = function(port_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/ports/' + port_id, true); - request_options.metricPath = 'remote-calls.neutron.ports.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'port'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - - cb(null, self.mangleObject("Port", body.port)); - }); -}; - - - - -//updates the data on a specified port then calls back with (error, port) -//NOTE: the network_id is not optional according to the docs but I think it is... -Neutron.prototype.updatePort = function(port_id, data, cb){ - var self = this; - var optional_keys = ['status', 'name', 'admin_state_up', 'tenant_id', 'mac_address', 'fixed_ips', 'security_groups', 'network_id', "allowed_address_pairs"]; - var put_data = {port: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //we may have 1 required param - //put_data.port.network_id = network_id; - - //now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.port[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/ports/' + port_id, put_data); - request_options.metricPath = 'remote-calls.neutron.ports.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'port'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Port', body.port)); - }); -}; - - - -//calls back with (error, security_groups) for the given tenant/project -//NOTE: the ?tenant_id= thing is undocumented -//it forces us to get back permissions only to the given project (as opposed ot the whole company) -Neutron.prototype.listSecurityGroups = function(project_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/security-groups' + '?tenant_id=' + escape(project_id), true); - request_options.metricPath = 'remote-calls.neutron.security-groups.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'security_groups'; - - this.request.get(request_options, function(error, response, body){ - var groups_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - //can't tell at this point if an empty result would come back with a blank array or just no security_groups value at all so... - if(body.security_groups.length) - { - for(n = 0; n < body.security_groups.length; n++) - { - groups_array[n] = self.mangleObject('SecurityGroup', body.security_groups[n]); - } - } - else - { - //leave an empty array as the result and log an issue.... that might not be an issue... or might be... - console.error('No Security group found for given project - returning blank array'); - } - - //NOTE: for some reason there is no pagination or self url for security groups - I guess they don't expect that many of em - cb(null, groups_array); - }); -}; - - - -Neutron.prototype.getSecurityGroup = function(group_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/security-groups/' + group_id, true); - request_options.metricPath = 'remote-calls.neutron.security-groups.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'security_group'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject("SecurityGroup", body.security_group)); - }); -}; - - - -//Creates a new security group and calls back with cb(error, result) -//NOTE: specifying tenant_id is an undocumented feature that allows you to set it to a different tenant than the token -//we use this for creating groups via a service acct -Neutron.prototype.createSecurityGroup = function(group_name, data, cb){ - var self = this; - var optional_keys = ['description', 'tenant_id']; - var post_data = {security_group: {name: group_name}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.security_group[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/security-groups', post_data); - request_options.metricPath = 'remote-calls.neutron.security-groups.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'security_group'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject("SecurityGroup", body.security_group)); - }); -}; - - - -//calls back with (error, security_group) after updating the name and or description of a security group -Neutron.prototype.updateSecurityGroup = function(group_id, data, cb){ - var self = this; - var optional_keys = ['name', 'description']; - var put_data = {security_group: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.security_group[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/security-groups/' + group_id, put_data); - request_options.metricPath = 'remote-calls.neutron.security-groups.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'security_group'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - - cb(null, self.mangleObject('SecurityGroup', body.security_group)); - }); -}; - - - -//calls back with (error) after attempting to remove the given security group -Neutron.prototype.removeSecurityGroup = function(group_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/security-groups/' + group_id, true); - request_options.metricPath = 'remote-calls.neutron.security-groups.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else return noosing! - - cb(); - }); -}; - - - - -//Calls back cb(error, security_rules) with a list of security rules for this tenant (which seems kida weird) -Neutron.prototype.listSecurityGroupRules = function(cb){ - var self = this; - var rules_array = []; - var n = 0; - var request_options = this.getRequestOptions('/security-group-rules', true); - request_options.metricPath = 'remote-calls.neutron.security-group-rules.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'security_group_rules'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - //not sure at this point if a blank rule set comes back as an empty array or what so.... - if(body.security_group_rules.length) - { - for(n = 0; n < body.security_group_rules.length; n++) - { - rules_array[n] = self.mangleObject('SecurityGroupRule', body.security_group_rules[n]); - } - } - - cb(null, rules_array); - }); -}; - - - -Neutron.prototype.getSecurityGroupRule = function(rule_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/security-group-rules/' + rule_id, true); - request_options.metricPath = 'remote-calls.neutron.security-group-rules.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'security_group_rule'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('SecurityGroupRule', body.security_group_rule)); - }); -}; - - - -//Calls back cb(error, rule) with a newly created rule from the given group, data -//note: the docs say the direction is optional but lets imagine its not... -//also we need a freakin un-mangler! -Neutron.prototype.createSecurityGroupRule = function(group_id, data, cb){ - var self = this; - var optional_keys = ['tenant_id', 'ethertype', 'protocol', 'port_range_min', 'port_range_max', 'remote_ip_prefix', 'remote_group_id']; - var post_data = {security_group_rule: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //we have 2 required params - post_data.security_group_rule.security_group_id = group_id; - post_data.security_group_rule.direction = data.direction; - - //now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.security_group_rule[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/security-group-rules', post_data); - request_options.metricPath = 'remote-calls.neutron.security-group-rules.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'security_group_rule'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - - cb(null, self.mangleObject('SecurityGroupRule', body.security_group_rule)); - }); -}; - - - -//calls back with (error) after removing the given security group rule -Neutron.prototype.removeSecurityGroupRule = function(rule_id, cb) -{ - var request_options = this.getRequestOptions('/security-group-rules/' + rule_id, true); - request_options.metricPath = 'remote-calls.neutron.security-group-rules.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - -// -------------------------------------------------- // -// ----------------- Load Balancers ----------------- // -// -------------------------------------------------- // - -Neutron.prototype.listLoadBalancers = function(cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/loadbalancers', true); - request_options.metricPath = 'remote-calls.neutron.lbaas.loadbalancers.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancers'; - - this.request.get(request_options, function(error, response, body){ - var lb_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - // Not sure at this point if a blank resource comes back as an empty array or what so.... - if(body.loadbalancers.length) - { - for(n = 0; n < body.loadbalancers.length; n++) - { - lb_array[n] = self.mangleObject('LoadBalancer', body.loadbalancers[n]); - } - } - - cb(null, lb_array); - }); -}; - - -Neutron.prototype.getLoadBalancer = function(lb_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.loadbalancers.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancer'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LoadBalancer', body.loadbalancer)); - }); -}; - - -//Calls back cb(error, rule) with a newly created resource from the given params -//also we need a freakin un-mangler! -Neutron.prototype.createLoadBalancer = function(tenant_id, vip_subnet_id, data, cb){ - var self = this; - var optional_keys = ['name', 'description', 'vip_address', 'admin_state_up', 'flavor', 'provider']; - var post_data = {loadbalancer: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //we have 2 required params - post_data.loadbalancer.vip_subnet_id = vip_subnet_id; - post_data.loadbalancer.tenant_id = tenant_id; - - //now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.loadbalancer[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/loadbalancers', post_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.loadbalancers.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancer'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LoadBalancer', body.loadbalancer)); - }); -}; - - - -//calls back with (error, lb) after updating the lb params -Neutron.prototype.updateLoadBalancer = function(lb_id, data, cb){ - var self = this; - var optional_keys = ['name', 'description', 'admin_state_up']; - var put_data = {loadbalancer: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.loadbalancer[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, put_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.loadbalancers.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancer'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('updateLoadBalancer', body.loadbalancer)); - }); -}; - - - -//calls back with (error) after attempting to remove the given lb -Neutron.prototype.removeLoadBalancer = function(lb_id, cb){ - var request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.loadbalancers.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -// -------------------------------------------------- // -// ------------------- Load Balancer Listeners -------------------- // -// -------------------------------------------------- // - -Neutron.prototype.listLBListeners = function(cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/listeners', true); - request_options.metricPath = 'remote-calls.neutron.lbaas.listeners.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listeners'; - - this.request.get(request_options, function(error, response, body){ - var listener_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - // Not sure at this point if a blank listener comes back as an empty array or what so.... - if(body.listeners && body.listeners.length) - { - for(n = 0; n < body.listeners.length; n++) - { - listener_array[n] = self.mangleObject('LBListener', body.listeners[n]); - } - } - - cb(null, listener_array); - }); -}; - - -Neutron.prototype.getLBListener = function(listener_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.listeners.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listener'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBListener', body.listener)); - }); -}; - - -// Calls back cb(error, rule) with a newly created listener from the given params -Neutron.prototype.createLBListener = function(tenant_id, loadbalancer_id, description, protocol, data, cb){ - var self = this; - var optional_keys = ['protocol_port', 'default_tls_container_ref', 'sni_container_refs', 'admin_state_up', 'name', 'connection_limit']; - var post_data = {listener: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //we have 4 required params - post_data.listener.tenant_id = tenant_id; - post_data.listener.loadbalancer_id = loadbalancer_id; - post_data.listener.description = description; - post_data.listener.protocol = protocol; - - //now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.listener[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/listeners', post_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.listeners.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listener'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBListener', body.listener)); - }); -}; - - -//calls back with (error, listener) after updating the listener -Neutron.prototype.updateLBListener = function(listener_id, data, cb){ - var self = this; - var optional_keys = ['name', 'description', 'admin_state_up', 'connection_limit', 'default_tls_container_ref', 'sni_container_refs']; - var put_data = {listener: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.listener[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, put_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.listeners.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listener'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBListener', body.listener)); - }); -}; - - -//calls back with (error) after attempting to remove the given resource -Neutron.prototype.removeLBListener = function(listener_id, cb){ - var request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.listeners.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - -// -------------------------------------------------- // -// -------------------- LBPools --------------------- // -// -------------------------------------------------- // - -Neutron.prototype.listLBPools = function(cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/pools', true); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pools'; - - this.request.get(request_options, function(error, response, body){ - var pool_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - if(body.pools.length) - { - for(n = 0; n < body.pools.length; n++) - { - pool_array[n] = self.mangleObject('LBPool', body.pools[n]); - } - } - - cb(null, pool_array); - }); -}; - - -Neutron.prototype.getLBPool = function(pool_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pool'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBPool', body.pool)); - }); -}; - - -// Calls back cb(error, rule) with a newly created resource from the given params -Neutron.prototype.createLBPool = function(tenant_id, protocol, lb_algorithm, listener_id, data, cb){ - var self = this; - var optional_keys = ['admin_state_up', 'name', 'description', 'session_persistence']; - var post_data = {pool: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - // we have 4 required params - post_data.pool.tenant_id = tenant_id; - post_data.pool.protocol = protocol; - post_data.pool.lb_algorithm = lb_algorithm; - post_data.pool.listener_id = listener_id; - - // now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.pool[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/pools', post_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pool'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBPool', body.pool)); - }); -}; - - -Neutron.prototype.updateLBPool = function(pool_id, data, cb){ - var self = this; - var optional_keys = ['name', 'description', 'admin_state_up', 'lb_algorithm', 'session_persistence']; - var put_data = {pool: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.pool[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, put_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pool'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBPool', body.pool)); - }); -}; - - -//calls back with (error) after attempting to remove the given resource -Neutron.prototype.removeLBPool = function(pool_id, cb){ - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - -// -------------------------------------------------- // -// -------------------- LBPoolMembers --------------------- // -// -------------------------------------------------- // - -Neutron.prototype.listLBPoolMembers = function(pool_id, cb){ - var self = this; - var member_array = []; - var n = 0; - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', true); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.members.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'members'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - if(body.members.length) - { - for(n = 0; n < body.members.length; n++) - { - member_array[n] = self.mangleObject('LBPoolMember', body.members[n]); - } - } - - cb(null, member_array); - }); -}; - - -Neutron.prototype.getLBPoolMember = function(pool_id, member_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.members.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'member'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBPoolMember', body.member)); - }); -}; - - -// Calls back cb(error, rule) with a newly created resource from the given params -Neutron.prototype.createLBPoolMember = function(pool_id, tenant_id, address, protocol_port, data, cb){ - var self = this; - var optional_keys = ['admin_state_up', 'weight', 'subnet_id']; - var post_data = {member: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - // we have 4 required params - post_data.member.tenant_id = tenant_id; - post_data.member.address = address; - post_data.member.protocol_port = protocol_port; - - // now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.member[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', post_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.members.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'member'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBPoolMember', body.member)); - }); -}; - - -Neutron.prototype.updateLBPoolMember = function(pool_id, member_id, data, cb){ - var self = this; - var optional_keys = ['weight', 'admin_state_up']; - var put_data = {member: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.member[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, put_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.members.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'member'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBMember', body.member)); - }); -}; - - -//calls back with (error) after attempting to remove the given resource -Neutron.prototype.removeLBPoolMember = function(pool_id, member_id, cb){ - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id +'/members/' + member_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.pools.members.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - -// -------------------------------------------------- // -// ----------------- LBHealthMonitors ----------------- // -// -------------------------------------------------- // - - -Neutron.prototype.listLBHealthMonitors = function(cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/healthmonitors', true); - request_options.metricPath = 'remote-calls.neutron.lbaas.healthmonitors.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitors'; - - this.request.get(request_options, function(error, response, body){ - var healthmonitor_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - if(body.healthmonitors && body.healthmonitors.length) - { - for(n = 0; n < body.healthmonitors.length; n++) - { - healthmonitor_array[n] = self.mangleObject('LBHealthMonitor', body.healthmonitors[n]); - } - } - - cb(null, healthmonitor_array); - }); -}; - - -Neutron.prototype.getLBHealthMonitor = function(health_monitor_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.healthmonitors.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitor'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBHealthMonitor', body.healthmonitor)); - }); -}; - - -// Calls back cb(error, rule) with a newly created resource from the given params -Neutron.prototype.createLBHealthMonitor = function(tenant_id, type, delay, timeout, max_retries, pool_id, data, cb){ - var self = this; - var optional_keys = ['http_method', 'url_path', 'expected_codes', 'admin_state_up']; - var post_data = {healthmonitor: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - // we have 4 required params - post_data.healthmonitor.tenant_id = tenant_id; - post_data.healthmonitor.type = type; - post_data.healthmonitor.delay = delay; - post_data.healthmonitor.timeout = timeout; - post_data.healthmonitor.max_retries = max_retries; - post_data.healthmonitor.pool_id = pool_id; - - // now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.healthmonitor[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/healthmonitors', post_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.healthmonitors.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitor'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBHealthMonitor', body.healthmonitor)); - }); -}; - - -Neutron.prototype.updateLBHealthMonitor = function(health_monitor_id, data, cb){ - var self = this; - var optional_keys = ['delay', 'timeout', 'max_retries', 'http_method', 'url_path', 'expected_codes', 'admin_state_up']; - var put_data = {healthmonitor: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.healthmonitor[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, put_data); - request_options.metricPath = 'remote-calls.neutron.lbaas.healthmonitors.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitor'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBHealthMonitor', body.healthmonitor)); - }); -}; - - -//calls back with (error) after attempting to remove the given resource -Neutron.prototype.removeLBHealthMonitor = function(health_monitor_id, cb){ - var request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true); - request_options.metricPath = 'remote-calls.neutron.lbaas.healthmonitors.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - -// -------------------------------------------------- // -// ---------------------- Stats --------------------- // -// -------------------------------------------------- // -//NOTE: May not be available in your openstack installation -//Leaving it here as it may be of use to those who do have it available -Neutron.prototype.getLBStats = function(lb_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id + '/stats', true); - request_options.metricPath = 'remote-calls.neutron.lbaas.loadbalancers.stats.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'stats'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('LBStat', body.stats)); - }); -}; - -module.exports = Neutron; diff --git a/lib/nova.js b/lib/nova.js deleted file mode 100644 index da93504..0000000 --- a/lib/nova.js +++ /dev/null @@ -1,1254 +0,0 @@ -var util = require('util'); -var osutils = require('./os-utils'); -var Request = require('./os-request'); - - -//constructor - should be the only export -function Nova(endpoint_url, auth_token) -{ - //set this way purely to facilitate unit test dependency injetion - this.request = Request; - - //this is an optional lib that we override to normalfy the openstack responses - leave as is for no munging - this.mangler = require('./mangler'); - this.mangleObject = this.mangler.mangleObject; - - //Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes - this.url = endpoint_url.replace(/\/$/, ""); - - //auth_token should be the scoped token from the projectInfo call - this.token = auth_token; - - //default the timeout to false - this forces the static value to be used - this.timeout = 9000; - - //default request id to blank - should represent the incomming request id - this.request_id = ''; - - //default to a blank user_name - this.user_name = ''; - - //logger should default to null - might consider checking for a logMetric function in that obj too? - this.logger = null; -} - -//setters for individual obj/call usage -//just set these prior to doing things and your good to go until you want to change it -Nova.prototype.setTimeout = function(new_timeout) -{ - this.timeout = new_timeout; -}; - -Nova.prototype.setRequestID = function(request_id) -{ - this.request_id = request_id; -}; - -Nova.prototype.setUserName = function(user_name) -{ - this.user_name = user_name; -}; - -Nova.prototype.setLogger = function(logger) -{ - this.logger = logger; -}; - -//this should only be used for dependency injection -Nova.prototype.setRequest = function(request_lib) -{ - this.request = request_lib; -} - -//lets us mangle/sanitize/make sane the various responses from openstack -//any replacement must simply support a static mangleObject that supports the following types [ie mangleObject(type, object)] -//Server, MetaData, Flavor, ServerImage, FloatingIp, IpPool, KeyPair, QuotaSet -Nova.prototype.setMangler = function(mangle_lib) -{ - this.mangler = mangle_lib; - this.mangleObject = this.mangler.mangleObject; -} - - - -//returns an formatted options object - just makes the code below a little less repetitious -//path should begin with a "/" -//json_value should be almost certainly be true if you don't have an actual object you want to send over -Nova.prototype.getRequestOptions = function(path, json_value) -{ - //start w/the instance timeout - var request_timeout = this.timeout; - if(!request_timeout) - { - //override with the static value if no instance value was given - request_timeout = Nova.timeout; - } - var return_object = { - uri: this.url + path, - headers:{'X-Auth-Token': this.token}, - json: json_value, - timeout: this.timeout, - metricRequestID: this.request_id, - metricUserName: this.user_name, - metricLogger: this.logger - }; - - return return_object; -}; - - - -// ---------------- -// Server methods -// ---------------- -//NOTE: options is an optional hash that lets you specify filters on the listing call ie: {limit: 1} -Nova.prototype.listServers = function(options, cb) -{ - //first a little param tweaking to actually make options optional (at least until we require node8 and can just default options to {} - var args = osutils.getArgsWithCallback(this.listServers.length, arguments); - options = args[0] || {}; - cb = args[1]; - - //now on with the show - var self = this; - var request_options = this.getRequestOptions('/servers/detail', true); - request_options.metricPath = 'remote-calls.nova.servers.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'servers'; - request_options.qs = options; - - this.request.get(request_options, function(error, response, body){ - var servers_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.servers.length; n++) - { - servers_array[n] = self.mangleObject('Server', body.servers[n]); - } - - cb(null, servers_array); - }); -}; - - - -Nova.prototype.getServer = function(id, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/servers/' + id, true); - request_options.metricPath = 'remote-calls.nova.servers.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'server'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Server', body.server)); - }); -}; - - - -Nova.prototype.createServer = function(data, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/servers', data); - request_options.metricPath = 'remote-calls.nova.servers.create'; - request_options.validateStatus = true; - //Commenting out so that we can handle returns of 'servers' for multiple creates - //request_options.requireBodyObject = 'server'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Server', body.server)); - }); -}; - - - -Nova.prototype.renameServer = function(id, name, cb) -{ - var data = {server:{'name': name}}; - var request_options = this.getRequestOptions('/servers/' + id, data); - request_options.metricPath = 'remote-calls.nova.servers.rename'; - request_options.validateStatus = true; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.resizeServer = function(id, flavor, cb) -{ - var data = {resize: {flavorRef: flavor}}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.resize'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.confirmResizeServer = function(id, cb) -{ - var data = {confirmResize: null}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.resize-confirm'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.revertResizeServer = function(id, cb) -{ - var data = {revertResize: null}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.resize-revert'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.removeServer = function(id, cb) -{ - var request_options = this.getRequestOptions('/servers/' + id, true); - request_options.metricPath = 'remote-calls.nova.servers.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.rebootServer = function(id, cb) -{ - var data = {reboot: {type: "SOFT"}}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.reboot'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.forceRebootServer = function(id, cb) -{ - var data = {reboot: {type: "HARD"}}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.reboot-force'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.stopServer = function(id, cb) -{ - var data = {"os-stop" : null}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.stop'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - - cb(); - }); -}; - - - -Nova.prototype.startServer = function(id, cb) -{ - var data = {'os-start': null}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.start'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.pauseServer = function(id, cb) -{ - var data = {pause: null}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.pause'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.suspendServer = function(id, cb) -{ - var data = {suspend: null}; - var request_options = this.getRequestOptions('/servers/' + id + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.suspend'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.resumeServer = function(id, cb) -{ - var self = this; - - this.getServer(id, function(err, server){ - var data = {}; - var request_options = {}; - var custom_error = null; - - if(err) - { - cb(err); - return; - } - - if(server.status != 'PAUSED' && server.status != 'SUSPENDED') - { - cb(new Error('Cannot resume server. Server is not in a paused or suspected state.')); - return; - } - //else - - if(server.status == 'PAUSED') - { - data = {unpause: null}; - } - else //SUSPENDED - { - data = {resume: null}; - } - request_options = self.getRequestOptions('/servers/' + escape(id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.resume'; - request_options.validateStatus = true; - - self.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); - }); -}; - - - -Nova.prototype.getServerConsoleURL = function(type, id, cb) -{ - var data = {}; - var request_options = {}; - - if(type == 'spice-html5') - { - data = {'os-getSPICEConsole' :{'type' : type}}; - } - else - { - if(type === undefined || !type) - { - type = 'novnc'; - } - data = {'os-getVNCConsole': {'type': type}}; - } - request_options = this.getRequestOptions('/servers/' + escape(id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.console-urls.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'console.url'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.console.url); - }); -}; - - - -//gets [length] lines form the log? of an instance -Nova.prototype.getServerLog = function(id, length, cb) -{ - var data = {}; - var request_options = {}; - - if(length === undefined || !length) - { - length = 35; - } - - data = {'os-getConsoleOutput': {'length': length}}; - request_options = this.getRequestOptions('/servers/' + escape(id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.logs.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'output'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.output); - }); -}; - - - -//creates an image from the current disk of an instance -//takes the id of an instance as well as any meta-data to be added to the image -//calls back with(error, new_image_info) -Nova.prototype.createServerImage = function(id, data, cb) -{ - var self = this; - var name = ''; - var metadata = {}; - var request_options = {}; - - if(data.name) - { - name = data.name - } - if(data.metadata) - { - metadata = data.metadata; - } - - data = {createImage: {'name': name, 'metadata': metadata}}; - request_options = this.getRequestOptions('/servers/' + escape(id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.images.create'; - request_options.validateStatus = true; - //commenting out to support later versions of nova that dont return - //request_options.requireBodyObject = 'output'; - - this.request.post(request_options, function(error, response, body){ - var url = ''; - var image_id = ''; - - if(error) - { - cb(error); - return; - } - //else if nova 2.45+ the image id is in the body, else its in the header (in theory) - - if(body && body.image_id) - { - //nova 2.45+ - image_id = body.image_id; - } - else - { - //old skool - url = response.headers.location; - image_id = url.match(/.*\/images\/(.*)/)[1]; - } - - //removing ServerImage mangling as we are updating this method with a diffrent format in 2.2+ - //going to try and output as close to what recent nova does regardless of version of nova used - cb(null, {'image_id': image_id}); - }); -}; - - - -Nova.prototype.setServerMetadata = function(id, data, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/servers/' + escape(id) + '/metadata', {metadata: data}); - request_options.metricPath = 'remote-calls.nova.servers.metadata.update'; - request_options.validateStatus = true; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('MetaData', body)); - }); -}; - - - -// ---------------- -// Flavor -// ---------------- -Nova.prototype.listFlavors = function(cb) -{ - var self = this; - var flavors_array = []; - var request_options = this.getRequestOptions('/flavors/detail', true); - request_options.metricPath = 'remote-calls.nova.flavors.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'flavors'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else we need to arrayify mangle the response(s) - - for(var n = 0; n < body.flavors.length; n++) - { - flavors_array[n] = self.mangleObject('Flavor', body.flavors[n]); - } - - //theres no self, prev, or next pagiation stuff so just return the array - cb(null, flavors_array); - }); -}; - - - -Nova.prototype.getFlavor = function(id, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/flavors/' + escape(id), true); - request_options.metricPath = 'remote-calls.nova.flavors.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'flavor'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('Flavor', body.flavor)); - }); -}; - - - -// ---------------- -// Project Network -// ---------------- -Nova.prototype.listProjectNetworks = function(cb) -{ - var projectNetworks_array = []; - var request_options = this.getRequestOptions('/os-tenant-networks', true); - request_options.metricPath = 'remote-calls.nova.os-tenant-networks.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'networks'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - - //No mangling needed as this is a new method/obj-type - //Input and output mangling should be handled outside of the lib going forward - projectNetworks_array = body.networks; - - //theres no self, prev, or next pagiation stuff so just return the array - cb(null, projectNetworks_array); - }); -}; - - - -// ---------------- -// Floating IP -// ---------------- -Nova.prototype.listFloatingIps = function(cb) -{ - var self = this; - var ip_array = []; - var request_options = this.getRequestOptions('/os-floating-ips', true); - request_options.metricPath = 'remote-calls.nova.floating-ips.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floating_ips'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - if(body.floating_ips && body.floating_ips.length) - { - for(var i = 0 ; i < body.floating_ips.length; i++) - { - ip_array.push(self.mangleObject('NovaFloatingIp', body.floating_ips[i])); - } - } - - cb(null, ip_array); - }); -}; - - - -Nova.prototype.getFloatingIp = function(id, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/os-floating-ips/' + escape(id), true); - request_options.metricPath = 'remote-calls.nova.floating-ips.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floating_ip'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('NovaFloatingIp', body.floating_ip)); - }); -}; - - - -//allocates assigns an ip -//calls cb with the info on the created ip -Nova.prototype.createFloatingIp = function(data, cb) -{ - var self = this; - var post_data = true; - if(data.pool !== undefined) - { - post_data = {pool: data.pool}; - } - var request_options = this.getRequestOptions('/os-floating-ips', post_data); - request_options.metricPath = 'remote-calls.nova.floating-ips.allocate'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floating_ip'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('NovaFloatingIp', body.floating_ip)); - }); -}; - - - -//removes the floating ip from the pool and dissasociates and generally hates all things -//calls back with cb(error) -Nova.prototype.removeFloatingIp = function(id, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/os-floating-ips/' + escape(id), true); - request_options.metricPath = 'remote-calls.nova.floating-ips.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null); - }); -}; - - - -//associates a given instance with a given ip address (nova only supports the ip_address not the ip_id) -//calls back with cb(error) as nova doesn't provide a result beyond a 204 -Nova.prototype.associateFloatingIp = function(instance_id, ip_address, cb) -{ - var self = this; - var data = {addFloatingIp: {'address': ip_address}}; - var request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.floating-ips.associate'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -//disassociates a given instance with a given ip address (nova only supports the ip_address not the ip_id) -//calls back with cb(error) as nova doesn't provide a result beyond a 204 -Nova.prototype.disassociateFloatingIp = function(instance_id, ip_address, cb) -{ - var self = this; - var data = {removeFloatingIp: {'address': ip_address}}; - var request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.floating-ips.disassociate'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -// ---------------- -// Floating IP Pool -// ---------------- -Nova.prototype.listFloatingIpPools = function(cb) -{ - var self = this; - var return_array = []; - var request_options = this.getRequestOptions('/os-floating-ip-pools', true); - request_options.metricPath = 'remote-calls.nova.ip-pool-list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'floating_ip_pools'; - - this.request.get(request_options, function(error, response, body){ - var pools_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.floating_ip_pools.length; n++) - { - pools_array[n] = self.mangleObject('FloatingIpPool', body.floating_ip_pools[n]); - } - - cb(null, pools_array); - }); -}; - - - -//since theres apparently no getIpPool info method in the nova api... -//NOTE: the return from ip_pools is weird and doesn' thave an id but its a better term. id == name in reality -Nova.prototype.getFloatingIpPool = function(id, cb) -{ - this.listFloatingIpPools(function(error, pools){ - var pool = null; - - if(error) - { - cb(error); - return; - } - //else - - for(var i = 0; i < pools.length; i++) - { - if(!pool && pools[i].name == id) - { - pool = pools[i]; - } - } - - if(!pool) - { - cb(new Error('No pool with specified id found')); - return; - } - //else - - cb(null, pool); - }); -}; - - - -// ---------------- -// Availability Zone -// ---------------- -Nova.prototype.listAvailabilityZones = function(cb){ - var self = this; - var request_options = this.getRequestOptions('/os-availability-zone', true); - request_options.metricPath = 'remote-calls.nova.os-availability-zones.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'availabilityZoneInfo'; - - this.request.get(request_options, function(error, response, body){ - var zones_array = []; - var zone = {}; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.availabilityZoneInfo.length; n++) - { - zones_array[n] = self.mangleObject('AvailabilityZone', body.availabilityZoneInfo[n]); - } - - cb(null, zones_array); - }); -}; - - - -//and since there is no method to get zone info in the nova api... -//NOTE: the return from listAvailabilityZones is weird and doesn' thave an id but its a better term. id == name in reality -Nova.prototype.getAvailabilityZone = function(id, cb){ - this.listAvailabilityZones(function(error, zones){ - var zone = null; - - if(error) - { - cb(error); - return; - } - //else - - for(var i = 0; i < zones.length; i++) - { - if(!zone && zones[i].zoneName== id) - { - zone = zones[i]; - } - } - - if(!zone) - { - cb(new Error('No zone with specified id found')); - } - //else - - cb(null, zone); - }); -} - - - -// --------------- -// (SSH) Key Pairs -// --------------- -Nova.prototype.listKeyPairs = function(cb){ - var self = this; - var request_options = this.getRequestOptions('/os-keypairs', true); - request_options.metricPath = 'remote-calls.nova.key-pairs.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'keypairs'; - - this.request.get(request_options, function(error, response, body){ - var kp_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - for(n = 0; n < body.keypairs.length; n++) - { - kp_array[n] = self.mangleObject('KeyPair', body.keypairs[n].keypair); - } - - cb(null, kp_array); - }); -}; - - - -Nova.prototype.getKeyPair = function(id, cb){ - var self = this; - var request_options = this.getRequestOptions('/os-keypairs/' + id, true); - request_options.metricPath = 'remote-calls.nova.key-pairs.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'keypair'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('KeyPair', body.keypair)); - }); -}; - - - -Nova.prototype.createKeyPair = function(name, public_key, cb) -{ - var self = this; - var data = {}; - var request_options = {}; - - data = {keypair: {'name': name}}; - if(public_key) - { - data.keypair.public_key = public_key; - } - request_options = this.getRequestOptions('/os-keypairs', data); - request_options.metricPath = 'remote-calls.nova.key-pairs.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'keypair'; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('KeyPair', body.keypair)); - }); -}; - - - -Nova.prototype.removeKeyPair = function(id, cb) -{ - var request_options = this.getRequestOptions('/os-keypairs/' + id, true); - request_options.metricPath = 'remote-calls.nova.key-pairs.remove'; - request_options.validateStatus = true; - - this.request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -// --------------- -// Quota/Usage -// --------------- -Nova.prototype.getQuotaSet = function(project_id, cb){ - var self = this; - var request_options = this.getRequestOptions('/os-quota-sets/' + escape(project_id), true); - request_options.metricPath = 'remote-calls.nova.quota-sets.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'quota_set'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('QuotaSet', body.quota_set)); - }); -}; - - -//updates the quota for a given project_id -//data should be an object with all of the things you want to update -//supported values are cores, ram, instances, floating_ip, and anything else in the docs -//calls back with cb(error, quota_set) where quota_set is an object with all the updated params -//*****NOTE: the token required for this call is usually the one scoped to the admin (usually 'openstack') project -//even though the call is not usually on that specific project_id -Nova.prototype.setQuotaSet = function(project_id, data, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/os-quota-sets/' + escape(project_id), {quota_set: data}); - request_options.metricPath = 'remote-calls.nova.quota-sets.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'quota_set'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('QuotaSet', body.quota_set)); - }); -}; - - - -//start_date and end_date should just be any 2 date objects -Nova.prototype.getTenantUsage = function(project_id, start_date_obj, end_date_obj, cb) -{ - var self = this; - var url = '/os-simple-tenant-usage/' + escape(project_id); - - // format of dates should be: %Y-%m-%d %H:%M:%S.%f - url += '?start=' + start_date_obj.toISOString().replace('T',' ').replace('Z',''); - url += '&end=' + end_date_obj.toISOString().replace('T',' ').replace('Z',''); - - var request_options = this.getRequestOptions(url, true); - request_options.metricPath = 'remote-calls.nova.tenant-usage.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'tenant_usage'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('TenantUsage', body.tenant_usage)); - }); -}; - - - -// --------------- -// SecurityGroup -// --------------- -Nova.prototype.assignSecurityGroup = function(security_group_name, instance_id, cb){ - var data = {'addSecurityGroup': {'name': security_group_name}}; - var request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.add-security-group'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -Nova.prototype.removeSecurityGroup = function(security_group_name, instance_id, cb) -{ - var data = {'removeSecurityGroup': {'name': security_group_name}}; - var request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data); - request_options.metricPath = 'remote-calls.nova.servers.remove-security-group'; - request_options.validateStatus = true; - - this.request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -// -------------------------------------------------- // -// Image MetaData (still handled by nova because....) // -// -------------------------------------------------- // -Nova.prototype.getImageMetaData = function(id, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/images/' + escape(id) + '/metadata', true); - request_options.metricPath = 'remote-calls.nova.images.metadata.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'metadata'; - - this.request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('MetaData', body.metadata)); - }); -}; - - - -Nova.prototype.setImageMetaData = function(id, data, cb) -{ - var self = this; - var request_options = this.getRequestOptions('/images/' + escape(id) + '/metadata', {metadata: data}); - request_options.metricPath = 'remote-calls.nova.images.metadata.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'metadata'; - - this.request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, self.mangleObject('MetaData', body.metadata)); - }); -}; - - -module.exports = Nova; diff --git a/lib/octavia.js b/lib/octavia.js deleted file mode 100644 index c059d39..0000000 --- a/lib/octavia.js +++ /dev/null @@ -1,1122 +0,0 @@ -var Async = require('async'); -var Request = require('./os-request'); - - -//constructor - should be the only export -function Octavia(endpoint_url, auth_token) -{ - //Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes - this.url = endpoint_url.replace(/\/$/, ""); - - //auth_token should be the scoped token from the projectInfo call - this.token = auth_token; - - //default the timeout to false - this forces the static value to be used - this.timeout = 9000; - - //default request id to blank - should represent the incomming request id - this.request_id = ''; - - //default to a blank user_name - this.user_name = ''; - - //logger should default to null - might consider checking for a logMetric function in that obj too? - this.logger = null; - - //the # of retries to attempt if a call is met with a 409/immutable error - this.retries = 5; - - //the delay between the call attempts when met with a 409/immutable error - this.retry_delay = 2000; -} - - -//setters for individual obj/call usage -//just set these prior to doing things and your good to go until you want to change it -Octavia.prototype.setTimeout = function(new_timeout) -{ - this.timeout = new_timeout; -}; - -Octavia.prototype.setRequestID = function(request_id) -{ - this.request_id = request_id; -}; - -Octavia.prototype.setUserName = function(user_name) -{ - this.user_name = user_name; -}; - -Octavia.prototype.setLogger = function(logger) -{ - this.logger = logger; -}; - -Octavia.prototype.setRetries = function(retries) -{ - this.retries = retries; -}; - -Octavia.prototype.setRetryDelay = function(retry_delay) -{ - this.retry_delay = retry_delay; -}; - - -//returns an formatted options object - just makes the code below a little less repetitious -//path should begin with a "/" -//json_value should be almost certainly be true if you don't have an actual object you want to send over -Octavia.prototype.getRequestOptions = function(path, json_value) -{ - //start w/the instance timeout - var request_timeout = this.timeout; - if(!request_timeout) - { - //override with the static value if no instance value was given - request_timeout = Octavia.timeout; - } - var return_object = { - uri: this.url + path, - headers:{'X-Auth-Token': this.token}, - json: json_value, - timeout: this.timeout, - metricRequestID: this.request_id, - metricUserName: this.user_name, - metricLogger: this.logger - }; - - return return_object; -}; - - - -Octavia.prototype.listLoadBalancers = function(cb){ - var request_options = this.getRequestOptions('/lbaas/loadbalancers', true); - request_options.metricPath = 'remote-calls.octavia.lbaas.loadbalancers.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancers'; - - Request.get(request_options, function(error, response, body){ - var lb_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - // Not sure at this point if a blank resource comes back as an empty array or what so.... - if(body.loadbalancers.length) - { - for(n = 0; n < body.loadbalancers.length; n++) - { - lb_array[n] = body.loadbalancers[n]; - } - } - - cb(null, lb_array); - }); -}; - - -Octavia.prototype.getLoadBalancer = function(lb_id, cb){ - var request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.loadbalancers.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancer'; - - Request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.loadbalancer); - }); -}; - - -//Calls back cb(error, rule) with a newly created resource from the given params -Octavia.prototype.createLoadBalancer = function(project_id, data, cb){ - var optional_keys = ['name', 'description', 'vip_address', 'vip_network_id', 'vip_port_id', 'admin_state_up', 'flavor', 'provider']; - var post_data = {loadbalancer: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the data values - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.loadbalancer[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/loadbalancers', post_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.loadbalancers.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancer'; - request_options.debug = true; - - Request.post(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.loadbalancer); - }); -}; - - - -//calls back with (error, lb) after updating the lb params -Octavia.prototype.updateLoadBalancer = function(lb_id, data, cb){ - var optional_keys = ['name', 'description', 'admin_state_up']; - var put_data = {loadbalancer: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.loadbalancer[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, put_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.loadbalancers.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'loadbalancer'; - - Request.put(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.loadbalancer); - }); -}; - - - -//calls back with (error) after attempting to remove the given lb -Octavia.prototype.removeLoadBalancer = function(lb_id, cb){ - var request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.loadbalancers.remove'; - request_options.validateStatus = true; - - Request.del(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(); - }); -}; - - - -// -------------------------------------------------- // -// ------------------- Load Balancer Listeners -------------------- // -// -------------------------------------------------- // - -Octavia.prototype.listLBListeners = function(cb){ - var request_options = this.getRequestOptions('/lbaas/listeners', true); - request_options.metricPath = 'remote-calls.octavia.lbaas.listeners.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listeners'; - - Request.get(request_options, function(error, response, body){ - var listener_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - // Not sure at this point if a blank listener comes back as an empty array or what so.... - if(body.listeners && body.listeners.length) - { - for(n = 0; n < body.listeners.length; n++) - { - listener_array[n] = body.listeners[n]; - } - } - - cb(null, listener_array); - }); -}; - - -Octavia.prototype.getLBListener = function(listener_id, cb){ - var request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.listeners.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listener'; - - Request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.listener); - }); -}; - - - -//Creates a load balancer listener -//calls back with cb(error, listener) -Octavia.prototype.createLBListener = function(loadbalancer_id, protocol, data, cb){ - var self = this; - var done = false; - var count = 0; - var optional_keys = ['default_pool', 'default_pool_id', 'insert_headers', 'l7policies', 'description', 'protocol_port', 'default_tls_container_ref', 'sni_container_refs', 'admin_state_up', 'name', 'connection_limit']; - var post_data = {listener: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //we have 2 required params - post_data.listener.loadbalancer_id = loadbalancer_id; - post_data.listener.protocol = protocol; - - //now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.listener[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/listeners', post_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.listeners.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listener'; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.post(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.listener); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - - -//calls back with (error, listener) after updating the listener -Octavia.prototype.updateLBListener = function(listener_id, data, cb){ - var self = this; - var done = false; - var count = 0; - var optional_keys = ['default_pool_id', 'insert_headers', 'name', 'description', 'admin_state_up', 'connection_limit', 'default_tls_container_ref', 'sni_container_refs']; - var put_data = {listener: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.listener[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, put_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.listeners.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'listener'; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.put(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.listener); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - -//calls back with (error) after attempting to remove the given resource -Octavia.prototype.removeLBListener = function(listener_id, cb){ - var self = this; - var count = 0; - var done = false; - var request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.listeners.remove'; - request_options.validateStatus = true; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.del(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else we are done one way or another - - done = true; - cb(error); - }); - }, - function(error){ - cb(error); - } - ); -}; - - - -// -------------------------------------------------- // -// -------------------- LBPools --------------------- // -// -------------------------------------------------- // - -Octavia.prototype.listLBPools = function(cb){ - var request_options = this.getRequestOptions('/lbaas/pools', true); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pools'; - - Request.get(request_options, function(error, response, body){ - var pool_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - if(body.pools.length) - { - for(n = 0; n < body.pools.length; n++) - { - pool_array[n] = body.pools[n]; - } - } - - cb(null, pool_array); - }); -}; - - - -Octavia.prototype.getLBPool = function(pool_id, cb){ - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pool'; - - Request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.pool); - }); -}; - - - -// Calls back cb(error, rule) with a newly created resource from the given params -Octavia.prototype.createLBPool = function(protocol, lb_algorithm, data, cb){ - var self = this; - var count = 0; - var done = false; - var optional_keys = ['loadbalancer_id', 'listener_id', 'admin_state_up', 'name', 'description', 'session_persistence']; - var post_data = {pool: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //add the required params - post_data.pool.protocol = protocol; - post_data.pool.lb_algorithm = lb_algorithm; - - // now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.pool[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/pools', post_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pool'; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.post(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.pool); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - -Octavia.prototype.updateLBPool = function(pool_id, data, cb){ - var self = this; - var count = 0; - var done = false; - var optional_keys = ['name', 'description', 'admin_state_up', 'lb_algorithm', 'session_persistence']; - var put_data = {pool: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.pool[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, put_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'pool'; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.put(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.pool); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - - -//calls back with (error) after attempting to remove the given resource -Octavia.prototype.removeLBPool = function(pool_id, cb){ - var self = this; - var count = 0; - var done = false; - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.remove'; - request_options.validateStatus = true; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.del(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else we are done one way or another - - done = true; - cb(error); - }); - }, - function(error){ - cb(error); - } - ); -}; - - -// -------------------------------------------------- // -// -------------------- LBPoolMembers --------------------- // -// -------------------------------------------------- // - -Octavia.prototype.listLBPoolMembers = function(pool_id, cb){ - var member_array = []; - var n = 0; - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', true); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.members.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'members'; - - Request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - if(body.members.length) - { - for(n = 0; n < body.members.length; n++) - { - member_array[n] = body.members[n]; - } - } - - cb(null, member_array); - }); -}; - - - -Octavia.prototype.getLBPoolMember = function(pool_id, member_id, cb){ - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.members.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'member'; - - Request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.member); - }); -}; - - - -//Creates a member on a given pool -//calls back with cb(error, member_obj) -Octavia.prototype.createLBPoolMember = function(pool_id, address, protocol_port, data, cb){ - var self = this; - var count = 0; - var done = false; - var optional_keys = ['name', 'monitor_port', 'monitor_address', 'admin_state_up', 'weight', 'subnet_id']; - var post_data = {member: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //handle the required params - post_data.member.address = address; - post_data.member.protocol_port = protocol_port; - - // now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.member[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', post_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.members.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'member'; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.post(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.member); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - -Octavia.prototype.updateLBPoolMember = function(pool_id, member_id, data, cb){ - var self = this; - var count = 0; - var done = false; - var optional_keys = ['name', 'monitor_port', 'monitor_address', 'weight', 'admin_state_up']; - var put_data = {member: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.member[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, put_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.members.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'member'; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.put(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.member); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - -//calls back with (error) after attempting to remove the given resource -Octavia.prototype.removeLBPoolMember = function(pool_id, member_id, cb){ - var self = this; - var count = 0; - var done = false; - var request_options = this.getRequestOptions('/lbaas/pools/' + pool_id +'/members/' + member_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.pools.members.remove'; - request_options.validateStatus = true; - request_options.debug = true; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.del(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else we are done one way or another - - done = true; - cb(error); - }); - }, - function(error){ - cb(error); - } - ); -}; - - -// -------------------------------------------------- // -// ----------------- Health Monitors ---------------- // -// -------------------------------------------------- // - - -Octavia.prototype.listLBHealthMonitors = function(cb){ - var request_options = this.getRequestOptions('/lbaas/healthmonitors', true); - request_options.metricPath = 'remote-calls.octavia.lbaas.healthmonitors.list'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitors'; - - Request.get(request_options, function(error, response, body){ - var healthmonitor_array = []; - var n = 0; - - if(error) - { - cb(error); - return; - } - //else - - if(body.healthmonitors && body.healthmonitors.length) - { - for(n = 0; n < body.healthmonitors.length; n++) - { - healthmonitor_array[n] = body.healthmonitors[n]; - } - } - - cb(null, healthmonitor_array); - }); -}; - - -Octavia.prototype.getLBHealthMonitor = function(health_monitor_id, cb){ - var request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.healthmonitors.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitor'; - - Request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.healthmonitor); - }); -}; - - - -//Creates a healthcheck for a given pool -//calls back with cb(error, health_monitor_obj) -Octavia.prototype.createLBHealthMonitor = function(pool_id, type, delay, timeout, max_retries, data, cb){ - var self = this; - var count = 0; - var done = false; - var optional_keys = ['name', 'max_retries_down', 'http_method', 'url_path', 'expected_codes', 'admin_state_up']; - var post_data = {healthmonitor: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //handle the required params - post_data.healthmonitor.pool_id = pool_id; - post_data.healthmonitor.type = type; - post_data.healthmonitor.delay = delay; - post_data.healthmonitor.timeout = timeout; - post_data.healthmonitor.max_retries = max_retries; - - - // now loop through all the optional ones - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - post_data.healthmonitor[key] = data[key]; - } - } - - //and now we can get the full request options object add the log path and make the request - request_options = this.getRequestOptions('/lbaas/healthmonitors', post_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.healthmonitors.create'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitor'; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.post(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.healthmonitor); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - - -Octavia.prototype.updateLBHealthMonitor = function(health_monitor_id, data, cb){ - var self = this; - var count = 0; - var done = false; - var optional_keys = ['delay', 'timeout', 'max_retries', 'max_retries_down', 'http_method', 'url_path', 'expected_codes', 'admin_state_up']; - var put_data = {healthmonitor: {}}; - var key = ''; - var n = 0; - var request_options = {}; - - //loop through all the optional data keys and add them to the post data - for(n = 0; n < optional_keys.length; n++) - { - key = optional_keys[n]; - if(typeof data[key] != 'undefined') - { - put_data.healthmonitor[key] = data[key]; - } - } - - request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, put_data); - request_options.metricPath = 'remote-calls.octavia.lbaas.healthmonitors.update'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'healthmonitor'; - - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.put(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else one way or another we are done - done = true; - - //now handle error and success - if(error) - { - cb(error); - return; - } - //else success! - - cb(null, body.healthmonitor); - }); - }, - function(error, result){ - cb(error, result); - } - ); -}; - - - -//calls back with (error) after attempting to remove the given resource -Octavia.prototype.removeLBHealthMonitor = function(health_monitor_id, cb){ - var self = this; - var count = 0; - var done = false; - var request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true); - request_options.metricPath = 'remote-calls.octavia.lbaas.healthmonitors.remove'; - request_options.validateStatus = true; - - //async to allow for retry logic - Async.until( - function(){return done}, - function(cb){ - count++; - Request.del(request_options, function(error, response, body){ - if(error && error.detail.remoteStatusCode == 409 && count <= self.retries) - { - //wait a second then call back to trigger another try and ignore this error - setTimeout(cb, self.retry_delay); - return; - } - //else we are done one way or another - - done = true; - cb(error); - }); - }, - function(error){ - cb(error); - } - ); -}; - - - -// -------------------------------------------------- // -// ---------------------- Stats --------------------- // -// -------------------------------------------------- // -//NOTE: This is just here for experimentation - not really supporting/supported yet -//Leaving it here though as it may be of use to those who do have it available -Octavia.prototype.getLBStats = function(lb_id, cb){ - var request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id + '/stats', true); - request_options.metricPath = 'remote-calls.octavia.lbaas.loadbalancers.stats.get'; - request_options.validateStatus = true; - request_options.requireBodyObject = 'stats'; - - Request.get(request_options, function(error, response, body){ - if(error) - { - cb(error); - return; - } - //else - - cb(null, body.stats); - }); -}; - -module.exports = Octavia; diff --git a/lib/os-request.js b/lib/os-request.js deleted file mode 100644 index f2ddd73..0000000 --- a/lib/os-request.js +++ /dev/null @@ -1,366 +0,0 @@ -//just a wrapper for the request object with some extra metrics stuff thrown on top -var Request = require('request'); - - -//given a deep object and a nested property string 'a.b.c.d' send back the value with a default of defaultValue -//basically lets avoid (if x && x.a && x.a.b && x.a.b.c) -function _getNestedPropValue(obj, nestedProperty, defaultValue) -{ - return nestedProperty.split('.').reduce(function(accum, currentProperty, index, arr) { - // check if it exists, if not, return the default value (aka accum) - if(obj && typeof obj[currentProperty] !== 'undefined' && obj[currentProperty] !== null) - { - // last one, return its value - if(index === arr.length - 1) - { - return obj[currentProperty]; - } - else - { - obj = obj[currentProperty]; - return accum; - } - } - else - { - return accum; - } - }, defaultValue); -} - - - -//given all the pieces of a remote request and the knowledge that an error occured -//this function returns a proper error object but with some extra props -//to use just pass in as much of this stuff as you have -//normally just used in gdrequest but can be used elswhere when raw request is needed (hence in util) -//return error is in following format: -//it will also return a true error object in the following format -//{ -// message: 'verbal description of what went wrong', -// stack: '[message]: stack track shown here', -// code: 'ALLCAPSCODE', -// detail: -// { -// remoteMethod: 'GET', -// remoteURI: 'http://odds.are.some.url/index.html', -// remoteStatusCode: 404 -// remoteMessage: 'verbal message parsed from remote response - should be a string', -// remoteCode: 'PARSEDFROMRESPONSE' -// remoteDetail: 'also parsed from remote response - should be a string', -// responseTime: 2.22 -// } -//} -function _getRequestError(error, response, body, request_options, response_time) -{ - var return_error = null; - var message = ''; - var code = 'REMOTEERROR'; - var detail = {}; - var remote_method = ''; - var remote_uri = ''; - var remote_status_code = 0; - var remote_message = ''; - var remote_code = ''; - var remote_detail = ''; - var key = ''; - - - //first the message and code for the actual error - should reflect what went wrong - //not what the remote api sent as a message/code (thats remote message and remote code) - if(error && error.message) - { - message = error.message; - } - else if(response && response.statusCode && (response.statusCode <= 199 || response.statusCode >= 300)) - { - message = 'Invalid status (' + response.statusCode + ') from remote call'; - } - else if(request_options && request_options.requireBodyObject && _getNestedPropValue(body, request_options.requireBodyObject, 'nope-nope-nope') == 'nope-nope-nope') - { - message = 'Invalid format (' + request_options.requireBodyObject + ') missing from remote call'; - } - else - { - message = 'Unknown error making remote call'; - } - - - //get the remote method from the data we have - if(response && response.request && response.request.method) - { - remote_method = response.request.method; - } - else if(request_options && request_options.method) - { - remote_method = request_options.method; - } - else - { - remote_method = 'indeterminable'; - } - - - //get the uri if possible - if(response && response.request && response.request.uri && response.request.uri.href) - { - remote_uri = response.request.uri.href; - } - else if(request_options && request_options.uri) - { - remote_uri = request_options.uri; - } - else if(request_options && (request_options.host || request_options.path)) - { - //its fine if one or more of these is blank/undefined - doing our best here is all - remote_uri = request_options.host + ':' + request_options.port + request_options.path; - } - else - { - remote_uri = 'indeterminable'; - } - - - //now the status that came from the response - if(response && response.statusCode) - { - remote_status_code = response.statusCode; - } - - - //now for the remote message - get whatever you can from wherever you can - if(body && body.message) - { - remote_message = body.message; - } - else if(body) - { - for(key in body) - { - //body.key check takes care of null which can't be hasOwnProperty'd apparently - if(body.hasOwnProperty(key) && body[key] && body[key].hasOwnProperty('message')) - { - remote_message = body[key].message; - } - } - } - //and as a last resort - if(body && !remote_message) - { - //toss a little of the body on there - limit this so we don't spew mountains of html to the logs - remote_message = JSON.stringify(body).substring(0, 150); - } - //else its just blank as theres no remote body at all - - - //look for an error code returned from the remote api - if(body && body.code) - { - remote_code = body.code; - } - else if(body) - { - for(key in body) - { - //body.key check takes care of null which can't be hasOwnProperty'd apparently - if(body.hasOwnProperty(key) && body[key] && body[key].hasOwnProperty('code')) - { - remote_code = body[key].code; - } - } - } - //else it can just be blank - - - //get remote details - if(body && body.detail) - { - remote_detail = body.detail; - } - else if(body) - { - for(key in body) - { - //body.key check takes care of null which can't be hasOwnProperty'd apparently - if(body.hasOwnProperty(key) && body[key] && body[key].hasOwnProperty('detail')) - { - remote_detail = body[key].detail; - } - } - } - //else it can just be blank - - - //now we can craft the detail prop for the error - detail.remoteMethod = remote_method; - detail.remoteURI = remote_uri; - detail.remoteStatusCode = remote_status_code - detail.remoteMessage = remote_message; - detail.remoteCode = remote_code; - detail.remoteDetail = remote_detail; - if(response_time) - { - detail.responseTime = response_time; - } - else - { - detail.responseTime = 0; - } - - - //now that we have all the things - construct the error (or use existing error) and return it - if(error) - { - return_error = error; - return_error.message = message;//could have changed - } - else - { - return_error = new Error(message); - } - return_error.code = code; - return_error.detail = detail; - - //console.log('returning error', return_error); - return return_error; -} - - - -//A 'private' function that does the actual request - here just to prevent me from duplicating code -//to use this class you should use the request or one of the helper functions below -//if a 'logPath' has been specified, a call is sent to the metrics system once the main call is complete to log the time -function _actualRequest(options, callback){ - var process_time = process.hrtime(); - - if(options.timeout) - { - options.timeout = parseInt(options.timeout); - } - else - { - options.timeout = 20000; - } - - - Request(options, function(error, response, body){ - //no matter the result we want to log this remote call - process_time = process.hrtime(process_time); - var process_time_in_seconds = process_time[0] + (process_time[1]/1e9); - var response_time = parseFloat(process_time_in_seconds.toFixed(3)); - var user_name = ''; //originating user - purely for logging - var request_id = ''; //originating request id - purely for logging - var metric_path = ''; //metric path to identify the specific call being made - var status_code = 0; - - //first handle debugging - if(options.debug) - { - console.log('request options:', options); - console.log('response body:', body); - if(response && response.statusCode) - { - console.log('response status: ', response.statusCode); - } - } - - //get all the things we will need for logging and error checking - if(response && response.statusCode) - { - status_code = response.statusCode; - } - - - //if a logger was a specified lets use that and dig out some info to log thats usually specified in the options - //unless a custom logger is specified though nothing will occur here - if(options.metricLogger) - { - if(options.metricUserName) - { - user_name = options.metricUserName; - } - if(options.metricRequestID) - { - request_id = options.metricRequestID; - } - if(options.metricPath) - { - metric_path = options.metricPath; - } - - options.metricLogger.logMetric({ - metricPath: metric_path, - requestVerb: options.method, - requestURL: options.uri, - statusCode: status_code, - responseTime: response_time, - userName: user_name, - requestID: request_id - }); - } - - - if(error) - { - //we got an error straight off the bat - add some extras to it and send back an error - error = _getRequestError(error, response, body, options, response_time) - } - else if((options.validateStatus || options.requireValidStatus) && (status_code <= 199 || status_code >= 300)) - { - //We have a response but not the status the options specified - send back an error - error = _getRequestError(error, response, body, options, response_time); - } - else if(options.requireBodyObject && _getNestedPropValue(body, options.requireBodyObject, 'nope-nope-nope') == 'nope-nope-nope') - { - //we have a response but not the format the options specified - send back an error - error = _getRequestError(error, response, body, options, response_time); - } - - callback(error, response, body); - }); -}; - - - - -//All functions should mimic functionality of the npm lib 'Request' -//we are adding 2 additional pieces of functionality based on extra 'options' properties -//1) options.validateStatus will return an error object if status is outside of 2xx range -//2) options.requireBodyObject will return an error object if the body doesn't contain the given json path/object - -//addtionally if replacing this lib with a custom version to enable logging you can expect the following -//3 options to always exist -- options.metricUserName, options.metricRequestID and options.metricPath -var request = { - get: function(options, callback){ - options.method = 'GET'; - _actualRequest(options, callback); - }, - - post: function(options, callback){ - options.method = 'POST'; - _actualRequest(options, callback); - }, - - patch: function(options, callback){ - options.method = 'PATCH'; - _actualRequest(options, callback); - }, - - put: function (options, callback){ - options.method = 'PUT'; - _actualRequest(options, callback); - }, - - del: function(options, callback){ - options.method = 'DELETE'; - _actualRequest(options, callback); - }, - - request: function(options, callback){ - //make the call with the method already set - _actualRequest(options, callback); - } -}; - - -module.exports = request; diff --git a/lib/os-utils.js b/lib/os-utils.js deleted file mode 100644 index 47ce986..0000000 --- a/lib/os-utils.js +++ /dev/null @@ -1,43 +0,0 @@ -//This is a helper lib/obj that contains some unility functions used throughout the various components - - -//getArgsWithCallback is to be used in overloaded functions to allow you to easily assign -//function variables when you don't know how many are actually passed in. Takes as input -//the highest number of arguments the function expects and the actual arguments used. -//the return value will be an array whose last element is the last element in the passed in -//arguments and whose length equals the passed in expected length based on the function signature -//I.E.: -// getArgsWithCallback(2, ["param1"]) -// will return [null, "param1"] - function getArgsWithCallback(expected_length, arg_obj) { - var return_args = []; - var i = 0; - var cb = null; - var arg_array = Array.prototype.slice.call(arg_obj); - - if(Array.isArray(arg_array)) - { - cb = arg_array.pop(); - - for(i=0; i < expected_length - 1; i++) - { - if(arg_array[i] == undefined) - { - arg_array[i] = null; - } - - return_args[i] = arg_array[i]; - } - - return_args[expected_length - 1] = cb; - - } - - return return_args; -} - - -module.exports = { - getArgsWithCallback: getArgsWithCallback -} - diff --git a/package.json b/package.json index e190a62..3158830 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,10 @@ { "name": "vincent99", "email": "vincent@rancher.com" + }, + { + "name": "taoqf", + "email": "tao_qiufeng@126.com" } ], "license": "MIT", @@ -37,16 +41,21 @@ "url": "https://github.com/godaddy/node-openstack-wrapper.git" }, "dependencies": { - "request": "~2", - "async": "~1" + "request": "~2" }, "devDependencies": { + "@types/request": "^2.48.1", "nodeunit": "~0.9", - "rewire": "~2.5" + "tslint": "^5.16.0", + "typescript": "^3.4.3" }, - "main": "./index.js", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "scripts": { - "test": "./node_modules/nodeunit/bin/nodeunit ./test" + "test": "nodeunit ./test", + "lint": "tslint --project ./tsconfig.json", + "build": "tsc", + "dev": "tsc -w" }, "gitHead": "ba2e0d6bdd001448d030f25daf2a7578fc1036d2", "_id": "openstack-wrapper@1.4.6", diff --git a/src/glance.ts b/src/glance.ts new file mode 100644 index 0000000..7ee6b09 --- /dev/null +++ b/src/glance.ts @@ -0,0 +1,212 @@ +import http from 'http'; +import https from 'https'; +import { Readable } from 'stream'; +import { parse } from 'url'; +import { IMetricLogger } from './os-request'; +import * as Request from './os-request'; +import { default_timeout } from './utils'; + +interface IImage { + // todo + todo: unknown; +} + +export default class Glance { + private url: string; + private token: string; + private timeout = default_timeout; + private request_id = ''; + private user_name = ''; + private logger = null as unknown as IMetricLogger; + private request = Request; + constructor(endpoint_url: string, auth_token: string) { + // endpoint_url should come from the keystone projectInfo call - also yank all the trailing slashes in case folks get clever + this.url = endpoint_url.replace(/\/$/, ''); + + // auth_token should be the scoped token from the projectInfo call + this.token = auth_token; + } + + public setRequest(request: typeof Request) { + this.request = request; + } + + // setters for individual obj/call usage + // just set these prior to doing things and your good to go until you want to change it + public setTimeout(new_timeout: number) { + this.timeout = new_timeout; + } + + public setRequestID(request_id: string) { + this.request_id = request_id; + } + + public setUserName(user_name: string) { + this.user_name = user_name; + } + + public setLogger(logger: IMetricLogger) { + this.logger = logger; + } + + + + // makes a callback cb(error, images_array) with a list of all of the available images for a given project/user + // NOTE: harding pagination for now - change at will (just be aware it will break backwards compat so update version accordingly) + public async listImages() { + const request_options = this.getRequestOptions('/images?member_status=all&limit=200', true, 'remote-calls.glance.images.list', 'images'); + + const body = await this.request.get<{ + images: IImage[]; + }>(request_options); + return body.images; + } + + // gets info on a specific image given the id + // takes an image id ex: '8ab808ed-d2aa-471c-9af0-0d3287061670' + // and callback with 2 params (error, image_info_object) + public getImage(id: string) { + const request_options = this.getRequestOptions('/images/' + escape(id), true, 'remote-calls.glance.images.get', 'id'); + + // todo + return this.request.get<{/* todo */ }>(request_options); + } + + // This might create a temporary id/placeholder for us to upload new images into + // ...or it may bring the end of times through dark titual.... probably 50/50 + // callback takes 2 params (error, data) where data seems to include the id of the result of queuing...er posting... er whatever + public queueImage(data: { + name?: string; + visibility?: boolean; + tags?: unknown[]; + disk_format?: string; + container_format?: string; + }) { + const request_options = this.getRequestOptions('/images', data, 'remote-calls.glance.images.queue', 'id'); + + // todo + return this.request.post<{/* todo */ }>(request_options); + } + + + + // uploads a new image to openstack + // takes the new image id(from the queue call above?) + // a stream object... don't really get that one (download result?) + // and a callback w/2 params (error, response) I think response here is the result of the upload call + public uploadImage(id: string, stream: Readable) { + return new Promise((resolve, reject) => { + const url = this.url + '/images/' + escape(id) + '/file'; + const opt = parse(url); // sadly I didn't get this working with the request object.... yet! + const h = (() => { + if (opt.protocol === 'https:') { + return https; + } else { + return http; + } + })(); + + const upload = h.request({ + ...opt, + headers: { + Connection: 'close', + 'Content-Type': 'application/octet-stream', + 'X-Auth-Token': this.token + }, + method: 'PUT' + }, (res) => { + let response = ''; + + res.on('data', (chunk) => { + response += chunk; + }); + + res.on('end', () => { + resolve(response); + }); + }); + + upload.on('error', (e) => { + reject(e); + }); + + stream.pipe(upload); + }); + } + + // calls back with (error, image) after updating the data on an image + // data should be an object with only the deltas to be tweaked - the following are supposed + /* + data.name + data.visibility + data.protected + data.tags + */ + public updateImage(id: string, data: { + name?: string; + visibility?: boolean; // ?? todo string + protected?: boolean; + tags: unknown[]; // todo: + }) { + const patch_data = []; + + if (data.name) { + patch_data.push({ op: 'replace', path: '/name', value: data.name }); + } + if (data.visibility) { + patch_data.push({ op: 'replace', path: '/visibility', value: data.visibility }); + } + // data.protected is a boolean so the normal if(thing) mechanism won't work - hence typeof + if (typeof data.protected !== 'undefined') { + patch_data.push({ op: 'replace', path: '/protected', value: !!data.protected }); + } + if (data.tags) { + patch_data.push({ op: 'replace', path: '/tags', value: data.tags }); + } + + // we have an additional header here due to the patch command + const request_options = this.getRequestOptions('/images/' + escape(id), patch_data, 'remote-calls.glance.images.update', 'id', { + 'Content-Type': 'application/openstack-images-v2.1-json-patch' + }); + + return this.request.patch(request_options); + } + + + + // calls back with (error) after attempting to remove an openstack image + public removeImage(id: string) { + const request_options = this.getRequestOptions('/images/' + escape(id), true, 'remote-calls.glance.images.remove', ''); + + return this.request.del(request_options); + } + + // returns an formatted options object - just makes the code below a little less repetitious + // path should begin with a "/" + // json_value should be almost certainly be true if you don't have an actual object you want to send over + private getRequestOptions(path: string, json_value: unknown, metricPath: string, requireBodyObject: string, extra_headers?: { [key: string]: string; }) { + const options = { + headers: { 'X-Auth-Token': this.token } as { [key: string]: string; }, + json: json_value, + metricLogger: this.logger, + metricPath, + metricRequestID: this.request_id, + metricUserName: this.user_name, + requireBodyObject, + timeout: this.timeout, + uri: this.url + path, + validateStatus: true + }; + + // add the extra header info if it exists + if (typeof extra_headers !== 'undefined') { + for (const key in extra_headers) { + if (extra_headers.hasOwnProperty(key)) { + options.headers[key] = extra_headers[key]; + } + } + } + + return options; + } +} diff --git a/src/heat.ts b/src/heat.ts new file mode 100644 index 0000000..55964b3 --- /dev/null +++ b/src/heat.ts @@ -0,0 +1,173 @@ +import { IMetricLogger } from './os-request'; +import * as Request from './os-request'; +import { default_timeout } from './utils'; + +// Class to handle all Heat methdology +// NOTE: This class was created after v2.1.10 +// and so mangling is no longer supported or required to be programmed in below + +interface IStack { + // todo + todo: unknown; +} + +export default class Heat { + private url: string; + private token: string; + private timeout = default_timeout; + private request_id = ''; + private user_name = ''; + private logger = null as unknown as IMetricLogger; + private request = Request; + constructor(endpoint_url: string, auth_token: string) { + // endpoint_url should come from the keystone projectInfo call - also yank all the trailing slashes in case folks get clever + this.url = endpoint_url.replace(/\/$/, ''); + + // auth_token should be the scoped token from the projectInfo call + this.token = auth_token; + } + + public setRequest(request: typeof Request) { + this.request = request; + } + + // setters for individual obj/call usage + // just set these prior to doing things and your good to go until you want to change it + public setTimeout(new_timeout: number) { + this.timeout = new_timeout; + } + + public setRequestID(request_id: string) { + this.request_id = request_id; + } + + public setUserName(user_name: string) { + this.user_name = user_name; + } + + public setLogger(logger: IMetricLogger) { + this.logger = logger; + } + + // gets a list of all stacks for the given project/tenant + // calls back with cb(error, stack_array) + // the options object can be a blank obj {} or used to specify filters using key/values, e.g.: + // { + // id: string, + // status: string, + // name: string, + // action: string, + // tenant: string, + // username: string, + // owner_id: string + // } + public async listStacks(options: unknown) { + const request_options = this.getRequestOptions('/stacks', true, 'remote-calls.heat.stacks.list'); + + const body = await this.request.get<{ + stacks: IStack[]; + }>({ + ...request_options, + qs: options, + requireBodyObject: 'stacks' + }); + return body.stacks; + } + + // show output of a stack for the given key name + // calls back with cb(error, output_object) + public async showStackOutput(name: string, id: string, outputKey: string) { + const request_options = this.getRequestOptions('/stacks/' + escape(name) + '/' + escape(id) + '/outputs/' + escape(outputKey), true, 'remote-calls.heat.stack.showStackOutput'); + + const body = await this.request.get<{ + output: string; + }>(request_options); + + return body.output; + } + + // creates a stack with the given name + // calls back with cb(error, stack_object) + // options: + // { + // disable_rollback: boolean, + // environment: object, + // files: object, + // parameters: object, + // tags: string, + // template: object, + // template_url: string, + // timeout_mins: number + // } + // note: either template or template_url must be defined + // todo @param name is not used + public async createStack(options: { + disable_rollback: boolean; + environment: unknown; + files: unknown; + parameters: unknown; + tags: string; + template: unknown; + template_url: string; + timeout_mins: number; + }) { + const request_options = this.getRequestOptions('/stacks', options, 'remote-calls.heat.stacks.create'); + + const body = await this.request.post<{ + stack: string; + }>({ + ...request_options, + requireBodyObject: 'stack' + }); + + return body.stack; + } + + // updates the stack with the given name and id, using HTTP PATCH + // calls back with cb(error, stack_object) + // options: + // { + // clear_parameters: array, + // disable_rollback: boolean, + // environment: object, + // environment_files: object, + // files: object, + // parameters: object, + // tags: string, + // template: object, + // template_url: string, + // timeout_mins: number, + // converge: boolean + // } + // note: either template or template_url must be defined + public updateStack(name: string, id: string, options: unknown) { + const request_options = this.getRequestOptions('/stacks/' + escape(name) + '/' + escape(id), options, 'remote-calls.heat.stacks.update'); + + return this.request.patch(request_options); + } + + // deletes the stack with the given name and id + public deleteStack(name: string, id: string) { + const request_options = this.getRequestOptions('/stacks/' + escape(name) + '/' + escape(id), true, 'remote-calls.heat.stack.delete'); + + return this.request.del(request_options); + } + + // returns an formatted options object - just makes the code below a little less repetitious + // path should begin with a "/" + // json_value should be almost certainly be true if you don't have an actual object you want to send over + private getRequestOptions(path: string, json_value: unknown, metricPath: string) { + const return_object = { + headers: { 'X-Auth-Token': this.token } as { [key: string]: string; }, + json: json_value, + metricLogger: this.logger, + metricPath, + metricRequestID: this.request_id, + metricUserName: this.user_name, + timeout: this.timeout, + uri: this.url + path, + validateStatus: true + }; + return return_object; + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..625252e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,74 @@ +import Glance from './glance'; +import Heat from './heat'; +import Keystone from './keystone'; +import Neutron from './neutron'; +import Nova from './nova'; +import Octavia from './octavia'; + +// A convenience method for quick/dirty work for those that already have a project_id +// calls back with (error, project) where project already has all the individual objects setup +// ie: project.nova, project.glance, etc.. +async function getSimpleProject(username: string, password: string, project_id: string, keystone_url: string) { + const keystone = new Keystone(keystone_url); + + const token = await keystone.getToken(username, password); + + const project_token = await keystone.getProjectToken(token.token, project_id); + const catalog_array = project_token.catalog; + let glance_url = ''; + let heat_url = ''; + let neutron_url = ''; + let octavia_url = ''; + let nova_url = ''; + for (let n = 0; n < catalog_array.length; n++) { + // ELS Puppet sometimes screws up Keystone and puts in duplicate service entries + // that have no endpoints.. ignore these. + if (!catalog_array[n].endpoints || !catalog_array[n].endpoints.length) { + continue; + } + + const endpoints_array = catalog_array[n].endpoints; + const endpoint_type = catalog_array[n].type; + + for (let j = 0; j < endpoints_array.length; j++) { + if (endpoints_array[j].interface === 'public') { + endpoints_array[j].url = endpoints_array[j].url.replace(/\/$/, '');// yank any trailing /'s, + + if (endpoint_type === 'image') { + // we have to add the v2 to the end to get the most current functionality + glance_url = endpoints_array[j].url + '/v2.0'; + } else if (endpoint_type === 'network') { + // we have to add the v2 to the end to get the most current functionality + neutron_url = endpoints_array[j].url + '/v2.0'; + } else if (endpoint_type === 'compute') { + nova_url = endpoints_array[j].url; + } else if (endpoint_type === 'load-balancer') { + octavia_url = endpoints_array[j].url; + } else if (endpoint_type === 'orchestration') { + heat_url = endpoints_array[j].url; + } + break; + } + } + } + + return { + general_token: token, + glance: new Glance(glance_url, project_token.token), + heat: new Heat(heat_url, project_token.token), + neutron: new Neutron(neutron_url, project_token.token), + nova: new Nova(nova_url, project_token.token), + octavia: new Octavia(octavia_url, project_token.token), + project_token + }; +} + +export default { + Glance, + Heat, + Keystone, + Neutron, + Nova, + Octavia, + getSimpleProject +}; diff --git a/src/keystone.ts b/src/keystone.ts new file mode 100644 index 0000000..9244f65 --- /dev/null +++ b/src/keystone.ts @@ -0,0 +1,503 @@ +import { IMetricLogger } from './os-request'; +import * as Request from './os-request'; +import { default_timeout } from './utils'; + +interface IAuthData { + auth: { + identity: { + methods: ['token']; + token: { id: string; }; + }; + scope: { + project: { + id?: string; + domain?: { id: string; }; + name?: string; + }; + }; + }; +} + +interface ILinks { + self?: string; + previous?: string; + next?: string; +} + +export interface IProject { + domain: { + id: string; + name: string; + }; + id: string; + name: string; +} + +export interface IRole { + id: string; + name: string; +} + +interface IRoleAssignment { + // todo + todo: unknown; +} + +interface IRegion { + parent_region_id: string; + id: string; + links: ILinks[]; + description: string; +} + +interface IEnvironment { + // todo + todo: unknown; +} + +interface IOwningGroup { + // todo + todo: unknown; +} + +interface IMeta { + // todo + todo: unknown; +} + +interface IEndPoint { + url: string; + interface: string; + region: string; + region_id: string; + id: string; +} + +export interface ICatalog { + endpoints: IEndPoint[]; + type: string; + id: string; + name: string; +} + +export interface IUser { + password_expires_at: string; + domain: { + id: string; + name: string; + }; + id: string; + name: string; +} + +type ArrayWithLinks = T[] & ILinks; + +export default class Keystone { + private url: string; + private timeout = default_timeout; + private request_id = ''; + private user_name = ''; + // logger should default to null - might consider checking for a logMetric function in that obj too? + private logger = null as unknown as IMetricLogger; + private request = Request; + constructor(endpoint_url: string) { + + // Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes + this.url = endpoint_url.replace(/\/$/, ''); + } + + public setRequest(request: typeof Request) { + this.request = request; + } + + // setters for individual obj/call usage + // just set these prior to doing things and your good to go until you want to change it + public setTimeout(new_timeout: number) { + if (new_timeout > 0) { + this.timeout = new_timeout; + } else { + this.timeout = default_timeout; + } + return this.timeout; + } + + public setRequestID(request_id: string) { + this.request_id = request_id; + } + + public setUserName(user_name: string) { + this.user_name = user_name; + } + + public setLogger(logger: IMetricLogger) { + this.logger = logger; + } + + // authorizes the users against the specified keystone + // can be called with 3 or 4 params (domain is optional, cb is not) + // calls back with (error, token) where token is an object containing all the token info + // NOTE: the actual token value normally comes back in the header - i'm modifying this to token.token for easier consumption + public async getToken(username: string, password: string, domain = 'Default') { + const auth_data = { + auth: { + identity: { + methods: ['password'], + password: { user: { domain: { name: domain }, name: username, password } } + } + } + }; + const request_options = this.getRequestOptions('bogus', '/auth/tokens', auth_data, 'remote-calls.keystone.tokens.get', 'token'); + request_options.headers = {}; // we don't want the normal auth header due to bogus token + + // auth-token will come back in the header for some reason as x-subject-token (used to come back in the body all nice like) + const { body, res } = await this.request.request<{ + token: { + token: string + audit_ids: string[]; + methods: string[]; + expires_at: string; + user: IUser; + }; + }>({ + ...request_options, + method: 'POST' + }); + + // tiny hack here to put the actual token string back into the object + body.token.token = res.headers['x-subject-token'] as string; + + // now we good + return body.token; + } + + // make a callback(error, project_authorization) with all of the data on a project and an access token for further calls on it + // NOTE: this is not the admin function that gets project details - you have to do this so I'm not bothering with that + public getProjectToken(access_token: string, project_id: string) { + return this.getProjectTokenForReal({ + auth: { + identity: { + methods: ['token'], + token: { id: access_token } + }, + scope: { + project: { id: project_id } + } + } + }); + } + + public getProjectTokenById(access_token: string, project_id: string) { + return this.getProjectToken(access_token, project_id); + } + + // make a callback(error, project_authorization) with all of the data on a project and an access token for further calls on it + // NOTE: this is not the admin function that gets project details - you have to do this so I'm not bothering with that + public getProjectTokenByName(access_token: string, project_name: string, domain_id = 'default') { + return this.getProjectTokenForReal({ + auth: { + identity: { + methods: ['token'], + token: { id: access_token } + }, + scope: { + project: { + domain: { id: domain_id }, + name: project_name + } + } + } + }); + } + + // gets a list of all projects in the system + // calls back with cb(error, project_array) + // ***NOTE: admin_access_token is a scoped token from a project you have admin rights on - yes this is weird + public async listProjects(admin_access_token: string) { + const request_options = this.getRequestOptions(admin_access_token, '/projects', true, 'remote-calls.keystone.projects.list', 'projects'); + + const body = await this.request.get<{ + projects: IProject[]; + links: ILinks; + }>(request_options); + + const projects_array = [] as ArrayWithLinks; + + for (let n = 0; n < body.projects.length; n++) { + projects_array[n] = body.projects[n]; + } + + // tack these on for easy consupmtion and in case we ever need pagination + projects_array.self = body.links.self; + projects_array.previous = body.links.previous; + projects_array.next = body.links.next; + + return projects_array; + } + + // gets a list of projects the given token is authorized to have some access to + // calls back with (error, projects_array) and self, previous, and null are tacked on as properties of the array + public async listUserProjects(username: string, access_token: string) { + const request_options = this.getRequestOptions(access_token, '/users/' + username + '/projects', true, 'remote-calls.keystone.projects.list-user', 'projects'); + + const body = await this.request.get<{ + projects: IProject[]; + links: ILinks; + }>(request_options); + + const projects_array = [] as ArrayWithLinks; + + for (let n = 0; n < body.projects.length; n++) { + projects_array[n] = body.projects[n]; + } + + // tack these on for easy consupmtion and in case we ever need pagination + projects_array.self = body.links.self; + projects_array.previous = body.links.previous; + projects_array.next = body.links.next; + return projects_array; + } + + // gets the details of a specific project by name + // calls back with cb(error, project_array) + // ***NOTE: admin_access_token is a scoped token from a project you have admin rights on - yes this is weird + // ***NOTE: this will return an error if 2 projects are named the same - not usable unless distinct projects are configured/required. + public async getProjectByName(admin_access_token: string, project_name: string) { + const request_options = this.getRequestOptions(admin_access_token, '/projects?name=' + project_name, true, 'remote-calls.keystone.projects.get-by-name', 'projects'); + + const body = await this.request.get<{ + projects: IProject[]; + }>(request_options); + + const project_object = {} as IProject; + + if (body.projects.length > 1) { + // kind of an error... in theory + throw new Error('Found multiple projects with same name'); + } + // else + + if (body.projects.length === 0) { + // not an error but no data either + return project_object; + } + // else + + // we are good + return body.projects[0]; + } + + + // gets a list of roles for the given project (specified by token ...kinda weird) + // calls back with (error, roles_array) and self, previous, and null are tacked on as properties of the array + // NOTE: this needs a project token scoped in our system - this may vary depending on how the security is setup + public async listRoles(project_token: string) { + const request_options = this.getRequestOptions(project_token, '/roles', true, 'remote-calls.keystone.roles.get', 'roles'); + + const body = await this.request.get<{ + roles: IRole[]; + links: ILinks; + }>(request_options); + + // console.log('roles', body); + let n = 0; + const roles_array = [] as ArrayWithLinks; + + // else + + for (n = 0; n < body.roles.length; n++) { + roles_array[n] = body.roles[n]; + } + + // tack these on for easy consupmtion and in case we ever need pagination + roles_array.self = body.links.self; + roles_array.previous = body.links.previous; + roles_array.next = body.links.next; + + return roles_array; + } + + // make a callback(error, assignments_array) with all of the role assignments for a project + // NOTE: this is only works if the user is authed as an admin or projectAdmin + public async listRoleAssignments(project_token: string, project_id: string) { + const request_options = this.getRequestOptions(project_token, '/role_assignments?scope.project.id=' + project_id, true, 'remote-calls.keystone.role-assigments.list', 'role_assignments'); + + const body = await this.request.get<{ + role_assignments: IRoleAssignment[]; + links: ILinks; + }>(request_options); + + const assignments_array = [] as ArrayWithLinks; + let n = 0; + + for (n = 0; n < body.role_assignments.length; n++) { + assignments_array[n] = body.role_assignments[n]; + } + + // tack these on for easy consupmtion and in case we ever need pagination + assignments_array.self = body.links.self; + assignments_array.previous = body.links.previous; + assignments_array.next = body.links.next; + + return assignments_array; + } + + + // make a callback(error) after adding a specific role assignment to a project (either a user or a group) + // NOTE: this is only works if the user is authed as an admin or projectAdmin + public addRoleAssignment(project_token: string, project_id: string, entry_id: string, entry_type: 'group' | 'users', role_id: string) { + let entry_type_path = 'users'; + + if (entry_type === 'group') { + entry_type_path = 'groups'; + } + const request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/' + entry_type_path + '/' + entry_id + '/roles/' + role_id, true, 'remote-calls.keystone.role-assignments.add'); + + + // the body comes back as undefined instead of containing the new role assingment - lame + return this.request.put(request_options); + } + + + // make a callback(error) after removing a specific role assignments on a project(either a user or a group) + // NOTE: this is only works if the user is authed as an admin or projectAdmin + public removeRoleAssignment(project_token: string, project_id: string, entry_id: string, entry_type: string, role_id: string) { + let entry_type_path = 'users'; + + if (entry_type === 'group') { + entry_type_path = 'groups'; + } + + const request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/' + entry_type_path + '/' + entry_id + '/roles/' + role_id, true, 'remote-calls.keystone.role-assignments.remove'); + + return this.request.del(request_options); + } + + // gets a list of all regions in the system + // calls back with cb(error, region_array) + public async listRegions(access_token: string) { + const request_options = this.getRequestOptions(access_token, '/regions', true, 'remote-calls.keystone.regions.list', 'regions'); + + const body = await this.request.get<{ + regions: IRegion[]; + links: ILinks; + }>(request_options); + // No mangling + // You should handle input and output mangling outside of this lib going forward + const regions_array = body.regions as ArrayWithLinks; + + // tack these on for easy consupmtion and in case we ever need pagination + regions_array.self = body.links.self; + regions_array.previous = body.links.previous; + regions_array.next = body.links.next; + + return regions_array; + } + + // THE FOLLOWING ARE ONLY USEFUL WITHIN GODADDY (and are prioprietary functions until/if the project meta data work is adopted) + // THUS THEY AREN"T DOCUMENTED + // -------------------------------------------------------------------------- + // make a callback(error) after retrieving all of the possible environments for the project/server meta data + // calls back with cb(error, environments_array) + public async listMetaEnvironments(auth_token: string) { + const request_options = this.getRequestOptions(auth_token, '/meta_values/environment', true, 'remote-calls.keystone.meta-environments.get', 'environments'); + + const body = await this.request.get<{ + environments: IEnvironment[]; + }>(request_options); + + return body.environments; + } + + // make a callback(error) after retrieving all of the possible ownsers for the project/server meta data + // calls back with cb(error, owning_groups_array) + public async listMetaOwningGroups(auth_token: string) { + const request_options = this.getRequestOptions(auth_token, '/meta_values/owning_group', true, 'remote-calls.keystone.meta-owninggroups.get', 'owning_groups'); + + const body = await this.request.get<{ + owning_groups: IOwningGroup[]; + }>(request_options); + + return body.owning_groups; + } + + // make a callback(error) after listing all of the project meta data + // calls back with cb(error, meta_object) + public async listProjectMeta(project_token: string, project_id: string) { + const request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/meta', true, 'remote-calls.keystone.projects.meta.get', 'meta'); + + const body = await this.request.get<{ + meta: IMeta; + }>(request_options); + + return body.meta; + } + + // make a callback(error) after updating the project meta data + // meta_data should be an object with key-value pairs ie: {environment: 'dev', group: 'marketing'} + // calls back with cb(error, meta_object) + public async updateProjectMeta(project_token: string, project_id: string, new_meta: string) { + const meta_data = { meta: new_meta }; + + const request_options = this.getRequestOptions(project_token, '/projects/' + project_id + '/meta', meta_data, 'remote-calls.keystone.projects.meta.update', 'meta'); + const body = await this.request.put<{ + meta: IMeta; + }>(request_options); + + return body.meta; + } + + // make a callback(error, project_authorization) with all of the data on a project and an access token for further calls on it + // NOTE: this is not the admin function that gets project details - you have to do this so I'm not bothering with that + private async getProjectTokenForReal(auth_data: IAuthData) { + // use the normal getRequestOptions but send in a bogus token and nullfiy the header + // the token will get passed in the data in this call + const request_options = this.getRequestOptions('bogus', '/auth/tokens', auth_data, 'remote-calls.keystone.tokens.get-project', 'token'); + + const { + body, + res + } = await this.request.request<{ + token: { + token: string; + is_domain: boolean, + methods: string[]; + roles: + IRole[]; + expires_at: string; + project: IProject; + catalog: ICatalog[], + user: IUser; + audit_ids: string[]; + issued_at: string; + }; + }>({ + ...request_options, + method: 'POST' + }); + + // hack to put the actual token value back into the body + body.token.token = res.headers['x-subject-token'] as string; + return body.token; + } + + // returns an formatted options object - just makes the code below a little less repetitious + // auth_token can be either a generic or project scoped token depending what your doing + // json_value should be almost certainly be true if you don't have an actual object you want to send over + // NOTE: because keystone is non-project specific this function is different than all the other classes with it + private getRequestOptions(auth_token: string, path: string, json_value: unknown, metricPath: string, requireBodyObject?: string) { + const return_object = { + headers: { 'X-Auth-Token': auth_token } as { [key: string]: string; }, + json: json_value, + metricLogger: this.logger, + metricPath, + metricRequestID: this.request_id, + metricUserName: this.user_name, + requireBodyObject, + timeout: this.timeout, + uri: this.url + path, + validateStatus: true + }; + + return return_object; + } +} diff --git a/src/neutron.ts b/src/neutron.ts new file mode 100644 index 0000000..5671c48 --- /dev/null +++ b/src/neutron.ts @@ -0,0 +1,859 @@ +import { IMetricLogger } from './os-request'; +import * as Request from './os-request'; +import { assign, default_timeout, IUnknowObject } from './utils'; + +interface INetwork { + // todo + todo: unknown; +} + +interface ISubnet { + // todo + todo: unknown; +} + +interface IRouter { + // todo + todo: unknown; +} + +interface IFloatingIp { + // todo + todo: unknown; +} + +interface IFilter { + // todo + todo: unknown; +} + +interface IPort { + // todo + todo: unknown; +} + +interface ISecurityGroup { + // todo + todo: unknown; +} + +interface ISecurityGroupRule { + // todo + todo: unknown; +} + +interface ILoadBalancer { + // todo + todo: unknown; +} + +interface IListener { + name: string; + description: string; + admin_state_up: string; + connection_limit: string; + default_tls_container_ref: string; + sni_container_refs: string; +} + +interface IPool { + // todo + todo: unknown; +} + +interface IPoolMember { + // todo + todo: unknown; +} + +interface IHealthMonitor { + // todo + todo: unknown; +} + +interface IStat { + // todo + todo: unknown; +} + +export default class Neutron { + private url: string; + private token: string; + private timeout = default_timeout; + private request_id = ''; + private user_name = ''; + private logger = null as unknown as IMetricLogger; + private request = Request; + constructor(endpoint_url: string, auth_token: string) { + + // Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes + this.url = endpoint_url.replace(/\/$/, ''); + + // auth_token should be the scoped token from the projectInfo call + this.token = auth_token; + } + + public setRequest(request: typeof Request) { + this.request = request; + } + + // setters for individual obj/call usage + // just set these prior to doing things and your good to go until you want to change it + public setTimeout(new_timeout: number) { + this.timeout = new_timeout; + } + + public setRequestID(request_id: string) { + this.request_id = request_id; + } + + public setUserName(user_name: string) { + this.user_name = user_name; + } + + public setLogger(logger: IMetricLogger) { + this.logger = logger; + } + + // gets a list of all networks for the given project/tenant + // calls back with cb(error, network_array) + public async listNetworks() { + const request_options = this.getRequestOptions('/networks', true, 'remote-calls.neutron.networks.list', 'networks'); + // request_options.debug = true; + + const body = await this.request.get<{ + networks: INetwork[]; + }>(request_options); + + // can't tell at this point if an empty result would come back with a blank array or just no ports at all so... + if (body.networks && body.networks.length) { + return body.networks; + } else { + // leave an empty array as the result and log an issue.... that might not be an issue... or might be... + console.error('No networks found for this project - returning blank array'); + return []; + } + } + + // gets a network by id (within the current project/tenant) + // calls back with cb(error, network_obj) + public async getNetwork(network_id: string) { + const request_options = this.getRequestOptions('/networks/' + network_id, true, 'remote-calls.neutron.networks.get', 'network'); + + const body = await this.request.get<{ + network: INetwork; + }>(request_options); + return body.network; + } + + // gets a list of all networks for the given project/tenant + // calls back with cb(error, network_array) + public async listSubnets() { + const request_options = this.getRequestOptions('/subnets', true, 'remote-calls.neutron.subnets.list', 'subnets'); + + const body = await this.request.get<{ + subnets: ISubnet[]; + }>(request_options); + + // can't tell at this point if an empty result would come back with a blank array or just no ports at all so... + if (body.subnets && body.subnets.length) { + return body.subnets; + } else { + // leave an empty array as the result and log an issue.... that might not be an issue... or might be... + console.error('No subnets found for this project - returning blank array'); + return []; + } + } + + // gets a subnet by id (within the current project/tenant) + // calls back with cb(error, subnet_obj) + public async getSubnet(subnet_id: string) { + const request_options = this.getRequestOptions('/subnets/' + subnet_id, true, 'remote-calls.neutron.subnets.get', 'subnet'); + + const body = await this.request.get<{ + subnet: ISubnet; + }>(request_options); + return body.subnet; + } + + // gets a list of all routers for the given project/tenant + // calls back with cb(error, router_array) + public async listRouters() { + const request_options = this.getRequestOptions('/routers', true, 'remote-calls.neutron.routers.list', 'routers'); + + const body = await this.request.get<{ + routers: IRouter[]; + }>(request_options); + if (body.routers && body.routers.length) { + return body.routers; + } else { + // leave an empty array as the result and log an issue.... that might not be an issue... or might be... + console.error('No routers found for this project - returning blank array'); + return []; + } + } + + // gets a specific router by id + // calls back with cb(error, router_obj) + public async getRouter(router_id: string) { + const request_options = this.getRequestOptions('/routers/' + router_id, true, 'remote-calls.neutron.routers.get', 'router'); + + const body = await this.request.get<{ + router: IRouter; + }>(request_options); + return body.router; + } + + // ------------------------FLOATING IPS------------------------------ + // Creates(allocates) a new floating ip from a given ip pool(floating_network_id) + // calls back with cb(error, obj) + public async createFloatingIp(floating_network_id: string) { + const request_options = this.getRequestOptions('/floatingips', { floatingip: { floating_network_id } }, 'remote-calls.neutron.floating-ips.create', 'floatingip'); + + const body = await this.request.post<{ + floatingip: IFloatingIp; + }>(request_options); + return body.floatingip; + } + + // gets a list of all floating ip's for the given project/tenant + // calls back with cb(error, ip_array) + // takes optional object that contains any filters to apply to request + // i.e. + // { + // filters: + // { + // 'device_id': 'abcdef123567' + // } + // } + public async listFloatingIps(options: { + filters: IFilter[]; + }) { + const request_options = this.getRequestOptions('/floatingips', true, 'remote-calls.neutron.floating-ips.list', 'floatingips'); + // get the actual args passed in as this function can be overloaded + + const body = await this.request.get<{ + floatingips: IFloatingIp[]; + }>({ + ...request_options, + qs: options.filters + }); + + // can't tell at this point if an empty result would come back with a blank array or just no ports at all so... + if (body.floatingips && body.floatingips.length) { + return body.floatingips; + } else { + // leave an empty array as the result and log an issue.... that might not be an issue... or might be... + console.error('No floating ips found for given project - returning blank array'); + return []; + } + } + + // gets a specific floating ip by id + // calls back with cb(error, ip_obj) + public async getFloatingIp(ip_id: string) { + const request_options = this.getRequestOptions('/floatingips/' + ip_id, true, 'remote-calls.neutron.floating-ips.get', 'floatingip'); + + const body = await this.request.get<{ + floatingip: IFloatingIp; + }>(request_options); + return body.floatingip; + } + + // updates the port_id on a floating ip (its the only thing we can update) + // calls back with cb(error, ip_obj) + public async updateFloatingIp(ip_id: string, port_id: string) { + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/floatingips/' + ip_id, { floatingip: { port_id } }, 'remote-calls.neutron.floating-ips.update', 'floatingip'); + + const body = await this.request.put<{ + floatingip: IFloatingIp; + }>(request_options); + return body.floatingip; + } + + // removes a floating ip by id + // calls back with cb(error) + public removeFloatingIp(ip_id: string) { + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/floatingips/' + ip_id, undefined, 'remote-calls.neutron.floating-ips.remove', ''); + + return this.request.del(request_options); + } + + // calls back with (error, ports) for the tenant/project of the current token + // takes optional object that contains any filters to apply to request + // i.e. + // { + // filters: + // { + // 'device_id': 'abcdef123567' + // } + // } + public async listPorts(options: { + filters: IFilter[]; + }) { + const request_options = this.getRequestOptions('/ports', true, 'remote-calls.neutron.ports.list', 'ports'); + // get the actual args passed in as this function can be overloaded + + const body = await this.request.get<{ + ports: IPort[]; + }>({ + ...request_options, + qs: options.filters + }); + // can't tell at this point if an empty result would come back with a blank array or just no ports at all so... + if (body.ports && body.ports.length) { + return body.ports; + } else { + // leave an empty array as the result and log an issue.... that might not be an issue... or might be... + console.error('No Ports group found for given project - returning blank array'); + return []; + } + } + + // gets the port with the specified id + public async getPort(port_id: string) { + const request_options = this.getRequestOptions('/ports/' + port_id, true, 'remote-calls.neutron.ports.get', 'port'); + + const body = await this.request.get<{ + port: IPort; + }>(request_options); + + return body.port; + } + + // updates the data on a specified port then calls back with (error, port) + // NOTE: the network_id is not optional according to the docs but I think it is... + public async updatePort(port_id: string, data: IUnknowObject) { + const optional_keys = ['status', 'name', 'admin_state_up', 'tenant_id', 'mac_address', 'fixed_ips', 'security_groups', 'network_id', 'allowed_address_pairs']; + const put_data = { port: {} }; + // we may have 1 required param + // put_data.port.network_id = network_id; + + // now loop through all the optional ones + assign(put_data.port, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/ports/' + port_id, put_data, 'remote-calls.neutron.ports.update', 'port'); + + const body = await this.request.put<{ port: IPort; }>(request_options); + return body.port; + } + + // calls back with (error, security_groups) for the given tenant/project + // NOTE: the ?tenant_id= thing is undocumented + // it forces us to get back permissions only to the given project (as opposed ot the whole company) + public async listSecurityGroups(project_id: string) { + const request_options = this.getRequestOptions('/security-groups' + '?tenant_id=' + escape(project_id), true, 'remote-calls.neutron.security-groups.list', 'security_groups'); + + const body = await this.request.get<{ + security_groups: ISecurityGroup[]; + }>(request_options); + // can't tell at this point if an empty result would come back with a blank array or just no security_groups value at all so... + if (body.security_groups.length) { + return body.security_groups; + } else { + // leave an empty array as the result and log an issue.... that might not be an issue... or might be... + console.error('No Security group found for given project - returning blank array'); + return []; + } + } + + public async getSecurityGroup(group_id: string) { + const request_options = this.getRequestOptions('/security-groups/' + group_id, true, 'remote-calls.neutron.security-groups.get', 'security_group'); + + const body = await this.request.get<{ + security_group: ISecurityGroup; + }>(request_options); + + return body.security_group; + } + + // Creates a new security group and calls back with cb(error, result) + // NOTE: specifying tenant_id is an undocumented feature that allows you to set it to a different tenant than the token + // we use this for creating groups via a service acct + public async createSecurityGroup(group_name: string, data: IUnknowObject) { + const optional_keys = ['description', 'tenant_id']; + const post_data = { security_group: { name: group_name } }; + + assign(post_data.security_group, optional_keys, data); + + const request_options = this.getRequestOptions('/security-groups', post_data, 'remote-calls.neutron.security-groups.create', 'security_group'); + + const body = await this.request.post<{ + security_group: ISecurityGroup; + }>(request_options); + + return body.security_group; + } + + // calls back with (error, security_group) after updating the name and or description of a security group + public async updateSecurityGroup(group_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'description']; + const put_data = { security_group: {} }; + assign(put_data.security_group, optional_keys, data); + + const request_options = this.getRequestOptions('/security-groups/' + group_id, put_data, 'remote-calls.neutron.security-groups.update', 'security_group'); + + const body = await this.request.put<{ + security_group: ISecurityGroup; + }>(request_options); + + return body.security_group; + } + + // calls back with (error) after attempting to remove the given security group + public removeSecurityGroup(group_id: string) { + const request_options = this.getRequestOptions('/security-groups/' + group_id, true, 'remote-calls.neutron.security-groups.remove', ''); + + return this.request.del(request_options); + } + + // Calls back cb(error, security_rules) with a list of security rules for this tenant (which seems kida weird) + public async listSecurityGroupRules() { + const request_options = this.getRequestOptions('/security-group-rules', true, 'remote-calls.neutron.security-group-rules.list', 'security_group_rules'); + + const body = await this.request.get<{ + security_group_rules: ISecurityGroupRule[]; + }>(request_options); + return body.security_group_rules; + } + + public async getSecurityGroupRule(rule_id: string) { + const request_options = this.getRequestOptions('/security-group-rules/' + rule_id, true, 'remote-calls.neutron.security-group-rules.get', 'security_group_rule'); + + const body = await this.request.get<{ + security_group_rule: ISecurityGroupRule; + }>(request_options); + + return body.security_group_rule; + } + + // Calls back cb(error, rule) with a newly created rule from the given group, data + // note: the docs say the direction is optional but lets imagine its not... + // also we need a freakin un-mangler! + public async createSecurityGroupRule(group_id: string, direction: string, data: IUnknowObject) { + const optional_keys = ['tenant_id', 'ethertype', 'protocol', 'port_range_min', 'port_range_max', 'remote_ip_prefix', 'remote_group_id']; + const post_data = { + security_group_rule: { + direction, + security_group_id: group_id + } + }; + assign(post_data.security_group_rule, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/security-group-rules', post_data, 'remote-calls.neutron.security-group-rules.create', 'security_group_rule'); + + const body = await this.request.post<{ + security_group_rule: ISecurityGroupRule; + }>(request_options); + + return body.security_group_rule; + } + + // calls back with (error) after removing the given security group rule + public removeSecurityGroupRule(rule_id: string) { + const request_options = this.getRequestOptions('/security-group-rules/' + rule_id, true, 'remote-calls.neutron.security-group-rules.remove', ''); + + return this.request.del(request_options); + } + + + // -------------------------------------------------- // + // ----------------- Load Balancers ----------------- // + // -------------------------------------------------- // + + public async listLoadBalancers() { + const request_options = this.getRequestOptions('/lbaas/loadbalancers', true, 'remote-calls.neutron.lbaas.loadbalancers.list', 'loadbalancers'); + + const body = await this.request.get<{ + loadbalancers: ILoadBalancer[]; + }>(request_options); + + return body.loadbalancers; + } + + public async getLoadBalancer(lb_id: string) { + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true, 'remote-calls.neutron.lbaas.loadbalancers.get', 'loadbalancer'); + + const body = await this.request.get<{ + loadbalancer: ILoadBalancer; + }>(request_options); + return body.loadbalancer; + } + + // Calls back cb(error, rule) with a newly created resource from the given params + // also we need a freakin un-mangler! + public async createLoadBalancer(tenant_id: string, vip_subnet_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'description', 'vip_address', 'admin_state_up', 'flavor', 'provider']; + const post_data = { + loadbalancer: { + tenant_id, + vip_subnet_id + } + }; + + assign(post_data.loadbalancer, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/loadbalancers', post_data, 'remote-calls.neutron.lbaas.loadbalancers.create', 'loadbalancer'); + + const body = await this.request.post<{ loadbalancer: ILoadBalancer; }>(request_options); + return body.loadbalancer; + } + + // calls back with (error, lb) after updating the lb params + public async updateLoadBalancer(lb_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'description', 'admin_state_up']; + const put_data = { loadbalancer: {} }; + assign(put_data.loadbalancer, optional_keys, data); + + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, put_data, 'remote-calls.neutron.lbaas.loadbalancers.update', 'loadbalancer'); + + const body = await this.request.put<{ + loadbalancer: ILoadBalancer; + }>(request_options); + + return body.loadbalancer; + } + + // calls back with (error) after attempting to remove the given lb + public removeLoadBalancer(lb_id: string) { + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true, 'remote-calls.neutron.lbaas.loadbalancers.remove', ''); + request_options.metricPath = 'remote-calls.neutron.lbaas.loadbalancers.remove'; + request_options.validateStatus = true; + + return this.request.del(request_options); + } + + // -------------------------------------------------- // + // ------------------- Load Balancer Listeners -------------------- // + // -------------------------------------------------- // + + public async listLBListeners() { + const request_options = this.getRequestOptions('/lbaas/listeners', true, 'remote-calls.neutron.lbaas.listeners.list', 'listeners'); + + const body = await this.request.get<{ + listeners: IListener[]; + }>(request_options); + + // Not sure at this point if a blank listener comes back as an empty array or what so.... + if (body.listeners && body.listeners.length) { + return body.listeners; + } else { + return []; + } + } + + public async getLBListener(listener_id: string) { + const request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true, 'remote-calls.neutron.lbaas.listeners.get', 'listener'); + + const body = await this.request.get<{ + listener: IListener; + }>(request_options); + + return body.listener; + } + + // Calls back cb(error, rule) with a newly created listener from the given params + public async createLBListener(tenant_id: string, loadbalancer_id: string, description: string, protocol: string, data: IUnknowObject) { + const optional_keys = ['protocol_port', 'default_tls_container_ref', 'sni_container_refs', 'admin_state_up', 'name', 'connection_limit']; + const post_data = { + listener: { + description, + loadbalancer_id, + protocol, + tenant_id + } + }; + + assign(post_data.listener, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/listeners', post_data, 'remote-calls.neutron.lbaas.listeners.create', 'listener'); + + const body = await this.request.post<{ + listener: IListener; + }>(request_options); + + return body.listener; + } + + // calls back with (error, listener) after updating the listener + public async updateLBListener(listener_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'description', 'admin_state_up', 'connection_limit', 'default_tls_container_ref', 'sni_container_refs']; + const put_data = { listener: {} as IUnknowObject }; + + assign(put_data.listener, optional_keys, data); + + const request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, put_data, 'remote-calls.neutron.lbaas.listeners.update', 'listener'); + + const body = await this.request.put<{ + listener: IListener; + }>(request_options); + + return body.listener; + } + + // calls back with (error) after attempting to remove the given resource + public removeLBListener(listener_id: string) { + const request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true, 'remote-calls.neutron.lbaas.listeners.remove', ''); + + return this.request.del(request_options); + } + + + // -------------------------------------------------- // + // -------------------- LBPools --------------------- // + // -------------------------------------------------- // + + public async listLBPools() { + const request_options = this.getRequestOptions('/lbaas/pools', true, 'remote-calls.neutron.lbaas.pools.list', 'pools'); + + const body = await this.request.get<{ + pools: IPool[]; + }>(request_options); + + return body.pools; + } + + + public async getLBPool(pool_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true, 'remote-calls.neutron.lbaas.pools.get', 'pool'); + + const body = await this.request.get<{ + pool: IPool; + }>(request_options); + return body.pool; + } + + // Calls back cb(error, rule) with a newly created resource from the given params + public async createLBPool(tenant_id: string, protocol: string, lb_algorithm: string, listener_id: string, data: IUnknowObject) { + const optional_keys = ['admin_state_up', 'name', 'description', 'session_persistence']; + const post_data = { + pool: { + lb_algorithm, + listener_id, + protocol, + tenant_id + } + }; + + assign(post_data.pool, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/pools', post_data, 'remote-calls.neutron.lbaas.pools.create', 'pool'); + + const body = await this.request.post<{ + pool: IPool; + }>(request_options); + return body.pool; + } + + public async updateLBPool(pool_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'description', 'admin_state_up', 'lb_algorithm', 'session_persistence']; + const put_data = { pool: {} as IUnknowObject }; + + // loop through all the optional data keys and add them to the post data + for (let n = 0; n < optional_keys.length; n++) { + const key = optional_keys[n]; + if (typeof data[key] !== 'undefined') { + put_data.pool[key] = data[key]; + } + } + + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, put_data, 'remote-calls.neutron.lbaas.pools.update', 'pool'); + + const body = await this.request.put<{ + pool: IPool; + }>(request_options); + return body.pool; + } + + // calls back with (error) after attempting to remove the given resource + public removeLBPool(pool_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true, 'remote-calls.neutron.lbaas.pools.remove', ''); + return this.request.del(request_options); + } + + // -------------------------------------------------- // + // -------------------- LBPoolMembers --------------------- // + // -------------------------------------------------- // + + public async listLBPoolMembers(pool_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', true, 'remote-calls.neutron.lbaas.pools.members.list', 'members'); + + const body = await this.request.get<{ + members: IPoolMember[]; + }>(request_options); + + return body.members; + } + + public async getLBPoolMember(pool_id: string, member_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, true, 'remote-calls.neutron.lbaas.pools.members.get', 'member'); + + const body = await this.request.get<{ + member: IPoolMember; + }>(request_options); + + return body.member; + } + + // Calls back cb(error, rule) with a newly created resource from the given params + public async createLBPoolMember(pool_id: string, tenant_id: string, address: string, protocol_port: number, data: IUnknowObject) { + const optional_keys = ['admin_state_up', 'weight', 'subnet_id']; + const post_data = { + member: { + address, + protocol_port, + tenant_id + } + }; + assign(post_data, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', post_data, 'remote-calls.neutron.lbaas.pools.members.create', 'member'); + + const body = await this.request.post<{ + member: IPoolMember; + }>(request_options); + + return body.member; + } + + public async updateLBPoolMember(pool_id: string, member_id: string, data: IUnknowObject) { + const optional_keys = ['weight', 'admin_state_up']; + const put_data = { member: {} }; + assign(put_data.member, optional_keys, data); + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, put_data, 'remote-calls.neutron.lbaas.pools.members.update', 'member'); + + const body = await this.request.put<{ + member: IPoolMember; + }>(request_options); + + return body.member; + } + + // calls back with (error) after attempting to remove the given resource + public removeLBPoolMember(pool_id: string, member_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, true, 'remote-calls.neutron.lbaas.pools.members.remove', ''); + + return this.request.del(request_options); + } + + + // -------------------------------------------------- // + // ----------------- LBHealthMonitors ----------------- // + // -------------------------------------------------- // + + + public async listLBHealthMonitors() { + const request_options = this.getRequestOptions('/lbaas/healthmonitors', true, 'remote-calls.neutron.lbaas.healthmonitors.list', 'healthmonitors'); + + const body = await this.request.get<{ + healthmonitors: IHealthMonitor[]; + }>(request_options); + + if (body.healthmonitors && body.healthmonitors.length) { + return body.healthmonitors; + } + } + + public async getLBHealthMonitor(health_monitor_id: string) { + const request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true, 'remote-calls.neutron.lbaas.healthmonitors.get', 'healthmonitor'); + + const body = await this.request.get<{ + healthmonitor: IHealthMonitor; + }>(request_options); + + return body.healthmonitor; + } + + // Calls back cb(error, rule) with a newly created resource from the given params + public async createLBHealthMonitor(tenant_id: string, type: string, delay: number, timeout: number, max_retries: number, pool_id: string, data: IUnknowObject) { + const optional_keys = ['http_method', 'url_path', 'expected_codes', 'admin_state_up']; + const post_data = { + healthmonitor: { + delay, + max_retries, + pool_id, + tenant_id, + timeout, + type + } + }; + assign(post_data.healthmonitor, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/healthmonitors', post_data, 'remote-calls.neutron.lbaas.healthmonitors.create', 'healthmonitor'); + + const body = await this.request.post<{ + healthmonitor: IHealthMonitor; + }>(request_options); + + return body.healthmonitor; + } + + public async updateLBHealthMonitor(health_monitor_id: string, data: IUnknowObject) { + const optional_keys = ['delay', 'timeout', 'max_retries', 'http_method', 'url_path', 'expected_codes', 'admin_state_up']; + const put_data = { healthmonitor: {} }; + assign(put_data, optional_keys, data); + + const request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, put_data, 'remote-calls.neutron.lbaas.healthmonitors.update', 'healthmonitor'); + + const body = await this.request.put<{ + healthmonitor: IHealthMonitor; + }>(request_options); + + return body.healthmonitor; + } + + // calls back with (error) after attempting to remove the given resource + public removeLBHealthMonitor(health_monitor_id: string) { + const request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true, 'remote-calls.neutron.lbaas.healthmonitors.remove', ''); + + return this.request.del(request_options); + } + + // -------------------------------------------------- // + // ---------------------- Stats --------------------- // + // -------------------------------------------------- // + // NOTE: May not be available in your openstack installation + // Leaving it here as it may be of use to those who do have it available + public async getLBStats(lb_id: string) { + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id + '/stats', true, 'remote-calls.neutron.lbaas.loadbalancers.stats.get', 'stats'); + + const body = await this.request.get<{ + stats: IStat[]; + }>(request_options); + return body.stats; + } + + // returns an formatted options object - just makes the code below a little less repetitious + // path should begin with a "/" + // json_value should be almost certainly be true if you don't have an actual object you want to send over + private getRequestOptions(path: string, json_value: unknown, metricPath: string, requireBodyObject: string) { + // start w/the instance timeout + let request_timeout = this.timeout; + if (!request_timeout) { + // override with the static value if no instance value was given + request_timeout = default_timeout; + } + return { + headers: { 'X-Auth-Token': this.token }, + json: json_value, + metricLogger: this.logger, + metricPath, + metricRequestID: this.request_id, + metricUserName: this.user_name, + requireBodyObject, + timeout: request_timeout, + uri: this.url + path, + validateStatus: true + }; + } +} + diff --git a/src/nova.ts b/src/nova.ts new file mode 100644 index 0000000..22c8904 --- /dev/null +++ b/src/nova.ts @@ -0,0 +1,601 @@ +import { IMetricLogger } from './os-request'; +import * as Request from './os-request'; +import { default_timeout } from './utils'; + +interface IServer { + // todo + status: 'PAUSED' | 'SUSPENDED' | 'PAUSED'; +} + +interface IFlavor { + // todo + todo: unknown; +} + +interface INetwork { + // todo + todo: unknown; +} + +interface IFloatIpPool { + // todo + name: string; +} + +interface IAvailabilityZoneInfo { + // todo + zoneName: string; +} + +interface IKeyPair { + keypair: { + name: string; + }; +} + +interface IQuotaSet { + // todo + todo: unknown; +} + +interface ITenantUsage { + // todo + todo: unknown; +} + +export default class Nova { + private url: string; + private token: string; + private timeout = default_timeout; + private request_id = ''; + private user_name = ''; + private logger = null as unknown as IMetricLogger; + private request = Request; + constructor(endpoint_url: string, auth_token: string) { + // Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes + this.url = endpoint_url.replace(/\/$/, ''); + + // auth_token should be the scoped token from the projectInfo call + this.token = auth_token; + } + + public setRequest(request: typeof Request) { + this.request = request; + } + + // setters for individual obj/call usage + // just set these prior to doing things and your good to go until you want to change it + public setTimeout(new_timeout: number) { + this.timeout = new_timeout; + } + + public setRequestID(request_id: string) { + this.request_id = request_id; + } + + public setUserName(user_name: string) { + this.user_name = user_name; + } + + public setLogger(logger: IMetricLogger) { + this.logger = logger; + } + + // ---------------- + // Server methods + // ---------------- + // NOTE: options is an optional hash that lets you specify filters on the listing call ie: {limit: 1} + public async listServers(options: {}) { + // now on with the show + const request_options = this.getRequestOptions('/servers/detail', true, 'remote-calls.nova.servers.list', 'servers', true); + + // todo + const body = await this.request.get<{ + servers: IServer[]; + }>({ + ...request_options, + qs: options + }); + return body.servers; + } + + public async getServer(id: string) { + const request_options = this.getRequestOptions('/servers/' + id, true, 'remote-calls.nova.servers.get', 'server', true); + request_options.metricPath = 'remote-calls.nova.servers.get'; + request_options.validateStatus = true; + request_options.requireBodyObject = 'server'; + + const body = await this.request.get<{ + server: IServer; + }>(request_options); + + return body.server; + } + + public async createServer(data: unknown) { + const request_options = this.getRequestOptions('/servers', data, 'remote-calls.nova.servers.create', '', true); + // Commenting out so that we can handle returns of 'servers' for multiple creates + // request_options.requireBodyObject = 'server'; + + const body = await this.request.post<{ + server: IServer; + }>(request_options); + + return body.server; + } + + public renameServer(id: string, name: string) { + const data = { server: { name } }; + const request_options = this.getRequestOptions('/servers/' + id, data, 'remote-calls.nova.servers.rename', '', true); + + return this.request.put(request_options); + } + + public resizeServer(id: string, flavor: string) { + const data = { resize: { flavorRef: flavor } }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.resize', '', true); + + return this.request.post(request_options); + } + + public confirmResizeServer(id: string) { + const data = { confirmResize: null }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.resize-confirm', '', true); + + return this.request.post(request_options); + } + + public revertResizeServer(id: string) { + const data = { revertResize: null }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.resize-revert', '', true); + + return this.request.post(request_options); + } + + public removeServer(id: string) { + const request_options = this.getRequestOptions('/servers/' + id, true, 'remote-calls.nova.servers.remove', '', true); + request_options.metricPath = 'remote-calls.nova.servers.remove'; + request_options.validateStatus = true; + + return this.request.del(request_options); + } + + public rebootServer(id: string) { + const data = { reboot: { type: 'SOFT' } }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.reboot', '', true); + + return this.request.post(request_options); + } + + public forceRebootServer(id: string) { + const data = { reboot: { type: 'HARD' } }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.reboot-force', '', true); + return this.request.post(request_options); + } + + public stopServer(id: string) { + const data = { 'os-stop': null }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.stop', '', true); + + return this.request.post(request_options); + } + + public startServer(id: string) { + const data = { 'os-start': null }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.start', ''); + + return this.request.post(request_options); + } + + public pauseServer(id: string) { + const data = { pause: null }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.pause', ''); + + return this.request.post(request_options); + } + + public suspendServer(id: string) { + const data = { suspend: null }; + const request_options = this.getRequestOptions('/servers/' + id + '/action', data, 'remote-calls.nova.servers.suspend', ''); + + return this.request.post(request_options); + } + + public async resumeServer(id: string) { + const server = await this.getServer(id); + + if (server.status !== 'PAUSED' && server.status !== 'SUSPENDED') { + throw new Error('Cannot resume server. Server is not in a paused or suspected state.'); + } + + const data = server.status === 'PAUSED' ? { unpause: null } : { resume: null }; + const request_options = this.getRequestOptions('/servers/' + escape(id) + '/action', data, 'remote-calls.nova.servers.resume', '', true); + + return this.request.post(request_options); + } + + public async getServerConsoleURL(type: 'spice-html5' | 'novnc', id: string) { + let data = {}; + + if (type === 'spice-html5') { + data = { 'os-getSPICEConsole': { type } }; + } else { + if (type === undefined || !type) { + type = 'novnc'; + } + data = { 'os-getVNCConsole': { type } }; + } + const request_options = this.getRequestOptions('/servers/' + escape(id) + '/action', data, 'remote-calls.nova.servers.console-urls.get', 'console.url', true); + + const body = await this.request.post<{ + console: { + url: string; + }; + }>(request_options); + + return body.console.url; + } + + // gets [length] lines form the log? of an instance + public async getServerLog(id: string, length: number) { + if (length === undefined || !length) { + length = 35; + } + + const data = { 'os-getConsoleOutput': { length } }; + const request_options = this.getRequestOptions('/servers/' + escape(id) + '/action', data, 'remote-calls.nova.servers.logs.get', 'output', true); + + const body = await this.request.post<{ output: string; }>(request_options); + + return body.output; + } + + // creates an image from the current disk of an instance + // takes the id of an instance as well as any meta-data to be added to the image + // calls back with(error, new_image_info) + public async createServerImage(id: string, { + name, + metadata + }: { + name?: string; + metadata?: object; + }) { + const request_options = this.getRequestOptions('/servers/' + escape(id) + '/action', { createImage: { name, metadata } }, 'remote-calls.nova.servers.images.create', '', true); + // commenting out to support later versions of nova that dont return + // request_options.requireBodyObject = 'output'; + + const { body, res } = await this.request.request<{ + image_id: string; + }>({ + ...request_options, + method: 'POST' + }); + let image_id = ''; + // else if nova 2.45+ the image id is in the body, else its in the header (in theory) + + if (body && body.image_id) { + // nova 2.45+ + image_id = body.image_id; + } else { + // old skool + const url = res.headers.location; + image_id = url!.match(/.*\/images\/(.*)/)![1]; + } + + // removing ServerImage mangling as we are updating this method with a diffrent format in 2.2+ + // going to try and output as close to what recent nova does regardless of version of nova used + return { image_id }; + } + + public setServerMetadata(id: string, data: unknown) { + const request_options = this.getRequestOptions('/servers/' + escape(id) + '/metadata', { metadata: data }, 'remote-calls.nova.servers.metadata.update', '', true); + + return this.request.put(request_options); + } + + // ---------------- + // Flavor + // ---------------- + public async listFlavors() { + const request_options = this.getRequestOptions('/flavors/detail', true, 'remote-calls.nova.flavors.list', 'flavors', true); + + const body = await this.request.get<{ + flavors: IFlavor[]; + }>(request_options); + + return body.flavors; + } + + public async getFlavor(id: string) { + const request_options = this.getRequestOptions('/flavors/' + escape(id), true, 'remote-calls.nova.flavors.get', 'flavor', true); + + const body = await this.request.get<{ + flavor: IFlavor; + }>(request_options); + + return body.flavor; + } + + // ---------------- + // Project Network + // ---------------- + public async listProjectNetworks() { + const request_options = this.getRequestOptions('/os-tenant-networks', true, 'remote-calls.nova.os-tenant-networks.list', 'networks', true); + + const body = await this.request.get<{ + networks: INetwork[]; + }>(request_options); + + return body.networks; + } + + // ---------------- + // Floating IP + // ---------------- + public async listFloatingIps() { + const request_options = this.getRequestOptions('/os-floating-ips', true, 'remote-calls.nova.floating-ips.list', 'floating_ips', true); + + const body = await this.request.get<{ + floating_ips: string[]; + }>(request_options); + + return body.floating_ips; + } + + + public async getFloatingIp(id: string) { + const request_options = this.getRequestOptions('/os-floating-ips/' + escape(id), true, 'remote-calls.nova.floating-ips.get', 'floating_ip', true); + + const body = await this.request.get<{ + floating_ip: string; + }>(request_options); + + return body.floating_ip; + } + + // allocates assigns an ip + // calls cb with the info on the created ip + public async createFloatingIp(data: { + pool: unknown; + }) { + const post_data = data.pool !== undefined ? { pool: data.pool } : true; + const request_options = this.getRequestOptions('/os-floating-ips', post_data, 'remote-calls.nova.floating-ips.allocate', 'floating_ip', true); + + const body = await this.request.post<{ + floating_ip: string; + }>(request_options); + + return body.floating_ip; + } + + // removes the floating ip from the pool and dissasociates and generally hates all things + // calls back with cb(error) + public removeFloatingIp(id: string) { + const request_options = this.getRequestOptions('/os-floating-ips/' + escape(id), true, 'remote-calls.nova.floating-ips.remove', '', true); + + return this.request.del(request_options); + } + + // associates a given : string a given ip address (nova only supports the ip_address not the ip_id) + // calls back with cb(error) as nova doesn't provide a result beyond a 204 + public associateFloatingIp(instance_id: string, ip_address: string) { + const data = { addFloatingIp: { address: ip_address } }; + const request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data, 'remote-calls.nova.floating-ips.associate', '', true); + + return this.request.post(request_options); + } + + // disassociates a given instance with a given ip address (nova only supports the ip_address not the ip_id) + // calls back with cb(error) as nova doesn't provide a result beyond a 204 + public disassociateFloatingIp(instance_id: string, ip_address: string) { + const data = { removeFloatingIp: { address: ip_address } }; + const request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data, 'remote-calls.nova.floating-ips.disassociate', '', true); + + return this.request.post(request_options); + } + + // ---------------- + // Floating IP Pool + // ---------------- + public async listFloatingIpPools() { + const request_options = this.getRequestOptions('/os-floating-ip-pools', true, 'remote-calls.nova.ip-pool-list', 'floating_ip_pools', true); + + const body = await this.request.get<{ + floating_ip_pools: IFloatIpPool[]; // todo + }>(request_options); + + return body.floating_ip_pools; + } + + // since theres apparently no getIpPool info method in the nova api... + // NOTE: the return from ip_pools is weird and doesn' thave an id but its a better term. id == name in reality + public async getFloatingIpPool(id: string) { + const pools = await this.listFloatingIpPools(); + + for (let i = 0; i < pools.length; i++) { + if (pools[i].name === id) { + return pools[i]; + } + } + + throw new Error('No pool with specified id found'); + } + + // ---------------- + // Availability Zone + // ---------------- + public async listAvailabilityZones() { + const request_options = this.getRequestOptions('/os-availability-zone', true, 'remote-calls.nova.os-availability-zones.list', 'availabilityZoneInfo', true); + + const body = await this.request.get<{ + availabilityZoneInfo: IAvailabilityZoneInfo[]; + }>(request_options); + + return body.availabilityZoneInfo; + } + + // and since there is no method to get zone info in the nova api... + // NOTE: the return from listAvailabilityZones is weird and doesn' thave an id but its a better term. id == name in reality + public async getAvailabilityZone(id: string) { + const zones = await this.listAvailabilityZones(); + for (let i = 0; i < zones.length; i++) { + if (zones[i].zoneName === id) { + return zones[i]; + } + } + throw new Error('No zone with specified id found'); + + } + + // --------------- + // (SSH) Key Pairs + // --------------- + public async listKeyPairs() { + const request_options = this.getRequestOptions('/os-keypairs', true, 'remote-calls.nova.key-pairs.list', 'keypairs', true); + + const body = await this.request.get<{ + keypairs: IKeyPair[]; + }>(request_options); + + return body.keypairs.map((keypair) => { + return keypair.keypair; + }); + } + + public async getKeyPair(id: string) { + const request_options = this.getRequestOptions('/os-keypairs/' + id, true, 'remote-calls.nova.key-pairs.get', 'keypair', true); + + const body = await this.request.get<{ + keypair: unknown; // todo + }>(request_options); + + return body.keypair; + } + + public async createKeyPair(name: string, public_key?: string) { + const data = { + keypair: { + name, + public_key + } + }; + const request_options = this.getRequestOptions('/os-keypairs', data, 'remote-calls.nova.key-pairs.create', 'keypair', true); + + const body = await this.request.post<{ + keypair: IKeyPair; + }>(request_options); + + return body.keypair; + } + + public removeKeyPair(id: string) { + const request_options = this.getRequestOptions('/os-keypairs/' + id, true, 'remote-calls.nova.key-pairs.remove', '', true); + + return this.request.del(request_options); + } + + public async getQuotaSet(project_id: string) { + const request_options = this.getRequestOptions('/os-quota-sets/' + escape(project_id), true, 'remote-calls.nova.quota-sets.get', 'quota_set', true); + + const body = await this.request.get<{ + quota_set: IQuotaSet; + }>(request_options); + return body.quota_set; + } + + // updates the quota for a given project_id + // data should be an object with all of the things you want to update + // supported values are cores, ram, instances, floating_ip, and anything else in the docs + // calls back with cb(error, quota_set) where quota_set is an object with all the updated params + // *****NOTE: the token required for this call is usually the one scoped to the admin (usually 'openstack') project + // even though the call is not usually on that specific project_id + public async setQuotaSet(project_id: string, data: unknown) { + const request_options = this.getRequestOptions('/os-quota-sets/' + escape(project_id), { quota_set: data }, 'remote-calls.nova.quota-sets.update', 'quota_set', true); + + const body = await this.request.put<{ + quota_set: IQuotaSet; + }>(request_options); + return body.quota_set; + } + + // start_date and end_date should just be any 2 date objects + public async getTenantUsage(project_id: string, start_date_obj: Date, end_date_obj: Date) { + let url = '/os-simple-tenant-usage/' + escape(project_id); + + // format of dates should be: %Y-%m-%d %H:%M:%S.%f + url += '?start=' + start_date_obj.toISOString().replace('T', ' ').replace('Z', ''); + url += '&end=' + end_date_obj.toISOString().replace('T', ' ').replace('Z', ''); + + const request_options = this.getRequestOptions(url, true, 'remote-calls.nova.tenant-usage.get', 'tenant_usage', true); + + const body = await this.request.get<{ + tenant_usage: ITenantUsage; + }>(request_options); + + return body.tenant_usage; + } + + // --------------- + // SecurityGroup + // --------------- + public assignSecurityGroup(security_group_name: string, instance_id: string) { + const data = { addSecurityGroup: { name: security_group_name } }; + const request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data, 'remote-calls.nova.servers.add-security-group', '', true); + + return this.request.post(request_options); + } + + public removeSecurityGroup(security_group_name: string, instance_id: string) { + const data = { removeSecurityGroup: { name: security_group_name } }; + const request_options = this.getRequestOptions('/servers/' + escape(instance_id) + '/action', data, 'remote-calls.nova.servers.remove-security-group', '', true); + + return this.request.post(request_options); + } + + // -------------------------------------------------- // + // Image MetaData (still handled by nova because....) // + // -------------------------------------------------- // + public async getImageMetaData(id: string) { + const request_options = this.getRequestOptions('/images/' + escape(id) + '/metadata', true, 'remote-calls.nova.images.metadata.get', 'metadata', true); + + const body = await this.request.get<{ + metadata: unknown; + }>(request_options); + return body.metadata; + } + + public async setImageMetaData(id: string, data: unknown) { + const request_options = this.getRequestOptions('/images/' + escape(id) + '/metadata', { metadata: data }, 'remote-calls.nova.images.metadata.update', 'metadata', true); + + const body = await this.request.put<{ + metadata: unknown; + }>(request_options); + + return body.metadata; + } + + // returns an formatted options object - just makes the code below a little less repetitious + // path should begin with a "/" + // json_value should be almost certainly be true if you don't have an actual object you want to send over + private getRequestOptions(path: string, json_value: unknown, metricPath: string, requireBodyObject: string, validateStatus?: boolean) { + // start w/the instance timeout + let request_timeout = this.timeout; + if (!request_timeout) { + // override with the static value if no instance value was given + request_timeout = default_timeout; + } + const return_object = { + headers: { 'X-Auth-Token': this.token } as { [key: string]: string; }, + json: json_value, + metricLogger: this.logger, + metricPath, + metricRequestID: this.request_id, + metricUserName: this.user_name, + requireBodyObject, + timeout: request_timeout, + uri: this.url + path, + validateStatus + }; + return return_object; + } +} diff --git a/src/octavia.ts b/src/octavia.ts new file mode 100644 index 0000000..d1fd0c2 --- /dev/null +++ b/src/octavia.ts @@ -0,0 +1,494 @@ +import { IDetail, IMetricLogger } from './os-request'; +import * as Request from './os-request'; +import { assign, default_timeout, IUnknowObject } from './utils'; + +interface ILoadbalancer { + // todo + todo: unknown; +} + +interface IListener { + // todo + todo: unknown; +} + +interface IPool { + // todo + todo: unknown; +} + +interface IPoolMember { + // todo + todo: unknown; +} + +interface IStat { + // todo + todo: unknown; +} + +interface IHealthMonitor { + // todo + todo: unknown; +} + +export default class Octavia { + private retries = 5; + private url: string; + private token: string; + private timeout = default_timeout; + private request_id = ''; + private user_name = ''; + private logger = null as unknown as IMetricLogger; + private retry_delay = 2000; + private request = Request; + constructor(endpoint_url: string, auth_token: string) { + // Keystone v3 is the only supported version at this point - add the url and yank all trailing slashes + this.url = endpoint_url.replace(/\/$/, ''); + + // auth_token should be the scoped token from the projectInfo call + this.token = auth_token; + } + + public setRequest(request: typeof Request) { + this.request = request; + } + + // setters for individual obj/call usage + // just set these prior to doing things and your good to go until you want to change it + public setTimeout(new_timeout: number) { + this.timeout = new_timeout; + } + + public setRequestID(request_id: string) { + this.request_id = request_id; + } + + public setUserName(user_name: string) { + this.user_name = user_name; + } + + public setLogger(logger: IMetricLogger) { + this.logger = logger; + } + + public setRetries(retries: number) { + this.retries = retries; + } + + public setRetryDelay(retry_delay: number) { + this.retry_delay = retry_delay; + } + + public async listLoadBalancers() { + const request_options = this.getRequestOptions('/lbaas/loadbalancers', true, 'remote-calls.octavia.lbaas.loadbalancers.list', 'loadbalancers'); + + const body = await this.request.get<{ + loadbalancers: ILoadbalancer[]; + }>(request_options); + // Not sure at this point if a blank resource comes back as an empty array or what so.... + return body.loadbalancers; + } + + public async getLoadBalancer(lb_id: string) { + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true, 'remote-calls.octavia.lbaas.loadbalancers.get', 'loadbalancer'); + + const body = await this.request.get<{ + loadbalancer: ILoadbalancer; + }>(request_options); + + return body.loadbalancer; + } + + // Calls back cb(error, rule) with a newly created resource from the given params + // todo @param project_id is not used + public async createLoadBalancer(data: IUnknowObject) { + const optional_keys = ['name', 'description', 'vip_address', 'vip_network_id', 'vip_port_id', 'admin_state_up', 'flavor', 'provider']; + const post_data = { loadbalancer: {} }; + assign(post_data.loadbalancer, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/loadbalancers', post_data, 'remote-calls.octavia.lbaas.loadbalancers.create', 'loadbalancer'); + // request_options.debug = true; + + const body = await this.request.post<{ + loadbalancer: ILoadbalancer; + }>(request_options); + + return body.loadbalancer; + } + + // calls back with (error, lb) after updating the lb params + public async updateLoadBalancer(lb_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'description', 'admin_state_up']; + const put_data = { loadbalancer: {} }; + assign(put_data.loadbalancer, optional_keys, data); + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, put_data, 'remote-calls.octavia.lbaas.loadbalancers.update', 'loadbalancer'); + + const body = await this.request.put<{ + loadbalancer: ILoadbalancer; + }>(request_options); + return body.loadbalancer; + } + + // calls back with (error) after attempting to remove the given lb + public removeLoadBalancer(lb_id: string) { + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id, true, 'remote-calls.octavia.lbaas.loadbalancers.remove', ''); + + return this.request.del(request_options); + } + + // -------------------------------------------------- // + // ------------------- Load Balancer Listeners -------------------- // + // -------------------------------------------------- // + + public async listLBListeners() { + const request_options = this.getRequestOptions('/lbaas/listeners', true, 'remote-calls.octavia.lbaas.listeners.list', 'listeners'); + + const body = await this.request.get<{ + listeners: IListener[]; + }>(request_options); + // Not sure at this point if a blank listener comes back as an empty array or what so.... + if (body.listeners && body.listeners.length) { + return body.listeners; + } else { + return []; + } + } + + public async getLBListener(listener_id: string) { + const request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true, 'remote-calls.octavia.lbaas.listeners.get', 'listener'); + + const body = await this.request.get<{ + listener: IListener; + }>(request_options); + return body.listener; + } + + // Creates a load balancer listener + // calls back with cb(error, listener) + public createLBListener(loadbalancer_id: string, protocol: string, data: IUnknowObject) { + const optional_keys = ['default_pool', 'default_pool_id', 'insert_headers', 'l7policies', 'description', 'protocol_port', 'default_tls_container_ref', 'sni_container_refs', 'admin_state_up', 'name', 'connection_limit']; + const post_data = { + listener: { + loadbalancer_id, + protocol + } + }; + assign(post_data.listener, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/listeners', post_data, 'remote-calls.octavia.lbaas.listeners.create', 'listener'); + + return this.retry(async () => { + const body = await this.request.post<{ + listener: IListener; + }>(request_options); + return body.listener; + }); + } + + // calls back with (error, listener) after updating the listener + public updateLBListener(listener_id: string, data: IUnknowObject) { + const optional_keys = ['default_pool_id', 'insert_headers', 'name', 'description', 'admin_state_up', 'connection_limit', 'default_tls_container_ref', 'sni_container_refs']; + const put_data = { listener: {} }; + assign(put_data.listener, optional_keys, data); + + const request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, put_data, 'remote-calls.octavia.lbaas.listeners.update', 'listener'); + + return this.retry(async () => { + const body = await this.request.put<{ + listener: IListener; + }>(request_options); + return body.listener; + }); + } + + // calls back with (error) after attempting to remove the given resource + public removeLBListener(listener_id: string) { + const request_options = this.getRequestOptions('/lbaas/listeners/' + listener_id, true, 'remote-calls.octavia.lbaas.listeners.remove', ''); + return this.retry(() => { + return this.request.del(request_options); + }); + } + + // -------------------------------------------------- // + // -------------------- LBPools --------------------- // + // -------------------------------------------------- // + + public async listLBPools() { + const request_options = this.getRequestOptions('/lbaas/pools', true, 'remote-calls.octavia.lbaas.pools.list', 'pools'); + + const body = await this.request.get<{ + pools: IPool[]; + }>(request_options); + + return body.pools; + } + + public async getLBPool(pool_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true, 'remote-calls.octavia.lbaas.pools.get', 'pool'); + + const body = await this.request.get<{ + pool: IPool; + }>(request_options); + return body.pool; + } + + // Calls back cb(error, rule) with a newly created resource from the given params + public createLBPool(protocol: string, lb_algorithm: string, data: IUnknowObject) { + const optional_keys = ['loadbalancer_id', 'listener_id', 'admin_state_up', 'name', 'description', 'session_persistence']; + const post_data = { + pool: { + lb_algorithm, + protocol + } + }; + assign(post_data.pool, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/pools', post_data, 'remote-calls.octavia.lbaas.pools.create', 'pool'); + + return this.retry(async () => { + const body = await this.request.post<{ + pool: IPool; + }>(request_options); + + return body.pool; + }); + } + + public updateLBPool(pool_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'description', 'admin_state_up', 'lb_algorithm', 'session_persistence']; + const put_data = { pool: {} }; + assign(put_data.pool, optional_keys, data); + + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, put_data, 'remote-calls.octavia.lbaas.pools.update', 'pool'); + + return this.retry(async () => { + const body = await this.request.put<{ + pool: IPool; + }>(request_options); + + return body.pool; + }); + } + + // calls back with (error) after attempting to remove the given resource + public removeLBPool(pool_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id, true, 'remote-calls.octavia.lbaas.pools.remove', ''); + + return this.retry(() => { + return this.request.del(request_options); + }); + } + + // -------------------------------------------------- // + // -------------------- LBPoolMembers --------------------- // + // -------------------------------------------------- // + + public async listLBPoolMembers(pool_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', true, 'remote-calls.octavia.lbaas.pools.members.list', 'members'); + + const body = await this.request.get<{ + members: IPoolMember[]; + }>(request_options); + return body.members; + } + + public async getLBPoolMember(pool_id: string, member_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, true, 'remote-calls.octavia.lbaas.pools.members.get', 'member'); + + const body = await this.request.get<{ + member: IPoolMember; + }>(request_options); + return body.member; + } + + // Creates a member on a given pool + // calls back with cb(error, member_obj) + public createLBPoolMember(pool_id: string, address: string, protocol_port: number, data: IUnknowObject) { + const optional_keys = ['name', 'monitor_port', 'monitor_address', 'admin_state_up', 'weight', 'subnet_id']; + const post_data = { + member: { + address, + protocol_port + } + }; + assign(post_data.member, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members', post_data, 'remote-calls.octavia.lbaas.pools.members.create', 'member'); + return this.retry(async () => { + const body = await this.request.post<{ + member: IPoolMember; + }>(request_options); + return body.member; + }); + } + + public updateLBPoolMember(pool_id: string, member_id: string, data: IUnknowObject) { + const optional_keys = ['name', 'monitor_port', 'monitor_address', 'weight', 'admin_state_up']; + const put_data = { member: {} }; + assign(put_data.member, optional_keys, data); + + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, put_data, 'remote-calls.octavia.lbaas.pools.members.update', 'member'); + return this.retry(async () => { + const body = await this.request.put<{ + member: IPoolMember; + }>(request_options); + + return body.member; + }); + } + + // calls back with (error) after attempting to remove the given resource + public removeLBPoolMember(pool_id: string, member_id: string) { + const request_options = this.getRequestOptions('/lbaas/pools/' + pool_id + '/members/' + member_id, true, 'remote-calls.octavia.lbaas.pools.members.remove', ''); + // request_options.debug = true; + + return this.retry(() => { + return this.request.del(request_options); + }); + } + + // -------------------------------------------------- // + // ----------------- Health Monitors ---------------- // + // -------------------------------------------------- // + public async listLBHealthMonitors() { + const request_options = this.getRequestOptions('/lbaas/healthmonitors', true, 'remote-calls.octavia.lbaas.healthmonitors.list', 'healthmonitors'); + + const body = await this.request.get<{ + healthmonitors: IHealthMonitor[]; + }>(request_options); + + if (body.healthmonitors && body.healthmonitors.length) { + return body.healthmonitors; + } else { + return []; + } + } + + public async getLBHealthMonitor(health_monitor_id: string) { + const request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true, 'remote-calls.octavia.lbaas.healthmonitors.get', 'healthmonitor'); + + const body = await this.request.get<{ + healthmonitor: IHealthMonitor; + }>(request_options); + + return body.healthmonitor; + } + + // Creates a healthcheck for a given pool + // calls back with cb(error, health_monitor_obj) + public createLBHealthMonitor(pool_id: string, type: string, delay: number, timeout: number, max_retries: number, data: IUnknowObject) { + const optional_keys = ['name', 'max_retries_down', 'http_method', 'url_path', 'expected_codes', 'admin_state_up']; + const post_data = { + healthmonitor: { + delay, + max_retries, + pool_id, + timeout, + type + } + }; + + assign(post_data.healthmonitor, optional_keys, data); + + // and now we can get the full request options object add the log path and make the request + const request_options = this.getRequestOptions('/lbaas/healthmonitors', post_data, 'remote-calls.octavia.lbaas.healthmonitors.create', 'healthmonitor'); + + return this.retry(async () => { + const body = await this.request.post<{ + healthmonitor: IHealthMonitor; + }>(request_options); + return body.healthmonitor; + }); + } + + public updateLBHealthMonitor(health_monitor_id: string, data: IUnknowObject) { + const optional_keys = ['delay', 'timeout', 'max_retries', 'max_retries_down', 'http_method', 'url_path', 'expected_codes', 'admin_state_up']; + const put_data = { healthmonitor: {} }; + assign(put_data.healthmonitor, optional_keys, data); + + const request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, put_data, 'remote-calls.octavia.lbaas.healthmonitors.update', 'healthmonitor'); + + return this.retry(async () => { + const body = await this.request.put<{ + healthmonitor: IHealthMonitor; + }>(request_options); + + return body.healthmonitor; + }); + } + + // calls back with (error) after attempting to remove the given resource + public removeLBHealthMonitor(health_monitor_id: string) { + const request_options = this.getRequestOptions('/lbaas/healthmonitors/' + health_monitor_id, true, 'remote-calls.octavia.lbaas.healthmonitors.remove', ''); + + return this.retry(async () => { + return this.request.del(request_options); + }); + } + + // -------------------------------------------------- // + // ---------------------- Stats --------------------- // + // -------------------------------------------------- // + // NOTE: This is just here for experimentation - not really supporting/supported yet + // Leaving it here though as it may be of use to those who do have it available + public async getLBStats(lb_id: string) { + const request_options = this.getRequestOptions('/lbaas/loadbalancers/' + lb_id + '/stats', true, 'remote-calls.octavia.lbaas.loadbalancers.stats.get', 'stats'); + + const body = await this.request.get<{ + stats: IStat[]; + }>(request_options); + return body.stats; + } + + // returns an formatted options object - just makes the code below a little less repetitious + // path should begin with a "/" + // json_value should be almost certainly be true if you don't have an actual object you want to send over + private getRequestOptions(path: string, json_value: unknown, metricPath: string, requireBodyObject: string) { + // start w/the instance timeout + let request_timeout = this.timeout; + if (!request_timeout) { + // override with the static value if no instance value was given + request_timeout = default_timeout; + } + const return_object = { + headers: { 'X-Auth-Token': this.token }, + json: json_value, + metricLogger: this.logger, + metricPath, + metricRequestID: this.request_id, + metricUserName: this.user_name, + requireBodyObject, + timeout: request_timeout, + uri: this.url + path, + validateStatus: true + }; + + return return_object; + } + + private retry(fun: () => T | Promise) { + return execute(fun, this.retries, 0, this.retry_delay); + } +} + +async function execute(fun: () => T | Promise, max: number, count: number, timeout: number): Promise { + try { + return await fun(); + } catch (error) { + if ((error as IDetail).remoteStatusCode === 409 && count <= max) { + return await new Promise((res) => { + setTimeout(() => { + res(execute(fun, max, ++count, timeout)); + }, timeout); + }); + } else { + throw error; + } + } +} + diff --git a/src/os-request.ts b/src/os-request.ts new file mode 100644 index 0000000..6c04cb7 --- /dev/null +++ b/src/os-request.ts @@ -0,0 +1,415 @@ +// just a wrapper for the request object with some extra metrics stuff thrown on top +import Request from 'request'; + +// given a deep object and a nested property string 'a.b.c.d' send back the value with a default of defaultValue +// basically lets avoid (if x && x.a && x.a.b && x.a.b.c) +function _getNestedPropValue(obj: { [key: string]: unknown }, nestedProperty: string, defaultValue: T) { + return nestedProperty.split('.').reduce((accum, currentProperty, index, arr) => { + // check if it exists, if not, return the default value (aka accum) + if (obj && typeof obj[currentProperty] !== 'undefined' && obj[currentProperty] !== null) { + // last one, return its value + if (index === arr.length - 1) { + return obj[currentProperty] as T; + } else { + obj = obj[currentProperty] as { [key: string]: unknown }; + return accum; + } + } else { + return accum; + } + }, defaultValue); +} + +export interface IDetail { + remoteMethod: string; remoteURI: string; + remoteStatusCode: number; + remoteMessage: string; + remoteCode: string; + remoteDetail: string; + responseTime: number; +} + +interface IError extends Error { + code: string; + detail: IDetail; +} + +interface IRequestOptions { + requireBodyObject?: string; + method?: string; + uri: string; + host?: string; + path?: string; + port?: number; +} + +interface IBody { + message?: string; + code?: string; + detail?: string; + [key: string]: unknown | Error; +} + +// given all the pieces of a remote request and the knowledge that an error occured +// this function returns a proper error object but with some extra props +// to use just pass in as much of this stuff as you have +// normally just used in gdrequest but can be used elswhere when raw request is needed (hence in util) +// return error is in following format: +// it will also return a true error object in the following format +// { +// message: 'verbal description of what went wrong', +// stack: '[message]: stack track shown here', +// code: 'ALLCAPSCODE', +// detail: +// { +// remoteMethod: 'GET', +// remoteURI: 'http://odds.are.some.url/index.html', +// remoteStatusCode: 404 +// remoteMessage: 'verbal message parsed from remote response - should be a string', +// remoteCode: 'PARSEDFROMRESPONSE' +// remoteDetail: 'also parsed from remote response - should be a string', +// responseTime: 2.22 +// } +// } +function _getRequestError(error: IError, response: Request.Response, body: IBody, request_options: IRequestOptions, response_time: number) { + let return_error = null as unknown as IError; + let message = ''; + const code = 'REMOTEERROR'; + const detail = {} as IDetail; + let remote_method = ''; + let remote_uri = ''; + let remote_status_code = 0; + let remote_message = ''; + let remote_code = ''; + let remote_detail = ''; + let key = ''; + + + // first the message and code for the actual error - should reflect what went wrong + // not what the remote api sent as a message/code (thats remote message and remote code) + if (error && error.message) { + message = error.message; + } else if (response && response.statusCode && (response.statusCode <= 199 || response.statusCode >= 300)) { + message = 'Invalid status (' + response.statusCode + ') from remote call'; + } else if (request_options && request_options.requireBodyObject && _getNestedPropValue(body, request_options.requireBodyObject, 'nope-nope-nope') === 'nope-nope-nope') { + message = 'Invalid format (' + request_options.requireBodyObject + ') missing from remote call'; + } else { + message = 'Unknown error making remote call'; + } + + + // get the remote method from the data we have + if (response && response.request && response.request.method) { + remote_method = response.request.method; + } else if (request_options && request_options.method) { + remote_method = request_options.method; + } else { + remote_method = 'indeterminable'; + } + + + // get the uri if possible + if (response && response.request && response.request.uri && response.request.uri.href) { + remote_uri = response.request.uri.href; + } else if (request_options && request_options.uri) { + remote_uri = request_options.uri; + } else if (request_options && (request_options.host || request_options.path)) { + // its fine if one or more of these is blank/undefined - doing our best here is all + remote_uri = request_options.host + ':' + request_options.port + request_options.path; + } else { + remote_uri = 'indeterminable'; + } + + + // now the status that came from the response + if (response && response.statusCode) { + remote_status_code = response.statusCode; + } + + // now for the remote message - get whatever you can from wherever you can + if (body && body.message) { + remote_message = body.message; + } else if (body) { + for (key in body) { + // body.key check takes care of null which can't be hasOwnProperty'd apparently + if (body.hasOwnProperty(key) && body[key] && (body[key] as IError).hasOwnProperty('message')) { + remote_message = (body[key] as IError).message; + } + } + } + // and as a last resort + if (body && !remote_message) { + // toss a little of the body on there - limit this so we don't spew mountains of html to the logs + remote_message = JSON.stringify(body).substring(0, 150); + } + // else its just blank as theres no remote body at all + + + // look for an error code returned from the remote api + if (body && body.code) { + remote_code = body.code; + } else if (body) { + for (key in body) { + // body.key check takes care of null which can't be hasOwnProperty'd apparently + if (body.hasOwnProperty(key) && body[key] && (body[key] as {}).hasOwnProperty('code')) { + remote_code = (body[key] as { code: string }).code; + } + } + } + // else it can just be blank + + + // get remote details + if (body && body.detail) { + remote_detail = body.detail; + } else if (body) { + for (key in body) { + // body.key check takes care of null which can't be hasOwnProperty'd apparently + if (body.hasOwnProperty(key) && body[key] && (body[key] as {}).hasOwnProperty('detail')) { + remote_detail = (body[key] as { detail: string }).detail; + } + } + } + // else it can just be blank + + + // now we can craft the detail prop for the error + detail.remoteMethod = remote_method; + detail.remoteURI = remote_uri; + detail.remoteStatusCode = remote_status_code; + detail.remoteMessage = remote_message; + detail.remoteCode = remote_code; + detail.remoteDetail = remote_detail; + if (response_time) { + detail.responseTime = response_time; + } else { + detail.responseTime = 0; + } + + + // now that we have all the things - construct the error (or use existing error) and return it + if (error) { + return_error = error; + return_error.message = message;// could have changed + } else { + return_error = new Error(message) as IError; + } + return_error.code = code; + return_error.detail = detail; + + // console.log('returning error', return_error); + return return_error; +} + +export interface IMetricLogger { + logMetric(options: { + metricPath: string; + requestID: string; + requestURL: string; + requestVerb: string; + responseTime: number; + statusCode: number; + userName: string; + }): void; +} + +export interface IOptions { + host?: string; + path?: string; + port?: number; + // url: string | Url; + // uri: string | Url; + uri: string; + debug?: boolean; + validateStatus?: boolean; + requireValidStatus?: boolean; + requireBodyObject?: string; + timeout?: number; + metricLogger?: IMetricLogger | null; + metricUserName?: string; + metricRequestID?: string; + metricPath?: string; + method: string; + // baseUrl?: string; + // jar?: CookieJar | boolean; + // formData?: { [key: string]: any }; + // form?: { [key: string]: any } | string; + // auth?: AuthOptions; + // oauth?: OAuthOptions; + // aws?: AWSOptions; + // hawk?: HawkOptions; + qs?: unknown; + // qsStringifyOptions?: any; + // qsParseOptions?: any; + json?: unknown; + // jsonReviver?: (key: string, value: any) => any; + // jsonReplacer?: (key: string, value: any) => any; + // multipart?: RequestPart[] | Multipart; + // agent?: http.Agent | https.Agent; + // agentOptions?: http.AgentOptions | https.AgentOptions; + // agentClass?: any; + // forever?: any; + headers?: { [key: string]: string; }; + // body?: any; + // family?: 4 | 6; + // followRedirect?: boolean | ((response: http.IncomingMessage) => boolean); + // followAllRedirects?: boolean; + // followOriginalHttpMethod?: boolean; + // maxRedirects?: number; + // removeRefererHeader?: boolean; + // encoding?: string | null; + // pool?: any; + // localAddress?: string; + // proxy?: any; + // tunnel?: boolean; + // strictSSL?: boolean; + // rejectUnauthorized?: boolean; + // time?: boolean; + // gzip?: boolean; + // preambleCRLF?: boolean; + // postambleCRLF?: boolean; + // withCredentials?: boolean; + // key?: Buffer; + // cert?: Buffer; + // passphrase?: string; + // ca?: string | Buffer | string[] | Buffer[]; + // har?: HttpArchiveRequest; + // useQuerystring?: boolean; +} + +// A 'private' function that does the actual request - here just to prevent me from duplicating code +// to use this class you should use the request or one of the helper functions below +// if a 'logPath' has been specified, a call is sent to the metrics system once the main call is complete to log the time +function _actualRequest(options: IOptions) { + return new Promise<{ + res: Request.Response; + body: T; + }>((res, rej) => { + let process_time = process.hrtime(); + + options.timeout = options.timeout || 20000; + + Request(options, (error: IError, response, body: T) => { + // no matter the result we want to log this remote call + process_time = process.hrtime(process_time); + const process_time_in_seconds = process_time[0] + (process_time[1] / 1e9); + const response_time = parseFloat(process_time_in_seconds.toFixed(3)); + let user_name = ''; // originating user - purely for logging + let request_id = ''; // originating request id - purely for logging + let metric_path = ''; // metric path to identify the specific call being made + let status_code = 0; + + // first handle debugging + if (options.debug) { + console.log('request options:', options); + console.log('response body:', body); + if (response && response.statusCode) { + console.log('response status: ', response.statusCode); + } + } + + // get all the things we will need for logging and error checking + if (response && response.statusCode) { + status_code = response.statusCode; + } + + // if a logger was a specified lets use that and dig out some info to log thats usually specified in the options + // unless a custom logger is specified though nothing will occur here + if (options.metricLogger) { + if (options.metricUserName) { + user_name = options.metricUserName; + } + if (options.metricRequestID) { + request_id = options.metricRequestID; + } + if (options.metricPath) { + metric_path = options.metricPath; + } + + options.metricLogger.logMetric({ + metricPath: metric_path, + requestID: request_id, + requestURL: options.uri, + requestVerb: options.method, + responseTime: response_time, + statusCode: status_code, + userName: user_name + }); + } + + if (error) { + // we got an error straight off the bat - add some extras to it and send back an error + error = _getRequestError(error, response, body, options, response_time); + } else if ((options.validateStatus || options.requireValidStatus) && (status_code <= 199 || status_code >= 300)) { + // We have a response but not the status the options specified - send back an error + error = _getRequestError(error, response, body, options, response_time); + } else if (options.requireBodyObject && _getNestedPropValue(body, options.requireBodyObject, 'nope-nope-nope') === 'nope-nope-nope') { + // we have a response but not the format the options specified - send back an error + error = _getRequestError(error, response, body, options, response_time); + } + + if (!error) { + res({ + body, + res: response + }); + } else { + rej(error); + } + }); + }); +} + +export type Options = Pick>; + +// All functions should mimic functionality of the npm lib 'Request' +// we are adding 2 additional pieces of functionality based on extra 'options' properties +// 1) options.validateStatus will return an error object if status is outside of 2xx range +// 2) options.requireBodyObject will return an error object if the body doesn't contain the given json path/object + +// addtionally if replacing this lib with a custom version to enable logging you can expect the following +// 3 options to always exist -- options.metricUserName, options.metricRequestID and options.metricPath +export async function get(options: Options) { + const { body } = await _actualRequest({ + ...options, + method: 'GET' + }); + return body; +} + +export async function post(options: Options) { + const { body } = await _actualRequest({ + ...options, + method: 'POST' + }); + return body; +} + +export async function patch(options: Options) { + const { body } = await _actualRequest({ + ...options, + method: 'PATCH' + }); + return body; +} + +export async function put(options: Options) { + const { body } = await _actualRequest({ + ...options, + method: 'PUT' + }); + return body; +} + +export async function del(options: Options) { + const { body } = await _actualRequest({ + ...options, + method: 'DELETE' + }); + return body; +} + +export function request(options: IOptions) { + // make the call with the method already set + return _actualRequest(options); +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..4253e04 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,16 @@ +export const default_timeout = 9000; + +export interface IUnknowObject { + [key: string]: unknown; +} + +export function assign(dest: T, optional_keys: string[], src: IUnknowObject) { + // now loop through all the optional ones + for (let n = 0; n < optional_keys.length; n++) { + const key = optional_keys[n]; + if (typeof src[key] !== 'undefined') { + (dest as IUnknowObject)[key] = src[key]; + } + } + return dest; +} diff --git a/test/glance-test.js b/test/glance-test.js index cd2215f..f326302 100644 --- a/test/glance-test.js +++ b/test/glance-test.js @@ -1,161 +1,159 @@ -var Glance = require('../lib/glance.js'); -var glance = new Glance('http://mock_glance_url', 'mock_token'); +const Glance = require('../dist/glance.js').default; +const glance = new Glance('http://mock_glance_url', 'mock_token'); //returns a mock request object for dependency injection with get/post/patch/del methods calling back with the given 3 values -function getMockRequest(return_error, return_status_code, return_response) -{ - function mockVerb(options_array, callback) - { - callback(return_error, {statusCode: return_status_code}, return_response); - } - - var return_object = { - get: mockVerb, - post: mockVerb, - patch: mockVerb, - put: mockVerb, - del: mockVerb - }; - - return return_object; +function getMockRequest(return_error, return_status_code, return_response) { + function mockVerb(options_array, callback) { + // callback(return_error, { statusCode: return_status_code }, return_response); + if (return_error) { + throw return_error; + } else { + return return_response; + } + } + + const return_object = { + get: mockVerb, + post: mockVerb, + patch: mockVerb, + put: mockVerb, + del: mockVerb + }; + + return return_object; } exports.getRequestOptions = { - setUp: function(cb){ - cb(); - }, - - confirmResult: function(test){ - var result = glance.getRequestOptions('/mock_path', {meh: 'meh'}, {extra_header: 'extra_header_value'}); - var expected_result = { - uri: 'http://mock_glance_url/mock_path', - headers:{'X-Auth-Token': 'mock_token', extra_header: 'extra_header_value'}, - json: {meh: 'meh'}, - timeout: 9000, - metricRequestID: '', - metricUserName: '', - metricLogger: null - }; - - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - } + setUp: function (cb) { + cb(); + }, + + confirmResult: function (test) { + const result = glance.getRequestOptions('/mock_path', { meh: 'meh' }, 'a', 'b', { extra_header: 'extra_header_value' }); + const expected_result = { + uri: 'http://mock_glance_url/mock_path', + headers: { 'X-Auth-Token': 'mock_token', extra_header: 'extra_header_value' }, + json: { meh: 'meh' }, + timeout: 9000, + metricPath: 'a', + metricRequestID: '', + metricUserName: '', + metricLogger: null, + requireBodyObject: 'b', + validateStatus: true + }; + + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + } }; exports.listImages = { - setUp: function(cb){ - this.valid_response_body = {images: [{id: 'mock_id'}, {id: 'mock_id2'}]}; - this.valid_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - - cb(); - }, - - confirmImagesOnSuccess: function(test) - { - //stub out request with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - glance.setRequest(mock_request); - - - glance.listImages(function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status but an otherwise valid body (to ensure error on invalid status) - var mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_body); - glance.setRequest(mock_request); - - glance.listImages(function(error, access_token){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { images: [{ id: 'mock_id' }, { id: 'mock_id2' }] }; + this.valid_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + cb(); + }, + + async confirmImagesOnSuccess(test) { + //stub out request with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + glance.setRequest(mock_request); + + + const result = await glance.listImages(); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out request for an invalid status but an otherwise valid body (to ensure error on invalid status) + const mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_body); + glance.setRequest(mock_request); + + try { + await glance.listImages(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getImage = { - setUp: function(cb){ - this.valid_response_body = {id: 'mock_id'}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmImageOnSuccess: function(test) - { - //stub out the request for a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - glance.setRequest(mock_request); - - glance.getImage('mock_id', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status with valid json body (to test the status triggers an error) - var mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_body); - glance.setRequest(mock_request); - - glance.getImage('mock_id', function(error, result){ - test.ok(error, 'We should receive an error'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { id: 'mock_id' }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmImageOnSuccess(test) { + //stub out the request for a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + glance.setRequest(mock_request); + + const result = await glance.getImage('mock_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out request for an invalid status with valid json body (to test the status triggers an error) + const mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_body); + glance.setRequest(mock_request); + + try { + await glance.getImage('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error'); + test.done(); + + } + } }; exports.queueImage = { - setUp: function(cb){ - this.valid_response_body = {id: 'mock_id'}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmImageOnSuccess: function(test) - { - //stub out the request for a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - glance.setRequest(mock_request); - - glance.queueImage({}, function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status with valid json body (to test the status triggers an error) - var mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_body); - glance.setRequest(mock_request); - - glance.queueImage({}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { id: 'mock_id' }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmImageOnSuccess(test) { + //stub out the request for a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + glance.setRequest(mock_request); + + const result = await glance.queueImage({}); + + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status with valid json body (to test the status triggers an error) + const mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_body); + glance.setRequest(mock_request); + + try { + await glance.queueImage({}); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; @@ -165,65 +163,58 @@ exports.queueImage = { exports.updateImage = { - setUp: function(cb){ - this.valid_response_body = {id: 'mock_id'}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmImageOnSuccess: function(test) - { - //stub out request with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - glance.setRequest(mock_request); - - glance.updateImage('mock_id', {}, function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for a 500 with valid json in the body (to ensure the status triggers an error) - var mock_request = getMockRequest(new Error('meh'), 500, 'Our server just borked'); - glance.setRequest(mock_request); - - glance.updateImage('mock_id', {}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { id: 'mock_id' }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmImageOnSuccess(test) { + //stub out request with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + glance.setRequest(mock_request); + + const result = await glance.updateImage('mock_id', {}); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for a 500 with valid json in the body (to ensure the status triggers an error) + const mock_request = getMockRequest(new Error('meh'), 500, 'Our server just borked'); + glance.setRequest(mock_request); + + try { + await glance.updateImage('mock_id', {}); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; - - exports.removeImage = { - confirmNoErrorOnSuccess: function(test) - { - //stub out request with a completely valid response - var mock_request = getMockRequest(null, 200, {}); - glance.setRequest(mock_request); - - glance.removeImage('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out request for a 500 with valid json in the body (to ensure the status triggers an error) - var mock_request = getMockRequest(new Error('meh'), 500, 'Our server just borked'); - glance.setRequest(mock_request); - - glance.removeImage('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnSuccess(test) { + //stub out request with a completely valid response + const mock_request = getMockRequest(null, 200, {}); + glance.setRequest(mock_request); + + await glance.removeImage('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out request for a 500 with valid json in the body (to ensure the status triggers an error) + const mock_request = getMockRequest(new Error('meh'), 500, 'Our server just borked'); + glance.setRequest(mock_request); + + try { + await glance.removeImage('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; diff --git a/test/heat-test.js b/test/heat-test.js index 48a5e6e..93602da 100644 --- a/test/heat-test.js +++ b/test/heat-test.js @@ -1,203 +1,197 @@ -var util = require('util'); -var Heat = require('../lib/heat.js'); -var heat = new Heat('http://mock_heat_url', 'mock_token'); +const Heat = require('../dist/heat.js').default; +const heat = new Heat('http://mock_heat_url', 'mock_token'); //returns a mock request object for dependency injection with get/post/patch/del methods calling back with the given 3 values -function getMockRequest(return_error, return_status_code, return_response) -{ - function mockVerb(options_array, callback) - { - callback(return_error, {statusCode: return_status_code}, return_response); - } - - var return_object = { - get:mockVerb, - post: mockVerb, - patch: mockVerb, - put: mockVerb, - del: mockVerb - }; - - return return_object; +function getMockRequest(return_error, return_status_code, return_response) { + function mockVerb(options_array, callback) { + if (return_error) { + throw return_error; + } else { + return return_response; + } + } + + const return_object = { + get: mockVerb, + post: mockVerb, + patch: mockVerb, + put: mockVerb, + del: mockVerb + }; + + return return_object; } exports.getRequestOptions = { - setUp: function(cb){ - cb(); - }, - - confirmResult: function(test){ - var result = heat.getRequestOptions('/mock_path', {meh: 'meh'}); - var expected_result = { - uri: 'http://mock_heat_url/mock_path', - headers:{'X-Auth-Token': 'mock_token'}, - json: {meh: 'meh'}, - timeout: 9000, - metricRequestID: '', - metricUserName: '', - metricLogger: null - }; - - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - } + setUp: function (cb) { + cb(); + }, + + confirmResult: function (test) { + const result = heat.getRequestOptions('/mock_path', { meh: 'meh' }, 'a', 'b'); + const expected_result = { + uri: 'http://mock_heat_url/mock_path', + headers: { 'X-Auth-Token': 'mock_token' }, + json: { meh: 'meh' }, + timeout: 9000, + metricPath: 'a', + metricRequestID: '', + metricUserName: '', + metricLogger: null, + validateStatus: true + }; + + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + } }; exports.listStacks = { - setUp: function(cb){ - this.valid_response_body = {stacks: [{id: 1}, {id: 2}]}; - this.valid_result = [{id: 1}, {id: 2}]; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - heat.setRequest(mock_request); - - heat.listStacks({}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - heat.setRequest(mock_request); - - heat.listStacks({}, function(error, result){ - test.ok(error, 'We should receive an error object or string'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { stacks: [{ id: 1 }, { id: 2 }] }; + this.valid_result = [{ id: 1 }, { id: 2 }]; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + heat.setRequest(mock_request); + + const result = await heat.listStacks({}); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + heat.setRequest(mock_request); + + try { + await heat.listStacks({}); + } catch (error) { + test.ok(error, 'We should receive an error object or string'); + test.done(); + } + } }; exports.createStack = { - setUp: function(cb){ - this.valid_response_body = {stack: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - heat.setRequest(mock_request); - - const options = { - template_url: "http://mock_template_url" - }; - heat.createStack('mock_stack_name', options, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - heat.setRequest(mock_request); - - const options = { - template_url: "http://mock_template_url" - }; - heat.createStack('mock_stack_name', options, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { stack: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + heat.setRequest(mock_request); + + const options = { + template_url: "http://mock_template_url" + }; + const result = await heat.createStack('mock_stack_name', options); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + heat.setRequest(mock_request); + + const options = { + template_url: "http://mock_template_url" + }; + try { + await heat.createStack('mock_stack_name', options); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateStack = { - setUp: function(cb){ - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}); - heat.setRequest(mock_request); - - const options = { - template_url: "http://mock_template_url" - }; - heat.updateStack('mock_stack_name', 'mock_stack_id', options, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - heat.setRequest(mock_request); - - const options = { - template_url: "http://mock_template_url" - }; - heat.updateStack('mock_stack_name', 'mock_stack_id', options, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_result = {}; + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, {}); + heat.setRequest(mock_request); + + const options = { + template_url: "http://mock_template_url" + }; + const result = await heat.updateStack('mock_stack_name', 'mock_stack_id', options); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + heat.setRequest(mock_request); + + const options = { + template_url: "http://mock_template_url" + }; + try { + await heat.updateStack('mock_stack_name', 'mock_stack_id', options); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.deleteStack = { - setUp: function(cb){ - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}); - heat.setRequest(mock_request); - - heat.deleteStack('mock_stack_name', 'mock_stack_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - heat.setRequest(mock_request); - - heat.deleteStack('mock_stack_name', 'mock_stack_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_result = {}; + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, {}); + heat.setRequest(mock_request); + + const result = await heat.deleteStack('mock_stack_name', 'mock_stack_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + heat.setRequest(mock_request); + + try { + await heat.deleteStack('mock_stack_name', 'mock_stack_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; diff --git a/test/keystone-test.js b/test/keystone-test.js index 7b68b6a..897d867 100644 --- a/test/keystone-test.js +++ b/test/keystone-test.js @@ -1,605 +1,585 @@ -var Keystone = require('../lib/keystone.js'); -var keystone = new Keystone('http://mock_keystone_url'); +const Keystone = require('../dist/keystone.js').default; +const keystone = new Keystone('http://mock_keystone_url'); //returns a mock request object for dependency injection with the get method calling back with the given 3 values -function getMockRequest(return_error, return_status_code, return_headers, return_response) -{ - function mockVerb(options_array, callback) - { - callback(return_error, {statusCode: return_status_code, headers: return_headers}, return_response); - } - - var return_object = { - get: mockVerb, - post: mockVerb, - patch: mockVerb, - put: mockVerb, - del: mockVerb - }; - - return return_object; +function getMockRequest(return_error, return_status_code, return_headers, return_response) { + function mockVerb(options_array) { + if (return_error) { + throw return_error; + } else { + return return_response; + } + } + + function mockVerb2(options_array) { + if (return_error) { + throw return_error; + } else { + return { + res: { + statusCode: return_status_code, + headers: return_headers + }, + body: return_response + }; + } + } + + const return_object = { + get: mockVerb, + post: mockVerb, + request: mockVerb2, + patch: mockVerb, + put: mockVerb, + del: mockVerb + }; + + return return_object; } exports.getRequestOptions = { - setUp: function(cb){ - cb(); - }, - - - confirmResult: function(test){ - var result = keystone.getRequestOptions('mock_token', '/mock_path', {meh: 'meh'}); - var expected_result = { - uri: 'http://mock_keystone_url/mock_path', - headers:{'X-Auth-Token': 'mock_token'}, - json: {meh: 'meh'}, - timeout: 9000, - metricRequestID: '', - metricUserName: '', - metricLogger: null - }; - - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - } + setUp: function (cb) { + cb(); + }, + + + confirmResult(test) { + const result = keystone.getRequestOptions('mock_token', '/mock_path', { meh: 'meh' }, 'a', 'b'); + const expected_result = { + uri: 'http://mock_keystone_url/mock_path', + headers: { 'X-Auth-Token': 'mock_token' }, + json: { meh: 'meh' }, + timeout: 9000, + metricPath: 'a', + metricRequestID: '', + metricUserName: '', + metricLogger: null, + requireBodyObject: 'b', + validateStatus: true + }; + + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + } }; exports.getToken = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_headers = {'x-subject-token': 'token_value'}; - this.valid_response_body = {token: {meh: 'meh'}}; - this.valid_result = {meh: 'meh', token: 'token_value'}; - - cb(); - }, - - - confirmTokenOnSuccess: function(test) - { - //stub out the request for a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_headers, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.getToken('username', 'password', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out request for an automagic 500 with junk text in the body - var mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_headers, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.getToken('username', 'password', function(error, result){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_headers = { 'x-subject-token': 'token_value' }; + this.valid_response_body = { token: { meh: 'meh' } }; + this.valid_result = { meh: 'meh', token: 'token_value' }; + + cb(); + }, + + + async confirmTokenOnSuccess(test) { + //stub out the request for a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_headers, this.valid_response_body); + keystone.setRequest(mock_request); + + const result = await keystone.getToken('username', 'password'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out request for an automagic 500 with junk text in the body + const mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_headers, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.getToken('username', 'password'); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.getProjectToken = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_headers = {'x-subject-token': 'token_value'}; - this.valid_response_body = {token: {meh: 'meh'}}; - this.valid_result = {meh: 'meh', token: 'token_value'}; - - cb(); - }, - - - confirmTokenOnSuccess: function(test) - { - //stub out the request for a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_headers, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.getProjectToken('access_token', 'project_id', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out request for a 500 with a valid header/body (worst case scenario) - var mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_headers, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.getProjectToken("access_token", "project_id", function(error, project_info){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_headers = { 'x-subject-token': 'token_value' }; + this.valid_response_body = { token: { meh: 'meh' } }; + this.valid_result = { meh: 'meh', token: 'token_value' }; + + cb(); + }, + + + async confirmTokenOnSuccess(test) { + //stub out the request for a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_headers, this.valid_response_body); + keystone.setRequest(mock_request); + + const result = await keystone.getProjectToken('access_token', 'project_id'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out request for a 500 with a valid header/body (worst case scenario) + const mock_request = getMockRequest(new Error('meh'), 500, this.valid_response_headers, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.getProjectToken("access_token", "project_id"); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.listProjects = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_body = {links: {self: 'selfurl', previous: null, next: null}, projects: []}; - this.valid_result = []; - this.valid_result.self = 'selfurl'; - this.valid_result.previous = null; - this.valid_result.next = null; - - cb(); - }, - - - confirmProjectsOnSuccess: function(test) - { - //stub out request with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listProjects('accesstoken', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out request for a 500 with a valid body (worst case scenario) - var mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listProjects('accesstoken', function(error, result){ - test.ok(error, "We should receive an error object"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_body = { links: { self: 'selfurl', previous: null, next: null }, projects: [] }; + this.valid_result = []; + this.valid_result.self = 'selfurl'; + this.valid_result.previous = null; + this.valid_result.next = null; + + cb(); + }, + + + async confirmProjectsOnSuccess(test) { + //stub out request with a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, {}, this.valid_response_body); + keystone.setRequest(mock_request); + + const result = await keystone.listProjects('accesstoken'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out request for a 500 with a valid body (worst case scenario) + const mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.listProjects('accesstoken'); + } catch (error) { + test.ok(error, "We should receive an error object"); + test.done(); + } + } }; exports.listUserProjects = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_body = {links: {self: 'selfurl', previous: null, next: null}, projects: []}; - this.valid_result = []; - this.valid_result.self = 'selfurl'; - this.valid_result.previous = null; - this.valid_result.next = null; - - cb(); - }, - - - confirmProjectsOnSuccess: function(test) - { - //stub out request with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listUserProjects('username', 'accesstoken', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for a 500 with a valid body (worst case scenario) - var mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listUserProjects('username', 'accesstoken', function(error, result){ - test.ok(error, "We should receive an error object"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_body = { links: { self: 'selfurl', previous: null, next: null }, projects: [] }; + this.valid_result = []; + this.valid_result.self = 'selfurl'; + this.valid_result.previous = null; + this.valid_result.next = null; + + cb(); + }, + + + async confirmProjectsOnSuccess(test) { + //stub out request with a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, {}, this.valid_response_body); + keystone.setRequest(mock_request); + + const result = await keystone.listUserProjects('username', 'accesstoken'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for a 500 with a valid body (worst case scenario) + const mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.listUserProjects('username', 'accesstoken'); + } catch (error) { + test.ok(error, "We should receive an error object"); + test.done(); + } + } }; exports.getProjectByName = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_body = {links: {self: 'selfurl', previous: null, next: null}, projects: [{meh: 'meh'}]}; - this.valid_result = {meh: 'meh'}; - - cb(); - }, - - confirmProjectsOnSuccess: function(test) - { - //stub out request with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.getProjectByName('accesstoken', 'project_name', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for a 500 with a valid body (worst case scenario) - var mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.getProjectByName('accesstoken', 'project_name', function(error, result){ - test.ok(error, "We should receive an error object"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_body = { links: { self: 'selfurl', previous: null, next: null }, projects: [{ meh: 'meh' }] }; + this.valid_result = { meh: 'meh' }; + + cb(); + }, + + async confirmProjectsOnSuccess(test) { + //stub out request with a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, {}, this.valid_response_body); + keystone.setRequest(mock_request); + + const result = await keystone.getProjectByName('accesstoken', 'project_name'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for a 500 with a valid body (worst case scenario) + const mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.getProjectByName('accesstoken', 'project_name'); + } catch (error) { + test.ok(error, "We should receive an error object"); + test.done(); + } + } }; exports.listRoles = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_body = {links: {self: 'selfurl', previous: null, next: null}, roles: []}; - this.valid_result = []; - this.valid_result.self = 'selfurl'; - this.valid_result.previous = null; - this.valid_result.next = null; - - cb(); - }, - - - confirmRolesOnSuccess: function(test) - { - //stub out request with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listRoles('access_token', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request with an invalid status but a valid body/header - var mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listRoles('accesstoken', function(error, result){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_body = { links: { self: 'selfurl', previous: null, next: null }, roles: [] }; + this.valid_result = []; + this.valid_result.self = 'selfurl'; + this.valid_result.previous = null; + this.valid_result.next = null; + + cb(); + }, + + + async confirmRolesOnSuccess(test) { + //stub out request with a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, {}, this.valid_response_body); + keystone.setRequest(mock_request); + + const result = await keystone.listRoles('access_token'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request with an invalid status but a valid body/header + const mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.listRoles('accesstoken'); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.listRoleAssignments = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_body = {links: {self: 'selfurl', previous: null, next: null}, role_assignments: []}; - this.valid_result = []; - this.valid_result.self = 'selfurl'; - this.valid_result.previous = null; - this.valid_result.next = null; - - cb(); - }, - - - confirmAssignmentsArrayOnSuccess: function(test) - { - //inject request to give a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listRoleAssignments('access_token', 'project_id', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status but with a valid body - var mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); - keystone.setRequest(mock_request); - - keystone.listRoleAssignments('accesstoken', 'project_id', function(error, result){ - test.ok(error, "We should receive an error object"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_body = { links: { self: 'selfurl', previous: null, next: null }, role_assignments: [] }; + this.valid_result = []; + this.valid_result.self = 'selfurl'; + this.valid_result.previous = null; + this.valid_result.next = null; + + cb(); + }, + + + async confirmAssignmentsArrayOnSuccess(test) { + //inject request to give a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, {}, this.valid_response_body); + keystone.setRequest(mock_request); + + const result = await keystone.listRoleAssignments('access_token', 'project_id'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status but with a valid body + const mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.listRoleAssignments('accesstoken', 'project_id'); + } catch (error) { + test.ok(error, "We should receive an error object"); + test.done(); + } + } }; exports.addRoleAssignment = { - setUp: function(cb){ - cb(); - }, - - - confirmObjectOnSuccess: function(test) - { - //stub out a rquest with a valid result - var mock_request = getMockRequest(null, 200, {}, {}); - keystone.setRequest(mock_request); - - keystone.addRoleAssignment('access_token', 'project_id', 'entry_id', 'group', 'role_id', function(error){ - test.ifError(error, 'There should be no error') - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status - var mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); - keystone.setRequest(mock_request); - - keystone.addRoleAssignment('accesstoken', 'project_id', 'entry_id', 'user', 'role_id', function(error){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + + async confirmObjectOnSuccess(test) { + //stub out a rquest with a valid result + const mock_request = getMockRequest(null, 200, {}, {}); + keystone.setRequest(mock_request); + + await keystone.addRoleAssignment('access_token', 'project_id', 'entry_id', 'group', 'role_id'); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status + const mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); + keystone.setRequest(mock_request); + try { + await keystone.addRoleAssignment('accesstoken', 'project_id', 'entry_id', 'user', 'role_id'); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.removeRoleAssignment = { - setUp: function(cb){ - cb(); - }, - - - confirmNoErrorOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {}, {}); - keystone.setRequest(mock_request); - - //stub out a rquest with a valid result - keystone.removeRoleAssignment('access_token', 'project_id', 'entry_id', 'group', 'role_id', function(error){ - test.ifError(error, 'There should be no error') - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status - var mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); - keystone.setRequest(mock_request); - - keystone.removeRoleAssignment('accesstoken', 'project_id', 'entry_id', 'user', 'role_id', function(error){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + + async confirmNoErrorOnSuccess(test) { + const mock_request = getMockRequest(null, 200, {}, {}); + keystone.setRequest(mock_request); + + //stub out a rquest with a valid result + await keystone.removeRoleAssignment('access_token', 'project_id', 'entry_id', 'group', 'role_id'); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status + const mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); + keystone.setRequest(mock_request); + try { + await keystone.removeRoleAssignment('accesstoken', 'project_id', 'entry_id', 'user', 'role_id'); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.listRegions = { - setUp: function(cb){ - //we'll need these a few times so... - this.valid_response_body = { - links: {self: 'selfurl', previous: null, next: null}, - regions: [ - { - "description": "", - "id": "RegionOne", - "links": {"self": "selfurl"}, - "parent_region_id": null - } - ] - }; - - this.valid_result = [ - { - "description": "", - "id": "RegionOne", - "links": {"self": "selfurl"}, - "parent_region_id": null - } - ]; - - this.valid_result.self = 'selfurl'; - this.valid_result.previous = null; - this.valid_result.next = null; - cb(); - }, - - confirmRegionsOnSuccess: function(test) - { - //stub out request with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, {}, this.valid_response_body); - keystone.setRequest(mock_request); - keystone.listRegions('accesstoken', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out request for a 500 with a valid body (worst case scenario) - var mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); - keystone.setRequest(mock_request); - keystone.listRegions('accesstoken', function(error, result){ - test.ok(error, "We should receive an error object"); - test.done(); - }); - } + setUp: function (cb) { + //we'll need these a few times so... + this.valid_response_body = { + links: { self: 'selfurl', previous: null, next: null }, + regions: [ + { + "description": "", + "id": "RegionOne", + "links": { "self": "selfurl" }, + "parent_region_id": null + } + ] + }; + + this.valid_result = [ + { + "description": "", + "id": "RegionOne", + "links": { "self": "selfurl" }, + "parent_region_id": null + } + ]; + + this.valid_result.self = 'selfurl'; + this.valid_result.previous = null; + this.valid_result.next = null; + cb(); + }, + + async confirmRegionsOnSuccess(test) { + //stub out request with a completely valid response + const self = this; + const mock_request = getMockRequest(null, 200, {}, this.valid_response_body); + keystone.setRequest(mock_request); + const result = await keystone.listRegions('accesstoken'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out request for a 500 with a valid body (worst case scenario) + const mock_request = getMockRequest(new Error('meh'), 500, {}, this.valid_response_body); + keystone.setRequest(mock_request); + try { + await keystone.listRegions('accesstoken'); + } catch (error) { + test.ok(error, "We should receive an error object"); + test.done(); + } + } }; exports.listMetaEnvironments = { - setUp: function(cb){ - this.valid_result = [{id: 'DEV', name: 'Development'}]; - cb(); - }, - - - confirmObjectsOnSuccess: function(test) - { - //stub out a rquest with a valid result - var self = this; - var mock_request = getMockRequest(null, 200, {}, {environments: [{id: 'DEV', name: 'Development'}]}); - keystone.setRequest(mock_request); - - keystone.listMetaEnvironments('access_token', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status - var mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); - keystone.setRequest(mock_request); - - keystone.listMetaEnvironments('accesstoken', function(error, result){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + this.valid_result = [{ id: 'DEV', name: 'Development' }]; + cb(); + }, + + + async confirmObjectsOnSuccess(test) { + //stub out a rquest with a valid result + const self = this; + const mock_request = getMockRequest(null, 200, {}, { environments: [{ id: 'DEV', name: 'Development' }] }); + keystone.setRequest(mock_request); + + const result = await keystone.listMetaEnvironments('access_token'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status + const mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); + keystone.setRequest(mock_request); + try { + await keystone.listMetaEnvironments('accesstoken'); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.listMetaOwningGroups = { - setUp: function(cb){ - this.valid_result = [{id: '1 - Group Name', name: 'Group Name'}]; - cb(); - }, - - - confirmObjetsOnSuccess: function(test) - { - //stub out a rquest with a valid result - var self = this; - var mock_request = getMockRequest(null, 200, {}, {owning_groups: [{id: '1 - Group Name', name: 'Group Name'}]}); - keystone.setRequest(mock_request); - - keystone.listMetaOwningGroups('access_token', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, JSON.stringify(result) + '!=' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status - var mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); - keystone.setRequest(mock_request); - - keystone.listMetaOwningGroups('accesstoken', function(error, result){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + this.valid_result = [{ id: '1 - Group Name', name: 'Group Name' }]; + cb(); + }, + + + async confirmObjetsOnSuccess(test) { + //stub out a rquest with a valid result + const self = this; + const mock_request = getMockRequest(null, 200, {}, { owning_groups: [{ id: '1 - Group Name', name: 'Group Name' }] }); + keystone.setRequest(mock_request); + + const result = await keystone.listMetaOwningGroups('access_token'); + test.deepEqual(result, self.valid_result, JSON.stringify(result) + '!=' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status + const mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); + keystone.setRequest(mock_request); + try { + await keystone.listMetaOwningGroups('accesstoken'); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.listProjectMeta = { - setUp: function(cb){ - this.valid_result = {name: 'value'}; - cb(); - }, - - - confirmObjectsOnSuccess: function(test) - { - //stub out a rquest with a valid result - var self = this; - var mock_request = getMockRequest(null, 200, {}, {meta: {name: 'value'}}); - keystone.setRequest(mock_request); - - keystone.listProjectMeta('access_token', 'project_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status - var mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); - keystone.setRequest(mock_request); - - keystone.listProjectMeta('accesstoken', 'project_id', function(error, result){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + this.valid_result = { name: 'value' }; + cb(); + }, + + + async confirmObjectsOnSuccess(test) { + //stub out a rquest with a valid result + const self = this; + const mock_request = getMockRequest(null, 200, {}, { meta: { name: 'value' } }); + keystone.setRequest(mock_request); + + const result = await keystone.listProjectMeta('access_token', 'project_id'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status + const mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); + keystone.setRequest(mock_request); + try { + await keystone.listProjectMeta('accesstoken', 'project_id'); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; exports.updateProjectMeta = { - setUp: function(cb){ - this.valid_result = {name: 'value'}; - cb(); - }, - - - confirmObjectOnSuccess: function(test) - { - //stub out a rquest with a valid result - var self = this; - var mock_request = getMockRequest(null, 200, {}, {meta: {name: 'value'}}); - keystone.setRequest(mock_request); - - keystone.updateProjectMeta('access_token', 'project_id', {environment: 'ENV', owning_group: 'GROUPID'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out request for an invalid status - var mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); - keystone.setRequest(mock_request); - - keystone.updateProjectMeta('accesstoken', 'project_id', {environment: 'ENV', owning_grouop: 'GROUPID'}, function(error, result){ - test.ok(error, "We should receive an error object or string"); - test.done(); - }); - } + setUp: function (cb) { + this.valid_result = { name: 'value' }; + cb(); + }, + + + async confirmObjectOnSuccess(test) { + //stub out a rquest with a valid result + const self = this; + const mock_request = getMockRequest(null, 200, {}, { meta: { name: 'value' } }); + keystone.setRequest(mock_request); + + const result = await keystone.updateProjectMeta('access_token', 'project_id', { environment: 'ENV', owning_group: 'GROUPID' }); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out request for an invalid status + const mock_request = getMockRequest(new Error('meh'), 500, {}, 'Our server just borked'); + keystone.setRequest(mock_request); + + try { + await keystone.updateProjectMeta('accesstoken', 'project_id', { environment: 'ENV', owning_grouop: 'GROUPID' }); + } catch (error) { + test.ok(error, "We should receive an error object or string"); + test.done(); + } + } }; \ No newline at end of file diff --git a/test/neutron-test.js b/test/neutron-test.js index 3009aaa..3af5839 100644 --- a/test/neutron-test.js +++ b/test/neutron-test.js @@ -1,1661 +1,1540 @@ -var util = require('util'); -var Neutron = require('../lib/neutron.js'); -var neutron = new Neutron('http://mock_neutron_url', 'mock_token'); +const Neutron = require('../dist/neutron.js').default; +const neutron = new Neutron('http://mock_neutron_url', 'mock_token'); //returns a mock request object for dependency injection with get/post/patch/del methods calling back with the given 3 values -function getMockRequest(return_error, return_status_code, return_response) -{ - function mockVerb(options_array, callback) - { - callback(return_error, {statusCode: return_status_code}, return_response); - } - - var return_object = { - get:mockVerb, - post: mockVerb, - patch: mockVerb, - put: mockVerb, - del: mockVerb - }; - - return return_object; +function getMockRequest(return_error, return_status_code, return_response) { + function mockVerb(options_array) { + if (return_error) { + throw return_error; + } else { + return return_response; + } + } + + function mockVerb2(options_array) { + if (return_error) { + throw return_error; + } else { + return { + res: { + statusCode: return_status_code, + headers: return_headers + }, + body: return_response + }; + } + } + + const return_object = { + get: mockVerb, + post: mockVerb, + request: mockVerb2, + patch: mockVerb, + put: mockVerb, + del: mockVerb + }; + + return return_object; } - - exports.getRequestOptions = { - setUp: function(cb){ - cb(); - }, - - confirmResult: function(test){ - var result = neutron.getRequestOptions('/mock_path', {meh: 'meh'}); - var expected_result = { - uri: 'http://mock_neutron_url/mock_path', - headers:{'X-Auth-Token': 'mock_token'}, - json: {meh: 'meh'}, - timeout: 9000, - metricRequestID: '', - metricUserName: '', - metricLogger: null - }; - - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - } + setUp: function (cb) { + cb(); + }, + + async confirmResult(test) { + const result = neutron.getRequestOptions('/mock_path', { meh: 'meh' }, 'a', 'b'); + const expected_result = { + uri: 'http://mock_neutron_url/mock_path', + headers: { 'X-Auth-Token': 'mock_token' }, + json: { meh: 'meh' }, + timeout: 9000, + metricPath: 'a', + metricRequestID: '', + metricUserName: '', + metricLogger: null, + requireBodyObject: 'b', + validateStatus: true + }; + + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + } }; exports.listNetworks = { - setUp: function(cb){ - this.valid_response_body = {networks: [{id: 1}, {id: 2}]}; - this.valid_result = [{id: 1}, {id: 2}]; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listNetworks(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listNetworks(function(error, result){ - test.ok(error, 'We should receive an error object or string'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { networks: [{ id: 1 }, { id: 2 }] }; + this.valid_result = [{ id: 1 }, { id: 2 }]; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listNetworks(); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listNetworks(); + } catch (error) { + test.ok(error, 'We should receive an error object or string'); + test.done(); + } + } }; exports.getNetwork = { - setUp: function(cb){ - this.valid_response_body = {network: {id: 1}}; - this.valid_result = {id: 1}; - - cb(); - }, - - confirmFipsOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getNetwork('id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getNetwork('id', function(error, result){ - test.ok(error, 'We should receive an error object or string'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { network: { id: 1 } }; + this.valid_result = { id: 1 }; + + cb(); + }, + + async confirmFipsOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getNetwork('id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getNetwork('id'); + } catch (error) { + test.ok(error, 'We should receive an error object or string'); + test.done(); + } + } }; exports.createFloatingIp = { - setUp: function(cb){ - this.valid_response_body = {floatingip: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createFloatingIp('mock_network_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createFloatingIp('mock_network_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { floatingip: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createFloatingIp('mock_network_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + try { + await neutron.createFloatingIp('mock_network_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listFloatingIps = { - setUp: function(cb){ - this.valid_response_body = {floatingips: [{id: 1}, {id: 2}]}; - this.valid_result = [{id: 1}, {id: 2}]; - - cb(); - }, - - confirmPortsOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listFloatingIps(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmPortsOnSuccessWithOptions: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listFloatingIps({}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listFloatingIps(function(error, result){ - test.ok(error, 'We should receive an error object or string'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { floatingips: [{ id: 1 }, { id: 2 }] }; + this.valid_result = [{ id: 1 }, { id: 2 }]; + + cb(); + }, + + async confirmPortsOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listFloatingIps({}); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmPortsOnSuccessWithOptions(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listFloatingIps({}); + + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listFloatingIps({}); + } catch (error) { + test.ok(error, 'We should receive an error object or string'); + test.done(); + } + } }; exports.getFloatingIp = { - setUp: function(cb){ - this.valid_response_body = {floatingip: {id: 1}}; - this.valid_result = {id: 1}; - - cb(); - }, - - confirmFipsOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getFloatingIp('id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getFloatingIp('id', function(error, result){ - test.ok(error, 'We should receive an error object or string'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { floatingip: { id: 1 } }; + this.valid_result = { id: 1 }; + + cb(); + }, + + async confirmFipsOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getFloatingIp('id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getFloatingIp('id'); + } catch (error) { + test.ok(error, 'We should receive an error object or string'); + test.done(); + } + } }; exports.updateFloatingIp = { - setUp: function(cb){ - this.valid_response_body = {floatingip: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updateFloatingIp('mock_id', 'mock_port_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updateFloatingIp('mock_id', 'mock_port_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { floatingip: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updateFloatingIp('mock_id', 'mock_port_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.updateFloatingIp('mock_id', 'mock_port_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeFloatingIp = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeFloatingIp('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeFloatingIp('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid response + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeFloatingIp('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeFloatingIp('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listPorts = { - setUp: function(cb){ - this.valid_response_body = {ports: [{id: 1}, {id: 2}]}; - this.valid_result = [{id: 1}, {id: 2}]; - - cb(); - }, - - confirmPortsOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listPorts(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmPortsOnSuccessWithOptions: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listPorts({}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listPorts(function(error, result){ - test.ok(error, 'We should receive an error object or string'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { ports: [{ id: 1 }, { id: 2 }] }; + this.valid_result = [{ id: 1 }, { id: 2 }]; + + cb(); + }, + + async confirmPortsOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listPorts({}); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmPortsOnSuccessWithOptions(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listPorts({}); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + try { + await neutron.listPorts(); + } catch (error) { + test.ok(error, 'We should receive an error object or string'); + test.done(); + } + } }; - - exports.updatePort = { - setUp: function(cb){ - this.valid_response_body = {port: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmPortOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updatePort('mock_id', {name: 'mock_name'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updatePort('mock_id', {name: 'mock_name'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { port: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmPortOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updatePort('mock_id', { name: 'mock_name' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + try { + await neutron.updatePort('mock_id', { name: 'mock_name' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listSecurityGroups = { - setUp: function(cb){ - this.valid_response_body = {security_groups: [{}, {}]}; - this.valid_result = [{}, {}]; - - cb(); - }, - - confirmSecurityGroupsOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listSecurityGroups('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listSecurityGroups('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object or string'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { security_groups: [{}, {}] }; + this.valid_result = [{}, {}]; + + cb(); + }, + + async confirmSecurityGroupsOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listSecurityGroups('mock_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listSecurityGroups('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object or string'); + test.done(); + } + } }; exports.getSecurityGroup = { - setUp: function(cb){ - this.valid_response_body = {security_group: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmSecurityGroupOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getSecurityGroup('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getSecurityGroup('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { security_group: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmSecurityGroupOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getSecurityGroup('mock_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getSecurityGroup('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; - - exports.createSecurityGroup = { - setUp: function(cb){ - this.valid_response_body = {security_group: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmSecurityGroupOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createSecurityGroup('mock_name', {description: 'mock_description'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createSecurityGroup('mock_name', {description: 'mock_description'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { security_group: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmSecurityGroupOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createSecurityGroup('mock_name', { description: 'mock_description' }); + + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.createSecurityGroup('mock_name', { description: 'mock_description' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateSecurityGroup = { - setUp: function(cb){ - this.valid_response_body = {security_group: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmSecurityGroupOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updateSecurityGroup('mock_id', {name: 'mock-name'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updateSecurityGroup('mock_id', {name: 'mock-name'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { security_group: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmSecurityGroupOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updateSecurityGroup('mock_id', { name: 'mock-name' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.updateSecurityGroup('mock_id', { name: 'mock-name' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeSecurityGroup = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeSecurityGroup('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeSecurityGroup('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid response + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeSecurityGroup('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeSecurityGroup('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listSecurityGroupRules = { - setUp: function(cb){ - this.valid_response_body = {security_group_rules: [{id: 'mock_id'}, {id: 'mock_id2'}]}; - this.valid_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - - cb(); - }, - - confirmSecurityGroupRulesOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listSecurityGroupRules(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listSecurityGroupRules(function(error, rules_array){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { security_group_rules: [{ id: 'mock_id' }, { id: 'mock_id2' }] }; + this.valid_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + + cb(); + }, + + async confirmSecurityGroupRulesOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listSecurityGroupRules(); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listSecurityGroupRules(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getSecurityGroupRule = { - setUp: function(cb){ - this.valid_response_body = {security_group_rule: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmSecurityGroupRuleOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getSecurityGroupRule('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getSecurityGroupRule('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { security_group_rule: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmSecurityGroupRuleOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getSecurityGroupRule('mock_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getSecurityGroupRule('mock_id') + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.createSecurityGroupRule = { - setUp: function(cb){ - this.valid_response_body = {security_group_rule: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmSecurityGroupRuleOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createSecurityGroupRule('mock_id', {name: 'mock_name', description: 'mock_description'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - //stub out a request with a valid status but an invalid json response body - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createSecurityGroupRule('mock_id', {name: 'mock_name', description: 'mock_description'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { security_group_rule: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmSecurityGroupRuleOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createSecurityGroupRule('mock_id', 'mock_direction', { name: 'mock_name', description: 'mock_description' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + //stub out a request with a valid status but an invalid json response body + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.createSecurityGroupRule('mock_id', { name: 'mock_name', description: 'mock_description' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; //various tests for neutron.securityRule.remove() exports.removeSecurityGroupRule = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid request - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeSecurityGroupRule('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeSecurityGroupRule('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeSecurityGroupRule('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeSecurityGroupRule('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listLoadBalancers = { - setUp: function(cb){ - this.valid_response_body = {loadbalancers: [{id: 'mock_id'}, {id: 'mock_id2'}] - }; - this.valid_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - - cb(); - }, - - confirmLoadBalancersOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listLoadBalancers(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listLoadBalancers(function(error, rules_array){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { + loadbalancers: [{ id: 'mock_id' }, { id: 'mock_id2' }] + }; + this.valid_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + + cb(); + }, + + async confirmLoadBalancersOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listLoadBalancers(); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listLoadBalancers(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getLoadBalancers = { - setUp: function(cb){ - this.valid_response_body = {loadbalancer: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmLoadBalancerOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getLoadBalancer('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getLoadBalancer('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { loadbalancer: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmLoadBalancerOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getLoadBalancer('mock_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getLoadBalancer('mock_id') + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; - exports.createLoadBalancer = { - setUp: function(cb){ - this.valid_response_body = {loadbalancer: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createLoadBalancer('tenant_id', 'vip_subnet_id', {name: 'mock_name'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - //stub out a request with a valid status but an invalid json response body - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createLoadBalancer('tenant_id', 'vip_subnet_id', {name: 'mock_name'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { loadbalancer: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createLoadBalancer('tenant_id', 'vip_subnet_id', { name: 'mock_name' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + //stub out a request with a valid status but an invalid json response body + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.createLoadBalancer('tenant_id', 'vip_subnet_id', { name: 'mock_name' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateLoadBalancer = { - setUp: function(cb){ - this.valid_response_body = {loadbalancer: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updateLoadBalancer('mock_id', {description: 'Updated LB'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updateLoadBalancer('mock_id', {description: 'Updated LB'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { loadbalancer: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updateLoadBalancer('mock_id', { description: 'Updated LB' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.updateLoadBalancer('mock_id', { description: 'Updated LB' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeLoadBalancer = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeLoadBalancer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeLoadBalancer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid response + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeLoadBalancer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeLoadBalancer('mock_id') + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getLBStats = { - setUp: function(cb){ - this.valid_response_body = {stats: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getLBStats('lb_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getLBStats('lb_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { stats: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getLBStats('lb_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + try { + await neutron.getLBStats('lb_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listLBListeners = { - setUp: function(cb){ - this.valid_response_body = {listeners: [{id: 'mock_id'}, {id: 'mock_id2'}]}; - this.valid_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - - cb(); - }, - - confirmLBListenersOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listLBListeners(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listLBListeners(function(error, rules_array){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { listeners: [{ id: 'mock_id' }, { id: 'mock_id2' }] }; + this.valid_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + + cb(); + }, + + async confirmLBListenersOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listLBListeners(); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listLBListeners(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getLBListener = { - setUp: function(cb){ - this.valid_response_body = {listener: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmLBListenerOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getLBListener('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getLBListener('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { listener: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmLBListenerOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getLBListener('mock_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getLBListener('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.createLBListener = { - setUp: function(cb){ - this.valid_response_body = {listener: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createLBListener('tenant_id', 'loadbalancer_id', 'description', 'protocol', {protocol_port: 'mock_protocol_port'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - //stub out a request with a valid status but an invalid json response body - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createLBListener('tenant_id', 'loadbalancer_id', 'description', 'protocol', {protocol_port: 'mock_protocol_port'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { listener: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createLBListener('tenant_id', 'loadbalancer_id', 'description', 'protocol', { protocol_port: 'mock_protocol_port' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + //stub out a request with a valid status but an invalid json response body + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.createLBListener('tenant_id', 'loadbalancer_id', 'description', 'protocol', { protocol_port: 'mock_protocol_port' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateLBListener = { - setUp: function(cb){ - this.valid_response_body = {listener: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updateLBListener('mock_id', {description: 'Updated Listener'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updateLBListener('mock_id', {description: 'Updated Listener'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { listener: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updateLBListener('mock_id', { description: 'Updated Listener' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.updateLBListener('mock_id', { description: 'Updated Listener' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeLBListener = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeLBListener('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeLBListener('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid response + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeLBListener('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeLBListener('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listLBPools = { - setUp: function(cb){ - this.valid_response_body = {pools: [{id: 'mock_id'}, {id: 'mock_id2'}]}; - this.valid_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - - cb(); - }, - - confirmLBPoolsOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listLBPools(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listLBPools(function(error, rules_array){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { pools: [{ id: 'mock_id' }, { id: 'mock_id2' }] }; + this.valid_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + + cb(); + }, + + async confirmLBPoolsOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listLBPools(); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listLBPools(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getLBPool = { - setUp: function(cb){ - this.valid_response_body = {pool: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmPoolOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getLBPool('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getLBPool('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { pool: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmPoolOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getLBPool('mock_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getLBPool('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.createLBPool = { - setUp: function(cb){ - this.valid_response_body = {pool: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createLBPool('tenant_id', 'protocol', 'lb_algorithm', 'listener_id', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createLBPool('tenant_id', 'protocol', 'lb_algorithm', 'listener_id', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { pool: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createLBPool('tenant_id', 'protocol', 'lb_algorithm', 'listener_id', { 'admin_state_up': 'mock_admin_state_up' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.createLBPool('tenant_id', 'protocol', 'lb_algorithm', 'listener_id', { 'admin_state_up': 'mock_admin_state_up' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateLBPool = { - setUp: function(cb){ - this.valid_response_body = {pool: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updateLBPool('mock_id', {description: 'Updated LBPool'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updateLBPool('mock_id', {description: 'Updated LBPool'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { pool: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updateLBPool('mock_id', { description: 'Updated LBPool' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.updateLBPool('mock_id', { description: 'Updated LBPool' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeLBPool = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeLBPool('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeLBPool('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid response + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeLBPool('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeLBPool('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listLBPoolMembers = { - setUp: function(cb){ - this.valid_response_body = {members: [{id: 'mock_id'}, {id: 'mock_id2'}]}; - this.valid_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - - cb(); - }, - - confirmMembersOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listLBPoolMembers('pool_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listLBPoolMembers('pool_id', function(error, rules_array){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { members: [{ id: 'mock_id' }, { id: 'mock_id2' }] }; + this.valid_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + + cb(); + }, + + async confirmMembersOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listLBPoolMembers('pool_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listLBPoolMembers('pool_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getLBPoolMember = { - setUp: function(cb){ - this.valid_response_body = {member: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmMemberOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getLBPoolMember('pool_id', 'member_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getLBPoolMember('pool_id', 'member_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { member: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmMemberOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getLBPoolMember('pool_id', 'member_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getLBPoolMember('pool_id', 'member_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; -exports.createLBPoolMember= { - setUp: function(cb){ - this.valid_response_body = {member: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createLBPoolMember('pool_id', 'tenant_id', 'address', 'protocol_port', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createLBPoolMember('pool_id', 'tenant_id', 'address', 'protocol_port', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } +exports.createLBPoolMember = { + setUp: function (cb) { + this.valid_response_body = { member: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createLBPoolMember('pool_id', 'tenant_id', 'address', 'protocol_port', { 'admin_state_up': 'mock_admin_state_up' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.createLBPoolMember('pool_id', 'tenant_id', 'address', 'protocol_port', { 'admin_state_up': 'mock_admin_state_up' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateLBPoolMember = { - setUp: function(cb){ - this.valid_response_body = {member: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updateLBPoolMember('pool_id', 'member_id', {description: 'Updated LBPool'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updateLBPoolMember('pool_id', 'member_id', {description: 'Updated LBPool'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { member: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updateLBPoolMember('pool_id', 'member_id', { description: 'Updated LBPool' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.updateLBPoolMember('pool_id', 'member_id', { description: 'Updated LBPool' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeLBPoolMember = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeLBPoolMember('pool_id', 'member_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeLBPoolMember('pool_id', 'member_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid response + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeLBPoolMember('pool_id', 'member_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeLBPoolMember('pool_id', 'member_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listLBHealthMonitors = { - setUp: function(cb){ - this.valid_response_body = {healthmonitors: [{id: 'mock_id'}, {id: 'mock_id2'}] - }; - this.valid_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - - cb(); - }, - - confirmMembersOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.listLBHealthMonitors(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.listLBHealthMonitors(function(error, rules_array){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { + healthmonitors: [{ id: 'mock_id' }, { id: 'mock_id2' }] + }; + this.valid_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + + cb(); + }, + + async confirmMembersOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.listLBHealthMonitors(); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.listLBHealthMonitors(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getLBHealthMonitor = { - setUp: function(cb){ - this.valid_response_body = {healthmonitor: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.getLBHealthMonitor('health_monitor_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.getLBHealthMonitor('health_monitor_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { healthmonitor: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.getLBHealthMonitor('health_monitor_id'); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.getLBHealthMonitor('health_monitor_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; -exports.createLBHealthMonitor= { - setUp: function(cb){ - this.valid_response_body = {healthmonitor: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.createLBHealthMonitor('tenant_id', 'type', 'delay', 'timeout', 'max_retries', 'pool_id', {'http_method': 'mock_http_method'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.createLBHealthMonitor('tenant_id', 'type', 'delay', 'timeout', 'max_retries', 'pool_id', {'http_method': 'mock_http_method'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } +exports.createLBHealthMonitor = { + setUp: function (cb) { + this.valid_response_body = { healthmonitor: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a completely valid request + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.createLBHealthMonitor('tenant_id', 'type', 'delay', 'timeout', 'max_retries', 'pool_id', { 'http_method': 'mock_http_method' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.createLBHealthMonitor('tenant_id', 'type', 'delay', 'timeout', 'max_retries', 'pool_id', { 'http_method': 'mock_http_method' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateLBHealthMonitor = { - setUp: function(cb){ - this.valid_response_body = {healthmonitor: {id: 'mock_id'}}; - this.valid_result = {id: 'mock_id'}; - - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - neutron.setRequest(mock_request); - - neutron.updateLBHealthMonitor('health_monitor_id', {delay: 'mock_delay'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.updateLBHealthMonitor('health_monitor_id', {delay: 'mock_delay'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + this.valid_response_body = { healthmonitor: { id: 'mock_id' } }; + this.valid_result = { id: 'mock_id' }; + + cb(); + }, + + async confirmValidResultOnSuccess(test) { + //stub out a request obj with a completely valid response + const mock_request = getMockRequest(null, 200, this.valid_response_body); + neutron.setRequest(mock_request); + + const result = await neutron.updateLBHealthMonitor('health_monitor_id', { delay: 'mock_delay' }); + test.deepEqual(result, this.valid_result, 'result should be ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.updateLBHealthMonitor('health_monitor_id', { delay: 'mock_delay' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeLBHealthMonitor = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); - neutron.setRequest(mock_request); - - neutron.removeLBHealthMonitor('health_monitor_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - neutron.setRequest(mock_request); - - neutron.removeLBHealthMonitor('health_monitor_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp: function (cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + //stub out a completely valid response + const mock_request = getMockRequest(null, 200, ''); + neutron.setRequest(mock_request); + + await neutron.removeLBHealthMonitor('health_monitor_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + neutron.setRequest(mock_request); + + try { + await neutron.removeLBHealthMonitor('health_monitor_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; \ No newline at end of file diff --git a/test/nova-test.js b/test/nova-test.js index 2871331..bb58c72 100644 --- a/test/nova-test.js +++ b/test/nova-test.js @@ -1,1317 +1,1229 @@ -var util = require('util'); -var Nova = require('../lib/nova.js'); -var nova = new Nova('mock_url', 'mock_token'); +const Nova = require('../dist/nova.js').default; +const nova = new Nova('mock_url', 'mock_token'); //returns a mock request object for dependency injection with the get method calling back with the given 3 values -function getMockRequest(return_error, return_status_code, return_response) -{ - function mockVerb(options_array, callback) - { - callback(return_error, {statusCode: return_status_code}, return_response); - } - - var return_object = { - get:mockVerb, - post: mockVerb, - patch: mockVerb, - put: mockVerb, - del: mockVerb - }; - - return return_object; +function getMockRequest(return_error, return_status_code, return_response) { + function mockVerb(options_array) { + if (return_error) { + throw return_error; + } else { + return return_response; + } + } + + function mockVerb2(options_array) { + if (return_error) { + throw return_error; + } else { + return { + res: { + statusCode: return_status_code, + headers: return_headers + }, + body: return_response + }; + } + } + + const return_object = { + get: mockVerb, + post: mockVerb, + request: mockVerb2, + patch: mockVerb, + put: mockVerb, + del: mockVerb + }; + + return return_object; } exports.getRequestOptions = { - setUp: function(cb){ - cb(); - }, - - confirmResult: function(test){ - var result = nova.getRequestOptions('/mock_path', {meh: 'meh'}); - var expected_result = { - uri: 'mock_url/mock_path', - headers:{'X-Auth-Token': 'mock_token'}, - json: {meh: 'meh'}, - timeout: 9000, - metricRequestID: '', - metricUserName: '', - metricLogger: null - }; - - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - } + setUp(cb) { + cb(); + }, + + confirmResult(test) { + const result = nova.getRequestOptions('/mock_path', { meh: 'meh' }, 'a', 'b', true); + const expected_result = { + uri: 'mock_url/mock_path', + headers: { 'X-Auth-Token': 'mock_token' }, + json: { meh: 'meh' }, + timeout: 9000, + metricPath: 'a', + metricRequestID: '', + metricUserName: '', + metricLogger: null, + requireBodyObject: 'b', + validateStatus: true + }; + + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + } }; exports.listServers = { - setUp: function(callback){ - callback(); - }, - - confirmArrayOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {servers:[{status: 'ACTIVE'}]}); - nova.setRequest(mock_request); - - nova.listServers(function(error, result){ - test.ifError(error, 'There should be no error'); - test.equal(result[0].status, 'ACTIVE', 'value should be "ACTIVE"'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.listServers(function(error, result){ - test.ok(error, 'There should be an error object'); - test.done(); - }); - } + setUp(callback) { + callback(); + }, + + async confirmArrayOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { servers: [{ status: 'ACTIVE' }] }); + nova.setRequest(mock_request); + + const result = await nova.listServers(); + test.equal(result[0].status, 'ACTIVE', 'value should be "ACTIVE"'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.listServers(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getServer = { - confirmObjectOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {server:{status: 'ACTIVE'}}); - nova.setRequest(mock_request); - - nova.getServer('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.equal(result.status, 'ACTIVE', 'value should be "ACTIVE"'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getServer('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmObjectOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { server: { status: 'ACTIVE' } }); + nova.setRequest(mock_request); + + const result = await nova.getServer('mock_id'); + test.equal(result.status, 'ACTIVE', 'value should be "ACTIVE"'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.createServer = { - confirmObjectOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {server:{status: 'ACTIVE'}}); - nova.setRequest(mock_request); - - nova.createServer('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.equal(result.status, 'ACTIVE', 'value should be "ACTIVE"'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.createServer('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmObjectOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { server: { status: 'ACTIVE' } }); + nova.setRequest(mock_request); + + const result = await nova.createServer('mock_id'); + test.equal(result.status, 'ACTIVE', 'value should be "ACTIVE"'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.createServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.renameServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock_response'); - nova.setRequest(mock_request); - - nova.renameServer('mock_id', 'mock_name', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.renameServer('mock_id', 'mock_name', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock_response'); + nova.setRequest(mock_request); + + await nova.renameServer('mock_id', 'mock_name'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.renameServer('mock_id', 'mock_name'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.resizeServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock_response'); - nova.setRequest(mock_request); - - nova.resizeServer('mock_id', 'mock_flavor_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.resizeServer('mock_id', 'mock_flavor_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock_response'); + nova.setRequest(mock_request); + + await nova.resizeServer('mock_id', 'mock_flavor_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.resizeServer('mock_id', 'mock_flavor_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.confirmResizeServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock_response'); - nova.setRequest(mock_request); - - nova.confirmResizeServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.confirmResizeServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock_response'); + nova.setRequest(mock_request); + + await nova.confirmResizeServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.confirmResizeServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.revertResizeServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock_response'); - nova.setRequest(mock_request); - - nova.revertResizeServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.revertResizeServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock_response'); + nova.setRequest(mock_request); + + await nova.revertResizeServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.revertResizeServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock response'); - nova.setRequest(mock_request); - - nova.removeServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.removeServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock response'); + nova.setRequest(mock_request); + + await nova.removeServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.removeServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.rebootServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock response'); - nova.setRequest(mock_request); - - nova.rebootServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.rebootServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock response'); + nova.setRequest(mock_request); + + await nova.rebootServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.rebootServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.forceRebootServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock response'); - nova.setRequest(mock_request); - - nova.forceRebootServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.forceRebootServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock response'); + nova.setRequest(mock_request); + + await nova.forceRebootServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.forceRebootServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.stopServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock response'); - nova.setRequest(mock_request); - - nova.stopServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.stopServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock response'); + nova.setRequest(mock_request); + + await nova.stopServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.stopServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.startServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, 'mock response'); - nova.setRequest(mock_request); - - nova.startServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.startServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, 'mock response'); + nova.setRequest(mock_request); + + await nova.startServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.startServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.pauseServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, {meh: 'meh'}); - nova.setRequest(mock_request); - - nova.pauseServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.pauseServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, { meh: 'meh' }); + nova.setRequest(mock_request); + + await nova.pauseServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.pauseServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.suspendServer = { - confirmNoErrorOnValidStatus: function(test) - { - var mock_request = getMockRequest(null, 200, {meh: 'meh'}); - nova.setRequest(mock_request); - - nova.suspendServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.suspendServer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnValidStatus(test) { + const mock_request = getMockRequest(null, 200, { meh: 'meh' }); + nova.setRequest(mock_request); + + await nova.suspendServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.suspendServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.resumeServer = { - confirmNoErrorOnSuccess: function(test) - { - //can't use the normal getMockRequest here as there are actually 2 requests in this function - //first a get in getById then a post in the actual function - var mock_request = { - get: function(options_array, callback){ - callback(null, {statusCode: 200}, {server: {status: 'PAUSED'}}); - }, - post: function(options_array, callback){ - callback(null, {statusCode: 200}, {meh: 'meh'}); - } - }; - nova.setRequest(mock_request); - - nova.resumeServer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.resumeServer('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnSuccess(test) { + //can't use the normal getMockRequest here as there are actually 2 requests in this function + //first a get in getById then a post in the actual function + const mock_request = { + get: function (options_array, callback) { + return { server: { status: 'PAUSED' } }; + }, + post: function (options_array, callback) { + return { meh: 'meh' }; + } + }; + nova.setRequest(mock_request); + + await nova.resumeServer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.resumeServer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getServerConsoleUrl = { - confirmURLOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {console: {url: 'http://something'}}); - nova.setRequest(mock_request); - - nova.getServerConsoleURL('mock-type', 'mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.equal(result, 'http://something', 'value should be boolean "http://something"'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getServerConsoleURL('mock-type', 'mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmURLOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { console: { url: 'http://something' } }); + nova.setRequest(mock_request); + + const result = await nova.getServerConsoleURL('mock-type', 'mock_id'); + test.equal(result, 'http://something', 'value should be boolean "http://something"'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getServerConsoleURL('mock-type', 'mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getServerLog = { - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getServerLog('mock_id', 50, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + + try { + await nova.getServerLog('mock_id', 50); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.createServerImage = { - confirmResponseOnSuccessOldNova: function(test) - { - var mock_request = { - post: function(options_array, callback){ - callback(null, {statusCode: 200, headers: {location: '/images/mock_id'}}, {output: {result: 'result'}}); - } - }; - nova.setRequest(mock_request); - - nova.createServerImage('mock_id', {meh: 'meh'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual({image_id: 'mock_id'}, result, 'value should be {image_id: "mock_id"}'); - test.done(); - }); - }, - - confirmResponseOnSuccessNewNova: function(test) - { - var mock_request = { - post: function(options_array, callback){ - callback(null, {statusCode: 200}, {image_id: 'mock_id'}); - } - }; - nova.setRequest(mock_request); - - nova.createServerImage('mock_id', {meh: 'meh'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual({image_id: 'mock_id'}, result, 'value should be {image_id: "mock_id"}'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.createServerImage('mock_id', {meh: 'meh'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmResponseOnSuccessOldNova(test) { + const mock_request = { + request(options_array, callback) { + return { + res: { statusCode: 200, headers: { location: '/images/mock_id' } }, + body: { + output: { result: 'result' } + } + }; + } + }; + nova.setRequest(mock_request); + + const result = await nova.createServerImage('mock_id', { meh: 'meh' }); + test.deepEqual({ image_id: 'mock_id' }, result, 'value should be {image_id: "mock_id"}'); + test.done(); + }, + + async confirmResponseOnSuccessNewNova(test) { + const mock_request = { + request: function (options_array, callback) { + return { + body: { + image_id: 'mock_id' + } + }; + } + }; + nova.setRequest(mock_request); + + const result = await nova.createServerImage('mock_id', { meh: 'meh' }); + test.deepEqual({ image_id: 'mock_id' }, result, 'value should be {image_id: "mock_id"}'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.createServerImage('mock_id', { meh: 'meh' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; //tests Nova.Instance.setMetadata() exports.setServerMetadata = { - confirmResponseOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {x:'x'}); - nova.setRequest(mock_request); - - nova.setServerMetadata('mock_id', {meh: 'meh'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual({x:'x'}, result, 'value should be {x: "x"}'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.setServerMetadata('mock_id', {meh: 'meh'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmResponseOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { x: 'x' }); + nova.setRequest(mock_request); + + const result = await nova.setServerMetadata('mock_id', { meh: 'meh' }); + test.deepEqual({ x: 'x' }, result, 'value should be {x: "x"}'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.setServerMetadata('mock_id', { meh: 'meh' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listFlavors = { - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.listFlavors(function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.listFlavors(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getFlavor = { - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getFlavor("id", function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + + try { + await nova.getFlavor("id"); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listProjectNetworks = { - setUp: function(cb) - { - this.valid_response_body = { - networks: [ - { - "cidr": "10.0.0.0/29", - "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", - "label": "test_0" - }, - { - "cidr": "10.0.0.8/29", - "id": "616fb98f-46ca-475e-917e-2563e5a8cd20", - "label": "test_1" - } - ] - }; - - this.valid_result = [ - { - "cidr": "10.0.0.0/29", - "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", - "label": "test_0" - }, - { - "cidr": "10.0.0.8/29", - "id": "616fb98f-46ca-475e-917e-2563e5a8cd20", - "label": "test_1" - } - ]; - - cb(); - }, - - confirmArrayValuesOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - nova.listProjectNetworks(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'value should match object: ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - nova.listProjectNetworks(function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { + networks: [ + { + "cidr": "10.0.0.0/29", + "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", + "label": "test_0" + }, + { + "cidr": "10.0.0.8/29", + "id": "616fb98f-46ca-475e-917e-2563e5a8cd20", + "label": "test_1" + } + ] + }; + + this.valid_result = [ + { + "cidr": "10.0.0.0/29", + "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", + "label": "test_0" + }, + { + "cidr": "10.0.0.8/29", + "id": "616fb98f-46ca-475e-917e-2563e5a8cd20", + "label": "test_1" + } + ]; + + cb(); + }, + + async confirmArrayValuesOnSuccess(test) { + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + const result = await nova.listProjectNetworks(); + test.deepEqual(result, self.valid_result, 'value should match object: ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.listProjectNetworks(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.floatinglistFloatingIpsip_list = { - confirmArrayOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {floating_ips:[{status: 'ACTIVE'}]}); - nova.setRequest(mock_request); - - nova.listFloatingIps(function(error, result){ - test.ifError(error, 'There should be no error'); - test.equal(result[0].status, 'ACTIVE', 'value should be "ACTIVE"'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.listFloatingIps(function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmArrayOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { floating_ips: [{ status: 'ACTIVE' }] }); + nova.setRequest(mock_request); + + const result = await nova.listFloatingIps(); + test.equal(result[0].status, 'ACTIVE', 'value should be "ACTIVE"'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.listFloatingIps(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getFloatingIp = { - confirmObjectOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {floating_ip: {meh: 'meh'}}); - nova.setRequest(mock_request); - - nova.getFloatingIp('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, {meh: 'meh'}, 'value should be an object {meh: "meh"}'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getFloatingIp("id", function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmObjectOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { floating_ip: { meh: 'meh' } }); + nova.setRequest(mock_request); + + const result = await nova.getFloatingIp('mock_id'); + test.deepEqual(result, { meh: 'meh' }, 'value should be an object {meh: "meh"}'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getFloatingIp("id"); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.createFloatingIp = { - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.createFloatingIp({}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.createFloatingIp({}); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeFloatingIp = { - confirmNoErrorOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, true); - nova.setRequest(mock_request); - - nova.removeFloatingIp('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.removeFloatingIp("id", function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnSuccess(test) { + const mock_request = getMockRequest(null, 200, true); + nova.setRequest(mock_request); + + await nova.removeFloatingIp('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.removeFloatingIp("id"); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.associateFloatingIp = { - confirmNoErrorOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 204, true); - nova.setRequest(mock_request); - - nova.associateFloatingIp('mock_id', 'mock-address', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.associateFloatingIp("mock_id", 'mock-address', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnSuccess(test) { + const mock_request = getMockRequest(null, 204, true); + nova.setRequest(mock_request); + + await nova.associateFloatingIp('mock_id', 'mock-address'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.associateFloatingIp("mock_id", 'mock-address'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.disassociateFloatingIp = { - confirmNoErrorOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 204, true); - nova.setRequest(mock_request); - - nova.disassociateFloatingIp('mock_id', 'mock-address', function(error, result){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.disassociateFloatingIp("mock_id", 'mock-address', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOnSuccess(test) { + const mock_request = getMockRequest(null, 204, true); + nova.setRequest(mock_request); + + await nova.disassociateFloatingIp('mock_id', 'mock-address'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.disassociateFloatingIp("mock_id", 'mock-address'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listFloatingIpPools = { - setUp: function(cb){ - this.valid_response_body = {floating_ip_pools: [{name: 'mock_id'}]}; - this.valid_result = [{name: 'mock_id'}]; - - cb(); - }, - - confirmArrayOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.listFloatingIpPools(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.listFloatingIpPools(function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { floating_ip_pools: [{ name: 'mock_id' }] }; + this.valid_result = [{ name: 'mock_id' }]; + + cb(); + }, + + async confirmArrayOnSuccess(test) { + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.listFloatingIpPools(); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.listFloatingIpPools(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getFloatingIpPool = { - setUp: function(cb){ - //this function will actually call listIpPools so use a valid response body for that - this.valid_response_body = {floating_ip_pools: [{name: 'mock_id'}]}; - //just need the individual matching object though for the valid result check - this.valid_result = {name: 'mock_id'}; - - cb(); - }, - - - confirmObjectOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.getFloatingIpPool('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getFloatingIpPool("not-testid", function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + //this function will actually call listIpPools so use a valid response body for that + this.valid_response_body = { floating_ip_pools: [{ name: 'mock_id' }] }; + //just need the individual matching object though for the valid result check + this.valid_result = { name: 'mock_id' }; + + cb(); + }, + + + async confirmObjectOnSuccess(test) { + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.getFloatingIpPool('mock_id'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getFloatingIpPool("not-testid"); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listAvailabilityZones = { - setUp: function(cb){ - this.valid_response_body = {availabilityZoneInfo:[{zoneName: 'mock_name1'}, {zoneName: 'mock_name2'}]}; - this.valid_result = [{zoneName: 'mock_name1'}, {zoneName: 'mock_name2'}]; - - cb(); - }, - - confirmArrayValuesOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.listAvailabilityZones(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'value should match object: ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.listAvailabilityZones(function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { availabilityZoneInfo: [{ zoneName: 'mock_name1' }, { zoneName: 'mock_name2' }] }; + this.valid_result = [{ zoneName: 'mock_name1' }, { zoneName: 'mock_name2' }]; + + cb(); + }, + + async confirmArrayValuesOnSuccess(test) { + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.listAvailabilityZones(); + test.deepEqual(result, self.valid_result, 'value should match object: ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.listAvailabilityZones(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getAvailabilityZone = { - setUp: function(cb){ - this.valid_response_body = {availabilityZoneInfo:[{zoneName: 'mock_name'}, {zoneName: 'mock_name2'}]}; - this.valid_result = {zoneName: 'mock_name'}; - - cb(); - }, - - confirmObjectOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.getAvailabilityZone('mock_name', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'value should be an object: ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getAvailabilityZone("not-testname", function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { availabilityZoneInfo: [{ zoneName: 'mock_name' }, { zoneName: 'mock_name2' }] }; + this.valid_result = { zoneName: 'mock_name' }; + + cb(); + }, + + async confirmObjectOnSuccess(test) { + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.getAvailabilityZone('mock_name'); + test.deepEqual(result, self.valid_result, 'value should be an object: ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getAvailabilityZone("not-testname"); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.listKeyPairs = { - setUp: function(cb){ - this.valid_response_body = {keypairs:[{keypair: {name: 'mock_name'}}, {keypair: {name: 'mock_name2'}}]}; - this.valid_result = [{name: 'mock_name'}, {name: 'mock_name2'}]; - - cb(); - }, - - confirmArrayValuesOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.listKeyPairs(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'value should match object: ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.listKeyPairs(function(error, result){ - test.ok(error, 'Should be an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { keypairs: [{ keypair: { name: 'mock_name' } }, { keypair: { name: 'mock_name2' } }] }; + this.valid_result = [{ name: 'mock_name' }, { name: 'mock_name2' }]; + + cb(); + }, + + async confirmArrayValuesOnSuccess(test) { + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.listKeyPairs(); + test.deepEqual(result, this.valid_result, 'value should match object: ' + JSON.stringify(this.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.listKeyPairs(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getKeyPair = { - confirmObjectOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {keypair: {meh: 'meh'}}); - nova.setRequest(mock_request); - - nova.getKeyPair('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, {meh: 'meh'}, 'value should be an object {meh: "meh"}'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getKeyPair('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmObjectOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { keypair: { meh: 'meh' } }); + nova.setRequest(mock_request); + + const result = await nova.getKeyPair('mock_id'); + test.deepEqual(result, { meh: 'meh' }, 'value should be an object {meh: "meh"}'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getKeyPair('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.createKeyPair = { - confirmObjectOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {keypair: {meh: 'meh'}}); - nova.setRequest(mock_request); - - nova.createKeyPair('mock_name', 'mock-key', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, {meh: 'meh'}, 'value should be an object {meh: "meh"}'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.createKeyPair('mock_name', 'mock-key', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmObjectOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { keypair: { meh: 'meh' } }); + nova.setRequest(mock_request); + + const result = await nova.createKeyPair('mock_name', 'mock-key'); + test.deepEqual(result, { meh: 'meh' }, 'value should be an object {meh: "meh"}'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.createKeyPair('mock_name', 'mock-key'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeKeyPair = { - confirmSuccessOn200: function(test) - { - var mock_request = getMockRequest(null, 200, {keypair: {meh: 'meh'}}); - nova.setRequest(mock_request); - - nova.removeKeyPair('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - //I think thats all we can test for... - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.removeKeyPair('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmSuccessOn200(test) { + const mock_request = getMockRequest(null, 200, { keypair: { meh: 'meh' } }); + nova.setRequest(mock_request); + + await nova.removeKeyPair('mock_id'); + //I think thats all we can test for... + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + + try { + await nova.removeKeyPair('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getQuotaSet = { - setUp: function(cb){ - this.valid_response_body = {quota_set: {ram: 1234}}; - this.valid_result = {ram: 1234}; - - cb(); - }, - - confirmValueOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.getQuotaSet('mock_id', function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getQuotaSet('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { quota_set: { ram: 1234 } }; + this.valid_result = { ram: 1234 }; + + cb(); + }, + + async confirmValueOnSuccess(test) { + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.getQuotaSet('mock_id'); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getQuotaSet('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.setQuotaSet = { - setUp: function(cb){ - this.valid_response_body = {quota_set: {ram: 1234}}; - this.valid_result = {ram: 1234}; - - cb(); - }, - - confirmValueOnSuccess: function(test) - { - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.setQuotaSet('mock_id', {ram: 1234}, function(error, result){ - test.ifError(error, 'There should be no error') - test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.setQuotaSet('mock_id', {}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { quota_set: { ram: 1234 } }; + this.valid_result = { ram: 1234 }; + + cb(); + }, + + async confirmValueOnSuccess(test) { + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.setQuotaSet('mock_id', { ram: 1234 }); + test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.setQuotaSet('mock_id', {}); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getTenantUsage = { - setUp: function(cb){ - this.valid_response_body = {tenant_usage: {total_hours: 3.14167}}; - this.valid_result = {total_hours: 3.14167}; - - cb(); - }, - - confirmTenantUsageOnSuccess: function(test) - { - var self = this; - var start_date = new Date(); - var end_date = new Date(); - var mock_request = getMockRequest(null, 200, this.valid_response_body); - nova.setRequest(mock_request); - - nova.getTenantUsage('mock_id', start_date, end_date, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, self.valid_result, 'value should be an object: ' + JSON.stringify(self.valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - var start_date = new Date(); - var end_date = new Date(); - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getTenantUsage('mock_id', start_date, end_date, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + this.valid_response_body = { tenant_usage: { total_hours: 3.14167 } }; + this.valid_result = { total_hours: 3.14167 }; + + cb(); + }, + + async confirmTenantUsageOnSuccess(test) { + const self = this; + const start_date = new Date(); + const end_date = new Date(); + const mock_request = getMockRequest(null, 200, this.valid_response_body); + nova.setRequest(mock_request); + + const result = await nova.getTenantUsage('mock_id', start_date, end_date); + test.deepEqual(result, self.valid_result, 'value should be an object: ' + JSON.stringify(self.valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + const start_date = new Date(); + const end_date = new Date(); + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getTenantUsage('mock_id', start_date, end_date); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.assignSecurityGroup = { - confirmNoErrorOn200: function(test) - { - var mock_request = getMockRequest(null, 200, {meh: 'meh'}); - nova.setRequest(mock_request); - - nova.assignSecurityGroup('mock_name', 'mock_id', function(error, response){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.assignSecurityGroup('mock_name', 'mock_id', function(error, response){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmNoErrorOn200(test) { + const mock_request = getMockRequest(null, 200, { meh: 'meh' }); + nova.setRequest(mock_request); + + await nova.assignSecurityGroup('mock_name', 'mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + + try { + await nova.assignSecurityGroup('mock_name', 'mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeSecurityGroup = { - confirmValuesOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {meh: 'meh'}); - nova.setRequest(mock_request); - - nova.removeSecurityGroup('mock_name', 'mock_id', function(error, response){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOn5Error: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.removeSecurityGroup('mock_name', 'mock_id', function(error, response){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmValuesOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { meh: 'meh' }); + nova.setRequest(mock_request); + + await nova.removeSecurityGroup('mock_name', 'mock_id'); + test.done(); + }, + + async confirmErrorOn5Error(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.removeSecurityGroup('mock_name', 'mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getImageMetaData = { - confirmResponseOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {metadata: {x:'x'}}); - nova.setRequest(mock_request); - - nova.getImageMetaData('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual({x:'x'}, result, 'value should be {x: "x"}'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.getImageMetaData('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmResponseOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { metadata: { x: 'x' } }); + nova.setRequest(mock_request); + + const result = await nova.getImageMetaData('mock_id'); + test.deepEqual({ x: 'x' }, result, 'value should be {x: "x"}'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + try { + await nova.getImageMetaData('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.setImageMetadata = { - confirmResponseOnSuccess: function(test) - { - var mock_request = getMockRequest(null, 200, {metadata: {x:'x'}}); - nova.setRequest(mock_request); - - nova.setImageMetaData('mock_id', {meh: 'meh'}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual({x:'x'}, result, 'value should be {x: "x"}'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); - nova.setRequest(mock_request); - - nova.setImageMetaData('mock_id', {meh: 'meh'}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + async confirmResponseOnSuccess(test) { + const mock_request = getMockRequest(null, 200, { metadata: { x: 'x' } }); + nova.setRequest(mock_request); + + const result = await nova.setImageMetaData('mock_id', { meh: 'meh' }); + test.deepEqual({ x: 'x' }, result, 'value should be {x: "x"}'); + test.done(); + }, + + async confirmErrorOnError(test) { + //stub out some junk with an error + const mock_request = getMockRequest(new Error('meh'), 500, {}); + nova.setRequest(mock_request); + + try { + await nova.setImageMetaData('mock_id', { meh: 'meh' }); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; diff --git a/test/octavia-test.js b/test/octavia-test.js index ac82782..c746e87 100644 --- a/test/octavia-test.js +++ b/test/octavia-test.js @@ -1,244 +1,217 @@ -var rewire = require("rewire"); -var Octavia = rewire('../lib/octavia.js'); - +const Octavia = require('../dist/octavia.js').default; +const octavia = new Octavia('http://mock_url', 'mock_token'); exports.getRequestOptions = { - setUp: function(cb){ - cb(); - }, - - confirmResult: function(test){ - var octavia = new Octavia('http://mock_url', 'mock_token'); - var result = octavia.getRequestOptions('/mock_path', {meh: 'meh'}); - var expected_result = { - uri: 'http://mock_url/mock_path', - headers:{'X-Auth-Token': 'mock_token'}, - json: {meh: 'meh'}, - timeout: 9000, - metricRequestID: '', - metricUserName: '', - metricLogger: null - }; - - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - } + setUp(cb) { + cb(); + }, + + confirmResult(test) { + const result = octavia.getRequestOptions('/mock_path', { meh: 'meh' }, 'a', 'b'); + const expected_result = { + uri: 'http://mock_url/mock_path', + headers: { 'X-Auth-Token': 'mock_token' }, + json: { meh: 'meh' }, + timeout: 9000, + metricPath: 'a', + metricRequestID: '', + metricUserName: '', + metricLogger: null, + requireBodyObject: 'b', + validateStatus: true + }; + + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + } }; exports.listLoadBalancers = { - setUp: function(cb){ - cb(); - }, - - confirmLoadBalancersOnSuccess: function(test) - { - var valid_response_body = {loadbalancers: [{id: 'mock_id'}, {id: 'mock_id2'}]}; - var expected_result = [{id: 'mock_id'}, {id: 'mock_id2'}]; - var mock_request = { - get: function(options, cb){ - cb(null, {}, valid_response_body); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - octavia.listLoadBalancers(function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - var mock_request = { - get: function(options, cb){ - cb(new Error('meh')); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - - octavia.listLoadBalancers(function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + cb(); + }, + + async confirmLoadBalancersOnSuccess(test) { + const valid_response_body = { loadbalancers: [{ id: 'mock_id' }, { id: 'mock_id2' }] }; + const expected_result = [{ id: 'mock_id' }, { id: 'mock_id2' }]; + const mock_request = { + get: function (options, cb) { + return valid_response_body; + } + }; + + octavia.setRequest(mock_request); + const result = await octavia.listLoadBalancers(); + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + const mock_request = { + get: function (options, cb) { + throw new Error('meh'); + } + }; + octavia.setRequest(mock_request); + try { + await octavia.listLoadBalancers(); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.getLoadBalancers = { - setUp: function(cb){ - cb(); - }, - - confirmLoadBalancerOnSuccess: function(test) - { - var valid_response_body = {loadbalancer: {id: 'mock_id'}}; - var expected_result = {id: 'mock_id'}; - var mock_request = { - get: function(options, cb){ - cb(null, {}, valid_response_body); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - - octavia.getLoadBalancer('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - var mock_request = { - get: function(options, cb){ - cb(new Error('meh')); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - octavia.getLoadBalancer('mock_id', function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + cb(); + }, + + async confirmLoadBalancerOnSuccess(test) { + const valid_response_body = { loadbalancer: { id: 'mock_id' } }; + const expected_result = { id: 'mock_id' }; + const mock_request = { + get: function (options, cb) { + return valid_response_body; + } + }; + octavia.setRequest(mock_request); + + const result = await octavia.getLoadBalancer('mock_id'); + test.deepEqual(result, expected_result, 'result should be ' + JSON.stringify(expected_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + const mock_request = { + get: function (options, cb) { + cb(new Error('meh')); + } + }; + octavia.setRequest(mock_request); + try { + await octavia.getLoadBalancer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; - - exports.createLoadBalancer = { - setUp: function(cb){ - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - var valid_response_body = {loadbalancer: {id: 'mock_id'}}; - var valid_result = {id: 'mock_id'}; - var mock_request = { - post: function(options, cb){ - cb(null, {}, valid_response_body); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - octavia.createLoadBalancer('mock_project_id', {}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, valid_result, 'result should be ' + JSON.stringify(valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - var mock_request = { - post: function(options, cb){ - cb(new Error('mock'), {}, null); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - octavia.createLoadBalancer('mock_project_id', {}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + cb(); + }, + + async confirmValidResultOnSuccess(test) { + const valid_response_body = { loadbalancer: { id: 'mock_id' } }; + const valid_result = { id: 'mock_id' }; + const mock_request = { + post: function (options, cb) { + return valid_response_body; + } + }; + octavia.setRequest(mock_request); + + const result = await octavia.createLoadBalancer('mock_project_id', {}); + test.deepEqual(result, valid_result, 'result should be ' + JSON.stringify(valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + const mock_request = { + post: function (options, cb) { + throw new Error('mock'); + } + }; + octavia.setRequest(mock_request); + try { + await octavia.createLoadBalancer('mock_project_id', {}); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.updateLoadBalancer = { - setUp: function(cb){ - cb(); - }, - - confirmValidResultOnSuccess: function(test) - { - var valid_response_body = {loadbalancer: {id: 'mock_id'}}; - var valid_result = {id: 'mock_id'}; - - var mock_request = { - put: function(options, cb){ - cb(null, {}, valid_response_body); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - octavia.updateLoadBalancer('mock_id', {}, function(error, result){ - test.ifError(error, 'There should be no error'); - test.deepEqual(result, valid_result, 'result should be ' + JSON.stringify(valid_result)); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - var mock_request = { - put: function(options, cb){ - cb(new Error('mock'), null, null); - } - }; - - Octavia.__set__('Request', mock_request); - var octavia = new Octavia('http://mock_url', 'mock_token'); - - octavia.updateLoadBalancer('mock_id', {}, function(error, result){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + cb(); + }, + + async confirmValidResultOnSuccess(test) { + const valid_response_body = { loadbalancer: { id: 'mock_id' } }; + const valid_result = { id: 'mock_id' }; + + const mock_request = { + put: function (options, cb) { + return valid_response_body; + } + }; + octavia.setRequest(mock_request); + + const result = await octavia.updateLoadBalancer('mock_id', {}); + test.deepEqual(result, valid_result, 'result should be ' + JSON.stringify(valid_result)); + test.done(); + }, + + async confirmErrorOnError(test) { + const mock_request = { + put: function (options, cb) { + throw new Error('mock'); + } + }; + + octavia.setRequest(mock_request); + try { + await octavia.updateLoadBalancer('mock_id', {}); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; exports.removeLoadBalancer = { - setUp: function(cb){ - cb(); - }, - - confirmNoErrorOnSuccess: function(test) - { - var mock_request = { - del: function(options, cb){ - cb(null, {}, {}); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - octavia.removeLoadBalancer('mock_id', function(error){ - test.ifError(error, 'There should be no error'); - test.done(); - }); - }, - - confirmErrorOnError: function(test) - { - var mock_request = { - del: function(options, cb){ - cb(new Error('mock'), null, null); - } - }; - Octavia.__set__('Request', mock_request); - - var octavia = new Octavia('http://mock_url', 'mock_token'); - octavia.removeLoadBalancer('mock_id', function(error){ - test.ok(error, 'We should receive an error object'); - test.done(); - }); - } + setUp(cb) { + cb(); + }, + + async confirmNoErrorOnSuccess(test) { + const mock_request = { + del: function (options, cb) { + return {}; + } + }; + octavia.setRequest(mock_request); + + await octavia.removeLoadBalancer('mock_id'); + test.done(); + }, + + async confirmErrorOnError(test) { + const mock_request = { + del: function (options, cb) { + throw new Error('mock'); + } + }; + octavia.setRequest(mock_request); + + try { + await octavia.removeLoadBalancer('mock_id'); + } catch (error) { + test.ok(error, 'We should receive an error object'); + test.done(); + } + } }; @@ -254,21 +227,20 @@ exports.removeLoadBalancer = { confirmLBListenersOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.listLBListeners(function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); }, - + confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.listLBListeners(function(error, rules_array){ @@ -290,12 +262,11 @@ exports.getLBListener = { confirmLBListenerOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.getLBListener('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -304,7 +275,7 @@ exports.getLBListener = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.getLBListener('mock_id', function(error, result){ @@ -326,12 +297,11 @@ exports.createLBListener = { confirmValidResultOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.createLBListener('tenant_id', 'loadbalancer_id', 'description', 'protocol', {protocol_port: 'mock_protocol_port'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -341,9 +311,9 @@ exports.createLBListener = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); - + neutron.createLBListener('tenant_id', 'loadbalancer_id', 'description', 'protocol', {protocol_port: 'mock_protocol_port'}, function(error, result){ test.ok(error, 'We should receive an error object'); test.done(); @@ -364,12 +334,11 @@ exports.updateLBListener = { confirmValidResultOnSuccess: function(test) { //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.updateLBListener('mock_id', {description: 'Updated Listener'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -378,7 +347,7 @@ exports.updateLBListener = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.updateLBListener('mock_id', {description: 'Updated Listener'}, function(error, result){ @@ -398,11 +367,10 @@ exports.removeLBListener = { confirmNoErrorOnSuccess: function(test) { //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); + const mock_request = getMockRequest(null, 200, ''); neutron.setRequest(mock_request); neutron.removeLBListener('mock_id', function(error){ - test.ifError(error, 'There should be no error'); test.done(); }); }, @@ -410,7 +378,7 @@ exports.removeLBListener = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.removeLBListener('mock_id', function(error){ @@ -433,12 +401,11 @@ exports.listLBPools = { confirmLBPoolsOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.listLBPools(function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -447,7 +414,7 @@ exports.listLBPools = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.listLBPools(function(error, rules_array){ @@ -463,19 +430,18 @@ exports.getLBPool = { setUp: function(cb){ this.valid_response_body = {pool: {id: 'mock_id'}}; this.valid_result = {id: 'mock_id'}; - + cb(); }, confirmPoolOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.getLBPool('mock_id', function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -484,7 +450,7 @@ exports.getLBPool = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.getLBPool('mock_id', function(error, result){ @@ -507,12 +473,11 @@ exports.createLBPool = { confirmValidResultOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.createLBPool('tenant_id', 'protocol', 'lb_algorithm', 'listener_id', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -521,9 +486,9 @@ exports.createLBPool = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); - + neutron.createLBPool('tenant_id', 'protocol', 'lb_algorithm', 'listener_id', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ test.ok(error, 'We should receive an error object'); test.done(); @@ -544,12 +509,11 @@ exports.updateLBPool = { confirmValidResultOnSuccess: function(test) { //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.updateLBPool('mock_id', {description: 'Updated LBPool'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -558,7 +522,7 @@ exports.updateLBPool = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.updateLBPool('mock_id', {description: 'Updated LBPool'}, function(error, result){ @@ -578,11 +542,10 @@ exports.removeLBPool = { confirmNoErrorOnSuccess: function(test) { //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); + const mock_request = getMockRequest(null, 200, ''); neutron.setRequest(mock_request); neutron.removeLBPool('mock_id', function(error){ - test.ifError(error, 'There should be no error'); test.done(); }); }, @@ -590,7 +553,7 @@ exports.removeLBPool = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.removeLBPool('mock_id', function(error){ @@ -613,12 +576,11 @@ exports.listLBPoolMembers = { confirmMembersOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.listLBPoolMembers('pool_id', function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -627,7 +589,7 @@ exports.listLBPoolMembers = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.listLBPoolMembers('pool_id', function(error, rules_array){ @@ -650,12 +612,11 @@ exports.getLBPoolMember = { confirmMemberOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.getLBPoolMember('pool_id', 'member_id', function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -664,7 +625,7 @@ exports.getLBPoolMember = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.getLBPoolMember('pool_id', 'member_id', function(error, result){ @@ -686,12 +647,11 @@ exports.createLBPoolMember= { confirmValidResultOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.createLBPoolMember('pool_id', 'tenant_id', 'address', 'protocol_port', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -700,7 +660,7 @@ exports.createLBPoolMember= { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.createLBPoolMember('pool_id', 'tenant_id', 'address', 'protocol_port', {'admin_state_up': 'mock_admin_state_up'}, function(error, result){ @@ -723,12 +683,11 @@ exports.updateLBPoolMember = { confirmValidResultOnSuccess: function(test) { //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.updateLBPoolMember('pool_id', 'member_id', {description: 'Updated LBPool'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -737,7 +696,7 @@ exports.updateLBPoolMember = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.updateLBPoolMember('pool_id', 'member_id', {description: 'Updated LBPool'}, function(error, result){ @@ -757,11 +716,10 @@ exports.removeLBPoolMember = { confirmNoErrorOnSuccess: function(test) { //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); + const mock_request = getMockRequest(null, 200, ''); neutron.setRequest(mock_request); neutron.removeLBPoolMember('pool_id', 'member_id', function(error){ - test.ifError(error, 'There should be no error'); test.done(); }); }, @@ -769,7 +727,7 @@ exports.removeLBPoolMember = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.removeLBPoolMember('pool_id', 'member_id', function(error){ @@ -793,12 +751,11 @@ exports.listLBHealthMonitors = { confirmMembersOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.listLBHealthMonitors(function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -807,7 +764,7 @@ exports.listLBHealthMonitors = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.listLBHealthMonitors(function(error, rules_array){ @@ -830,12 +787,11 @@ exports.getLBHealthMonitor = { confirmValidResultOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.getLBHealthMonitor('health_monitor_id', function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -844,7 +800,7 @@ exports.getLBHealthMonitor = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.getLBHealthMonitor('health_monitor_id', function(error, result){ @@ -867,12 +823,11 @@ exports.createLBHealthMonitor= { confirmValidResultOnSuccess: function(test) { //stub out a completely valid request - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.createLBHealthMonitor('tenant_id', 'type', 'delay', 'timeout', 'max_retries', 'pool_id', {'http_method': 'mock_http_method'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -881,7 +836,7 @@ exports.createLBHealthMonitor= { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.createLBHealthMonitor('tenant_id', 'type', 'delay', 'timeout', 'max_retries', 'pool_id', {'http_method': 'mock_http_method'}, function(error, result){ @@ -904,12 +859,11 @@ exports.updateLBHealthMonitor = { confirmValidResultOnSuccess: function(test) { //stub out a request obj with a completely valid response - var self = this; - var mock_request = getMockRequest(null, 200, this.valid_response_body); + const self = this; + const mock_request = getMockRequest(null, 200, this.valid_response_body); neutron.setRequest(mock_request); neutron.updateLBHealthMonitor('health_monitor_id', {delay: 'mock_delay'}, function(error, result){ - test.ifError(error, 'There should be no error'); test.deepEqual(result, self.valid_result, 'result should be ' + JSON.stringify(self.valid_result)); test.done(); }); @@ -918,7 +872,7 @@ exports.updateLBHealthMonitor = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.updateLBHealthMonitor('health_monitor_id', {delay: 'mock_delay'}, function(error, result){ @@ -938,11 +892,10 @@ exports.removeLBHealthMonitor = { confirmNoErrorOnSuccess: function(test) { //stub out a completely valid response - var mock_request = getMockRequest(null, 200, ''); + const mock_request = getMockRequest(null, 200, ''); neutron.setRequest(mock_request); neutron.removeLBHealthMonitor('health_monitor_id', function(error){ - test.ifError(error, 'There should be no error'); test.done(); }); }, @@ -950,7 +903,7 @@ exports.removeLBHealthMonitor = { confirmErrorOnError: function(test) { //stub out some junk with an error - var mock_request = getMockRequest(new Error('meh'), 500, {}); + const mock_request = getMockRequest(new Error('meh'), 500, {}); neutron.setRequest(mock_request); neutron.removeLBHealthMonitor('health_monitor_id', function(error){ diff --git a/test/os-utils-test.js b/test/os-utils-test.js index 4391709..3a4308c 100644 --- a/test/os-utils-test.js +++ b/test/os-utils-test.js @@ -1,31 +1,28 @@ -var utils = require('../lib/os-utils.js'); +// var utils = require('../dist/os-utils.js').default; -//various tests for getArgsWithCallback -exports.getArgsWithCallback = { - confirmResponseWithMaxArgs: function(test) - { - var param1 = 'param1' - var param2 = function(){}; - var args = utils.getArgsWithCallback(2, [param1, param2]); - test.deepEqual(args, [param1, param2], 'Should return same arguments as passed in'); - test.done(); - }, - confirmResponseWithLessArgs: function(test) - { - var param1 = function(){}; - var args = utils.getArgsWithCallback(2, [param1]); - test.deepEqual(args, [null, param1], 'Should return array of same length with undefined elements for missing arguments'); - test.done(); - }, - confirmResponseWithMoreArgs: function(test) - { - var param1 = 'param1'; - var param2 = 'param2'; - var param3 = function(){}; - var args = utils.getArgsWithCallback(2, [param1, param2, param3]); - test.deepEqual(args, [param1, param3], 'Should return array with additional arguments removed'); - test.done(); - } - -}; \ No newline at end of file +// //various tests for getArgsWithCallback +// exports.getArgsWithCallback = { +// confirmResponseWithMaxArgs: function (test) { +// var param1 = 'param1' +// var param2 = function () { }; +// var args = utils.getArgsWithCallback(2, [param1, param2]); +// test.deepEqual(args, [param1, param2], 'Should return same arguments as passed in'); +// test.done(); +// }, +// confirmResponseWithLessArgs: function (test) { +// var param1 = function () { }; +// var args = utils.getArgsWithCallback(2, [param1]); +// test.deepEqual(args, [null, param1], 'Should return array of same length with undefined elements for missing arguments'); +// test.done(); +// }, +// confirmResponseWithMoreArgs: function (test) { +// var param1 = 'param1'; +// var param2 = 'param2'; +// var param3 = function () { }; +// var args = utils.getArgsWithCallback(2, [param1, param2, param3]); +// test.deepEqual(args, [param1, param3], 'Should return array with additional arguments removed'); +// test.done(); +// } + +// }; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3ed0eb4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,57 @@ +{ + "compilerOptions": { + /* Basic Options */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "incremental": true, /* Enable incremental compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} \ No newline at end of file diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..6422ae8 --- /dev/null +++ b/tslint.json @@ -0,0 +1,72 @@ +{ + "extends": "tslint:recommended", + "rulesDirectory": [ + "./src/" + ], + "rules": { + "no-unsafe-any": true, + "forin": false, + "prefer-for-of": false, + "no-unused-expression": true, + "unified-signatures": false, + "whitespace": [ + true, + "check-branch", + "check-operator" + ], + "indent": [ + true, + "tabs", + 2 + ], + "quotemark": [ + true, + "single", + "avoid-escape", + "avoid-template" + ], + "max-line-length": false, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "variable-name": [ + true, + "ban-keywords", + "check-format", + "allow-leading-underscore", + "allow-snake-case" + ], + "interface-name": [ + true, + "always-prefix" + ], + "object-literal-key-quotes": [ + true, + "as-needed" + ], + "no-bitwise": false, + "no-empty": false, + "align": [ + true, + "elements", + "members", + "statements" + ], + "new-parens": true, + "no-arg": true, + "no-conditional-assignment": true, + "no-consecutive-blank-lines": false, + "no-console": false + }, + "jsRules": { + "max-line-length": { + "options": [ + 120 + ] + } + } +} \ No newline at end of file From e2ab21759aef6b7e11cbf33f4cc45581dbce349f Mon Sep 17 00:00:00 2001 From: taoqf Date: Wed, 24 Apr 2019 18:19:04 +0800 Subject: [PATCH 2/3] remove file --- index.js | 97 -------------------------------------------------------- 1 file changed, 97 deletions(-) delete mode 100644 index.js diff --git a/index.js b/index.js deleted file mode 100644 index 6238843..0000000 --- a/index.js +++ /dev/null @@ -1,97 +0,0 @@ -var Keystone = require('./dist/keystone'); -var Glance = require('./dist/glance'); -var Neutron = require('./dist/neutron'); -var Octavia = require('./dist/octavia'); -var Nova = require('./dist/nova'); -var Heat = require('./dist/heat'); - -//A convenience method for quick/dirty work for those that already have a project_id -//calls back with (error, project) where project already has all the individual objects setup -//ie: project.nova, project.glance, etc.. -function getSimpleProject(username, password, project_id, keystone_url, cb) { - var keystone = new Keystone(keystone_url); - var return_object = {}; - var glance_url = ''; - var neutron_url = ''; - var nova_url = ''; - var octavia_url = ''; - var heat_url = ''; - var catalog_array = []; - var n = 0; - var j = 0; - var endpoint_type = ''; - - keystone.getToken(username, password, function (error, token) { - if (error) { - cb(error); - return; - } - - //else - keystone.getProjectToken(token.token, project_id, function (error, project_token) { - if (error) { - cb(error); - return; - } - - //else - catalog_array = project_token.catalog; - for (n = 0; n < catalog_array.length; n++) { - //ELS Puppet sometimes screws up Keystone and puts in duplicate service entries - //that have no endpoints.. ignore these. - if (!catalog_array[n].endpoints || !catalog_array[n].endpoints.length) { - continue; - } - - endpoints_array = catalog_array[n].endpoints; - endpoint_type = catalog_array[n].type; - - for (j = 0; j < endpoints_array.length; j++) { - if (endpoints_array[j].interface == 'public') { - endpoints_array[j].url = endpoints_array[j].url.replace(/\/$/, "");//yank any trailing /'s, - - if (endpoint_type == 'image') { - //we have to add the v2 to the end to get the most current functionality - glance_url = endpoints_array[j].url + '/v2.0'; - } - else if (endpoint_type == 'network') { - //we have to add the v2 to the end to get the most current functionality - neutron_url = endpoints_array[j].url + '/v2.0'; - } - else if (endpoint_type == 'compute') { - nova_url = endpoints_array[j].url; - } - else if (endpoint_type == 'load-balancer') { - octavia_url = endpoints_array[j].url; - } - else if (endpoint_type == 'orchestration') { - heat_url = endpoints_array[j].url; - } - break; - } - } - } - - return_object.general_token = token; - return_object.project_token = project_token; - return_object.glance = new Glance(glance_url, project_token.token); - return_object.neutron = new Neutron(neutron_url, project_token.token); - return_object.nova = new Nova(nova_url, project_token.token); - return_object.octavia = new Octavia(octavia_url, project_token.token); - return_object.heat = new Heat(heat_url, project_token.token); - cb(null, return_object); - }); - }); -} - - - -module.exports = { - Glance: Glance, - Keystone: Keystone, - Neutron: Neutron, - Octavia: Octavia, - Nova: Nova, - Heat: Heat, - getSimpleProject: getSimpleProject -} From 5828874850e1a489455baaa8532c145723a84d09 Mon Sep 17 00:00:00 2001 From: taoqf Date: Wed, 24 Apr 2019 18:36:55 +0800 Subject: [PATCH 3/3] import image is introduced --- src/glance.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/glance.ts b/src/glance.ts index 7ee6b09..fa24718 100644 --- a/src/glance.ts +++ b/src/glance.ts @@ -49,7 +49,17 @@ export default class Glance { this.logger = logger; } + public importImage(id: string, data: { + method: object; + }) { + const post_data = { + method: (data && data.method) || {} + }; + const request_options = this.getRequestOptions('/images/' + escape(id) + '/import', post_data, 'remote-calls.glance.images.import', '', { 'Content-Type': 'application/json' }); + + return this.request.post(request_options); + } // makes a callback cb(error, images_array) with a list of all of the available images for a given project/user // NOTE: harding pagination for now - change at will (just be aware it will break backwards compat so update version accordingly)