From 04d16137aad34437b8c66b35236cc3d60229c6ce Mon Sep 17 00:00:00 2001 From: Alan K <github@ack.modeswitch.org> Date: Mon, 11 Feb 2019 13:36:26 -0500 Subject: [PATCH] feat: Add getManagedInstances and deleteInstances to InstanceGroupManger API (#265) * Adds getManagedInstances and deleteInstances to InstanceGroupManger API * Fixes a broken documentation link --- .../src/instance-group-manager.js | 151 +++++++++++++- .../src/instance-group.js | 2 +- .../test/instance-group-manager.js | 193 ++++++++++++++++++ 3 files changed, 344 insertions(+), 2 deletions(-) diff --git a/packages/google-cloud-compute/src/instance-group-manager.js b/packages/google-cloud-compute/src/instance-group-manager.js index ff33fd08698..7400e39b787 100644 --- a/packages/google-cloud-compute/src/instance-group-manager.js +++ b/packages/google-cloud-compute/src/instance-group-manager.js @@ -16,7 +16,9 @@ 'use strict'; +const arrify = require('arrify'); const common = require('@google-cloud/common'); +const is = require('is'); const {promisifyAll} = require('@google-cloud/promisify'); const {teenyRequest} = require('teeny-request'); @@ -153,7 +155,154 @@ class InstanceGroupManager extends common.ServiceObject { */ this.name = name; } - + /** + * Flags the specified instances in the managed instance group for immediate deletion. + * @see [InstanceGroupManagers: deleteInstances API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/instanceGroupManagers/deleteInstances} + * @param {VM|VM[]} vms - VM instances to delete from + * this instance group manager. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {Operation} callback.operation - An operation object + * that can be used to check the status of the request. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * const Compute = require('@google-cloud/compute'); + * const compute = new Compute(); + * const zone = compute.zone('us-central1-a'); + * const instanceGroupManager = zone.instanceGroupManager('web-servers'); + * + * const vms = [ + * gce.zone('us-central1-a').vm('http-server'), + * gce.zone('us-central1-a').vm('https-server') + * ]; + * + * instanceGroupManager.deleteInstances(vms, function(err, operation, apiResponse) { + * // `operation` is an Operation object that can be used to check the status + * // of the request. + * }); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * instanceGroupManager.deleteInstances(vms).then(function(data) { + * const operation = data[0]; + * const apiResponse = data[1]; + * }); + */ + deleteInstances(vms, callback) { + const self = this; + this.request( + { + method: 'POST', + uri: '/deleteInstances', + json: { + instances: arrify(vms).map(function(vm) { + return vm.url; + }), + }, + }, + function(err, resp) { + if (err) { + callback(err, null, resp); + return; + } + const operation = self.zone.operation(resp.name); + operation.metadata = resp; + callback(null, operation, resp); + } + ); + } + /** + * Get a list of managed VM instances in this instance group manager. + * + * @see [InstanceGroupManagers: listManagedInstances API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/instanceGroupManagers/listManagedInstances} + * + * @param {object=} options - Instance search options. + * @param {boolean} options.autoPaginate - Have pagination handled + * automatically. Default: true. + * @param {string} options.filter - Search filter in the format of + * `{name} {comparison} {filterString}`. + * - **`name`**: the name of the field to compare + * - **`comparison`**: the comparison operator, `eq` (equal) or `ne` + * (not equal) + * - **`filterString`**: the string to filter to. For string fields, this + * can be a regular expression. + * @param {number} options.maxApiCalls - Maximum number of API calls to make. + * @param {number} options.maxResults - Maximum number of VMs to return. + * @param {string} options.pageToken - A previously-returned page token + * representing part of the larger set of results to view. + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {VM[]} callback.vms - VM objects from this instance + * group. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * const Compute = require('@google-cloud/compute'); + * const compute = new Compute(); + * const zone = compute.zone('us-central1-a'); + * const instanceGroupManager = zone.instanceGroupManager('web-servers'); + * + * instanceGroupManager.getManagedInstances(function(err, vms) { + * // `vms` is an array of `VM` objects. + * }); + * + * //- + * // To control how many API requests are made and page through the results + * // manually, set `autoPaginate` to `false`. + * //- + * function callback(err, vms, nextQuery, apiResponse) { + * if (nextQuery) { + * // More results exist. + * instanceGroupManager.getManagedInstances(nextQuery, callback); + * } + * } + * + * instanceGroupManager.getManagedInstances({ + * autoPaginate: false + * }, callback); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * instanceGroupManager.getManagedInstances().then(function(data) { + * const vms = data[0]; + * }); + */ + getManagedInstances(options, callback) { + const self = this; + if (is.fn(options)) { + callback = options; + options = {}; + } + options = options || {}; + this.request( + { + method: 'POST', + uri: '/listManagedInstances', + qs: options, + }, + function(err, resp) { + if (err) { + callback(err, null, null, resp); + return; + } + let nextQuery = null; + if (resp.nextPageToken) { + nextQuery = Object.assign({}, options, { + pageToken: resp.nextPageToken, + }); + } + const vms = arrify(resp.managedInstances).map(function(vm) { + const vmInstance = self.zone.vm(vm.instance); + vmInstance.metadata = vm; + return vmInstance; + }); + callback(null, vms, nextQuery, resp); + } + ); + } /** * Resizes the managed instance group. * diff --git a/packages/google-cloud-compute/src/instance-group.js b/packages/google-cloud-compute/src/instance-group.js index 5c9423868a7..e48fc92b61a 100644 --- a/packages/google-cloud-compute/src/instance-group.js +++ b/packages/google-cloud-compute/src/instance-group.js @@ -295,7 +295,7 @@ class InstanceGroup extends common.ServiceObject { /** * Get a list of VM instances in this instance group. * - * @see [InstaceGroups: listInstances API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/instanceGroups/listInstances} + * @see [InstanceGroups: listInstances API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/instanceGroups/listInstances} * * @param {object=} options - Instance search options. * @param {boolean} options.autoPaginate - Have pagination handled diff --git a/packages/google-cloud-compute/test/instance-group-manager.js b/packages/google-cloud-compute/test/instance-group-manager.js index 43d7e3b1685..118e32dba58 100644 --- a/packages/google-cloud-compute/test/instance-group-manager.js +++ b/packages/google-cloud-compute/test/instance-group-manager.js @@ -93,6 +93,199 @@ describe('InstanceGroupManager', function() { }); }); + describe('deleteInstances', function() { + const VMS = [{url: 'vm-url'}, {url: 'vm-url-2'}]; + + it('should make the correct API request', function(done) { + instanceGroupManager.request = function(reqOpts) { + assert.strictEqual(reqOpts.method, 'POST'); + assert.strictEqual(reqOpts.uri, '/deleteInstances'); + assert.deepStrictEqual(reqOpts.json, { + instances: VMS.map(function(vm) { + return vm.url; + }), + }); + + done(); + }; + + instanceGroupManager.deleteInstances(VMS, assert.ifError); + }); + + describe('error', function() { + const apiResponse = {}; + const error = new Error('Error.'); + + beforeEach(function() { + instanceGroupManager.request = function(reqOpts, callback) { + callback(error, apiResponse); + }; + }); + + it('should return an error and API response', function(done) { + instanceGroupManager.deleteInstances(VMS, function( + err, + operation, + apiResponse_ + ) { + assert.strictEqual(err, error); + assert.strictEqual(operation, null); + assert.strictEqual(apiResponse_, apiResponse); + done(); + }); + }); + }); + + describe('success', function() { + const apiResponse = {name: 'op-name'}; + + beforeEach(function() { + instanceGroupManager.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; + }); + + it('should return an Operation and API response', function(done) { + const operation = {}; + + instanceGroupManager.zone.operation = function(name) { + assert.strictEqual(name, apiResponse.name); + return operation; + }; + + instanceGroupManager.deleteInstances(VMS, function( + err, + operation_, + apiResponse_ + ) { + assert.ifError(err); + assert.strictEqual(operation_, operation); + assert.strictEqual(operation.metadata, apiResponse); + assert.strictEqual(apiResponse_, apiResponse); + done(); + }); + }); + }); + }); + + describe('getManagedInstances', function() { + beforeEach(function() { + instanceGroupManager.zone.vm = function() { + return {}; + }; + }); + + it('should accept only a callback', function(done) { + instanceGroupManager.request = function(reqOpts) { + assert.deepStrictEqual(reqOpts.qs, {}); + done(); + }; + + instanceGroupManager.getManagedInstances(assert.ifError); + }); + + it('should make the correct API request', function(done) { + const query = {a: 'b', c: 'd'}; + + instanceGroupManager.request = function(reqOpts) { + assert.strictEqual(reqOpts.uri, '/listManagedInstances'); + assert.strictEqual(reqOpts.qs, query); + + done(); + }; + + instanceGroupManager.getManagedInstances(query, assert.ifError); + }); + + describe('error', function() { + const error = new Error('Error.'); + const apiResponse = {a: 'b', c: 'd'}; + + beforeEach(function() { + instanceGroupManager.request = function(reqOpts, callback) { + callback(error, apiResponse); + }; + }); + + it('should execute callback with error & API response', function(done) { + instanceGroupManager.getManagedInstances({}, function( + err, + vms, + nextQuery, + apiResponse_ + ) { + assert.strictEqual(err, error); + assert.strictEqual(nextQuery, null); + assert.strictEqual(apiResponse_, apiResponse); + done(); + }); + }); + }); + + describe('success', function() { + const apiResponse = { + managedInstances: [{instance: 'vm-name'}], + }; + + beforeEach(function() { + instanceGroupManager.request = function(reqOpts, callback) { + callback(null, apiResponse); + }; + }); + + it('should build a nextQuery if necessary', function(done) { + const nextPageToken = 'next-page-token'; + const apiResponseWithNextPageToken = Object.assign({}, apiResponse, { + nextPageToken: nextPageToken, + }); + const expectedNextQuery = { + pageToken: nextPageToken, + }; + + instanceGroupManager.request = function(reqOpts, callback) { + callback(null, apiResponseWithNextPageToken); + }; + + instanceGroupManager.getManagedInstances({}, function( + err, + vms, + nextQuery + ) { + assert.ifError(err); + + assert.deepStrictEqual(nextQuery, expectedNextQuery); + + done(); + }); + }); + + it('should execute callback with VMs & API response', function(done) { + const vm = {}; + + instanceGroupManager.zone.vm = function(name) { + assert.strictEqual(name, apiResponse.managedInstances[0].instance); + return vm; + }; + + instanceGroupManager.getManagedInstances({}, function( + err, + vms, + nextQuery, + apiResponse_ + ) { + assert.ifError(err); + + assert.strictEqual(vms[0], vm); + assert.strictEqual(vms[0].metadata, apiResponse.managedInstances[0]); + + assert.strictEqual(apiResponse_, apiResponse); + + done(); + }); + }); + }); + }); + describe('resize', function() { const query = {size: 1};