From 60c87e6e7e4307670eacbde695116e6c42dbc6d1 Mon Sep 17 00:00:00 2001 From: Jani Patokallio Date: Thu, 5 Nov 2020 04:27:28 +0800 Subject: [PATCH] feat: add VM.get/setLabels() methods (#515) --- src/vm.js | 88 ++++++++++++++++++++++++++++++++++++++++++ system-test/compute.js | 7 ++++ test/vm.js | 86 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) diff --git a/src/vm.js b/src/vm.js index 85b2b292..c79c121e 100644 --- a/src/vm.js +++ b/src/vm.js @@ -466,6 +466,44 @@ class VM extends common.ServiceObject { }); }); } + /** + * Get the instance's labels and their fingerprint. + * + * This method wraps {module:compute/vm#getMetadata}, returning only the `labels` + * property. + * + * @param {function} callback - The callback function. + * @param {?error} callback.err - An error returned while making this request. + * @param {object[]} callback.labels - Label objects from this VM. + * @param {string} callback.fingerprint - The current label fingerprint. + * @param {object} callback.apiResponse - The full API response. + * + * @example + * const Compute = require('@google-cloud/compute'); + * const compute = new Compute(); + * const zone = compute.zone('zone-name'); + * const vm = zone.vm('vm-name'); + * + * vm.getLabels(function(err, labels, fingerprint, apiResponse) {}); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * vm.getLabels().then(function(data) { + * const labels = data[0]; + * const fingerprint = data[1]; + * const apiResponse = data[2]; + * }); + */ + getLabels(callback) { + this.getMetadata((err, metadata, apiResponse) => { + if (err) { + callback(err, null, null, apiResponse); + return; + } + callback(null, metadata.labels, metadata.labelFingerprint, apiResponse); + }); + } /** * Returns the serial port output for the instance. * @@ -721,6 +759,56 @@ class VM extends common.ServiceObject { }) ); } + /** + * Set labels for this instance. + * + * @see [Instances: setLabels API Documentation]{@link https://cloud.google.com/compute/docs/reference/v1/instances/setLabels} + * + * @param {object} labels - New labels. + * @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('zone-name'); + * const vm = zone.vm('vm-name'); + * + * const labels = { + * 'startup-script': '...', + * customKey: null // Setting `null` will remove the `customKey` property. + * }; + * + * vm.setLabels(labels, 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. + * //- + * vm.setLabels(labels).then(function(data) { + * const operation = data[0]; + * const apiResponse = data[1]; + * }); + */ + setLabels(labels, labelFingerprint, callback) { + const body = { + labels: labels, + labelFingerprint: labelFingerprint, + }; + this.request( + { + method: 'POST', + uri: '/setLabels', + json: body, + }, + callback || common.util.noop + ); + } /** * Set the custom metadata for this instance. * diff --git a/system-test/compute.js b/system-test/compute.js index dba06750..24bc3d2e 100644 --- a/system-test/compute.js +++ b/system-test/compute.js @@ -979,6 +979,13 @@ describe('Compute', () => { return vm.getSerialPortOutput(); }); + it('should set labels', async () => { + let [labels, fingerprint] = await vm.getLabels(); + await awaitResult(vm.setLabels({foo: 'bar'}, fingerprint)); + [labels, fingerprint] = await vm.getLabels(); + assert.strictEqual(labels.foo, 'bar'); + }); + it('should set tags', async () => { const newTagName = 'new-tag'; const [tags, fingerprint] = await vm.getTags(); diff --git a/test/vm.js b/test/vm.js index 796a9bf1..edc479ae 100644 --- a/test/vm.js +++ b/test/vm.js @@ -383,6 +383,65 @@ describe('VM', () => { }); }); + describe('getLabels', () => { + it('should get metadata', done => { + vm.getMetadata = function () { + done(); + }; + + vm.getTags(assert.ifError); + }); + + describe('error', () => { + const error = new Error('Error.'); + const apiResponse = {a: 'b', c: 'd'}; + + beforeEach(() => { + vm.getMetadata = function (callback) { + callback(error, null, apiResponse); + }; + }); + + it('should execute callback with error', done => { + vm.getLabels((err, labels, fingerprint, apiResponse_) => { + assert.strictEqual(err, error); + assert.strictEqual(labels, null); + assert.strictEqual(fingerprint, null); + assert.strictEqual(apiResponse_, apiResponse); + + done(); + }); + }); + }); + + describe('success', () => { + const metadata = { + labels: {}, + labelFingerprint: 'fingerprint', + }; + + const apiResponse = {a: 'b', c: 'd'}; + + beforeEach(() => { + vm.getMetadata = function (callback) { + callback(null, metadata, apiResponse); + }; + }); + + it('should execute callback with tags and fingerprint', done => { + vm.getLabels((err, labels, fingerprint, apiResponse_) => { + assert.ifError(err); + + assert.strictEqual(labels, metadata.labels); + assert.strictEqual(fingerprint, metadata.labelFingerprint); + assert.strictEqual(apiResponse_, apiResponse); + + done(); + }); + }); + }); + }); + describe('getSerialPortOutput', () => { const EXPECTED_QUERY = {port: 1, start: 0}; @@ -738,6 +797,33 @@ describe('VM', () => { }); }); + describe('setLabels', () => { + const LABELS = []; + const FINGERPRINT = ''; + + it('should make the correct request', done => { + vm.request = function (reqOpts, callback) { + assert.strictEqual(reqOpts.method, 'POST'); + assert.strictEqual(reqOpts.uri, '/setLabels'); + assert.strictEqual(reqOpts.json.labels, LABELS); + assert.strictEqual(reqOpts.json.labelFingerprint, FINGERPRINT); + + callback(); // done() + }; + + vm.setLabels(LABELS, FINGERPRINT, done); + }); + + it('should not require a callback', done => { + vm.request = function (reqOpts, callback) { + assert.doesNotThrow(callback); + done(); + }; + + vm.setLabels(LABELS, FINGERPRINT); + }); + }); + describe('setMetadata', () => { const METADATA = { newKey: 'newValue',