diff --git a/compute/reservations/createReservationInstanceTemplate.js b/compute/reservations/createReservationInstanceTemplate.js new file mode 100644 index 0000000000..796bbc6064 --- /dev/null +++ b/compute/reservations/createReservationInstanceTemplate.js @@ -0,0 +1,108 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +async function main(location, instanceTemplateName) { + // [START compute_reservation_create_template] + // Import the Compute library + const computeLib = require('@google-cloud/compute'); + const compute = computeLib.protos.google.cloud.compute.v1; + + // Instantiate a reservationsClient + const reservationsClient = new computeLib.ReservationsClient(); + // Instantiate a zoneOperationsClient + const zoneOperationsClient = new computeLib.ZoneOperationsClient(); + + /** + * TODO(developer): Update these variables before running the sample. + */ + // The ID of the project where you want to reserve resources and where the instance template exists. + const projectId = await reservationsClient.getProjectId(); + // The zone in which to reserve resources. + const zone = 'us-central1-a'; + // The name of the reservation to create. + const reservationName = 'reservation-01'; + // The number of VMs to reserve. + const vmsNumber = 3; + + /** + * The name of an existing instance template. + * TODO(developer): Uncomment and update instanceTemplateName before running the sample. + */ + // const instanceTemplateName = 'pernament-region-template-name'; + + /** + * // The location of the instance template. + * TODO(developer): Uncomment the `location` variable depending on which template you want to use. + */ + + // The location for a regional instance template: regions/{region}. Replace region with the region where the instance template is located. + // If you specify a regional instance template, then you can only reserve VMs within the same region as the template's region. + // const location = `regions/${zone.slice(0, -2)}`; + + // The location for a global instance template. + // const location = 'global'; + + async function callCreateComputeReservationInstanceTemplate() { + // Create reservation for 3 VMs in zone us-central1-a by specifying a instance template. + const specificReservation = new compute.AllocationSpecificSKUReservation({ + count: vmsNumber, + sourceInstanceTemplate: `projects/${projectId}/${location}/instanceTemplates/${instanceTemplateName}`, + }); + + // Create a reservation. + const reservation = new compute.Reservation({ + name: reservationName, + specificReservation, + }); + + const [response] = await reservationsClient.insert({ + project: projectId, + reservationResource: reservation, + zone, + }); + + let operation = response.latestResponse; + + // Wait for the create reservation operation to complete. + while (operation.status !== 'DONE') { + [operation] = await zoneOperationsClient.wait({ + operation: operation.name, + project: projectId, + zone: operation.zone.split('/').pop(), + }); + } + + const createdReservation = ( + await reservationsClient.get({ + project: projectId, + zone, + reservation: reservationName, + }) + )[0]; + + console.log(JSON.stringify(createdReservation)); + } + + await callCreateComputeReservationInstanceTemplate(); + // [END compute_reservation_create_template] +} + +main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; +}); diff --git a/compute/test/createReservationGlobalInstanceTemplate.test.js b/compute/test/createReservationGlobalInstanceTemplate.test.js new file mode 100644 index 0000000000..df34b1ad56 --- /dev/null +++ b/compute/test/createReservationGlobalInstanceTemplate.test.js @@ -0,0 +1,77 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const path = require('path'); +const assert = require('node:assert/strict'); +const {after, before, describe, it} = require('mocha'); +const cp = require('child_process'); +const {ReservationsClient} = require('@google-cloud/compute').v1; + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Create compute reservation using global instance template', async () => { + const reservationName = 'reservation-01'; + const instanceTemplateName = 'pernament-global-template-name'; + const location = 'global'; + const reservationsClient = new ReservationsClient(); + let projectId; + + before(async () => { + projectId = await reservationsClient.getProjectId(); + // Create template + execSync( + `node ./create-instance-templates/createTemplate.js ${projectId} ${instanceTemplateName}`, + { + cwd, + } + ); + }); + + after(() => { + // Delete reservation + execSync('node ./reservations/deleteReservation.js', { + cwd, + }); + // Delete template + execSync( + `node ./create-instance-templates/deleteInstanceTemplate.js ${projectId} ${instanceTemplateName}`, + { + cwd, + } + ); + }); + + it('should create a new reservation', () => { + const response = JSON.parse( + execSync( + `node ./reservations/createReservationInstanceTemplate.js ${location} ${instanceTemplateName}`, + { + cwd, + } + ) + ); + + assert.equal(response.name, reservationName); + assert.equal(response.specificReservation.count, '3'); + assert.equal( + response.specificReservation.sourceInstanceTemplate, + `https://www.googleapis.com/compute/v1/projects/${projectId}/${location}/instanceTemplates/${instanceTemplateName}` + ); + }); +}); diff --git a/compute/test/createReservationRegionalInstanceTemplate.test.js b/compute/test/createReservationRegionalInstanceTemplate.test.js new file mode 100644 index 0000000000..76522e3e2b --- /dev/null +++ b/compute/test/createReservationRegionalInstanceTemplate.test.js @@ -0,0 +1,63 @@ +/* + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +'use strict'; + +const path = require('path'); +const assert = require('node:assert/strict'); +const {after, before, describe, it} = require('mocha'); +const cp = require('child_process'); +const {ReservationsClient} = require('@google-cloud/compute').v1; + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const cwd = path.join(__dirname, '..'); + +describe('Create compute reservation using regional instance template', async () => { + const reservationName = 'reservation-01'; + const instanceTemplateName = 'pernament-region-template-name'; + const location = 'regions/us-central1'; + const reservationsClient = new ReservationsClient(); + let projectId; + + before(async () => { + projectId = await reservationsClient.getProjectId(); + }); + + after(() => { + // Delete reservation + execSync('node ./reservations/deleteReservation.js', { + cwd, + }); + }); + + it('should create a new reservation', () => { + const response = JSON.parse( + execSync( + `node ./reservations/createReservationInstanceTemplate.js ${location} ${instanceTemplateName}`, + { + cwd, + } + ) + ); + + assert.equal(response.name, reservationName); + assert.equal(response.specificReservation.count, '3'); + assert.equal( + response.specificReservation.sourceInstanceTemplate, + `https://www.googleapis.com/compute/v1/projects/${projectId}/${location}/instanceTemplates/${instanceTemplateName}` + ); + }); +}); diff --git a/compute/test/reservations.test.js b/compute/test/reservations.test.js index bcbec555fe..75715f020f 100644 --- a/compute/test/reservations.test.js +++ b/compute/test/reservations.test.js @@ -19,7 +19,6 @@ const path = require('path'); const assert = require('node:assert/strict'); const {describe, it} = require('mocha'); -const {expect} = require('chai'); const cp = require('child_process'); const {ReservationsClient} = require('@google-cloud/compute').v1; @@ -112,9 +111,8 @@ describe('Compute reservation', async () => { throw new Error('Reservation was not deleted.'); } catch (error) { // Assert that the error message indicates the reservation wasn't found - expect(error.message).to.include( - `The resource 'projects/${projectId}/zones/${zone}/reservations/${reservationName}' was not found` - ); + const expected = `The resource 'projects/${projectId}/zones/${zone}/reservations/${reservationName}' was not found`; + assert(error.message && error.message.includes(expected)); } }); });