Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: compute_consume_specific_shared_reservation #3912

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
22 changes: 13 additions & 9 deletions compute/reservations/createInstanceToConsumeAnyReservation.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,14 @@

async function main(instanceName) {
// [START compute_consume_any_matching_reservation]
// Import the Compute library
const computeLib = require('@google-cloud/compute');
const compute = computeLib.protos.google.cloud.compute.v1;

// Instantiate a reservationsClient
const instancesClient = new computeLib.InstancesClient();
// Instantiate a zoneOperationsClient
const zoneOperationsClient = new computeLib.ZoneOperationsClient();

/**
* TODO(developer): Update/uncomment these variables before running the sample.
* TODO(developer): Customize the following variables before running the sample.
*/
// The ID of the project where you want to create instance.
const projectId = await instancesClient.getProjectId();
Expand All @@ -39,9 +36,10 @@ async function main(instanceName) {
// Machine type to use for VM.
const machineType = 'n1-standard-4';

// Create instance to consume reservation if their properties match the VM properties
async function callCreateInstanceToConsumeAnyReservation() {
// Describe the size and source image of the boot disk to attach to the instance.
// Uses a persistent disk so that data is preserved even if the VM is
// stopped or restarted.
const disk = new compute.Disk({
boot: true,
autoDelete: true,
Expand All @@ -52,17 +50,24 @@ async function main(instanceName) {
},
});

// Define networkInterface
// Use the default network for simplicity. In production environments,
// you may want to specify a custom network with specific firewall rules
// and security configurations.
const networkInterface = new compute.NetworkInterface({
name: 'global/networks/default',
});

// Define reservationAffinity
// Configure the instance to consume any available reservation that matches
// its requirements (CPU, memory, etc.). This is a reasonable default for cost
// optimization for long-running workloads. Consider changing depending on your
// specific needs or workloads.
const reservationAffinity = new compute.ReservationAffinity({
consumeReservationType: 'ANY_RESERVATION',
});

// Create an instance
// Set the minimum CPU platform to ensure compatibility with
// machine type and to take advantage of specific CPU features.
// Change this based on performance and workload needs
const instance = new compute.Instance({
name: instanceName,
machineType: `zones/${zone}/machineTypes/${machineType}`,
Expand All @@ -80,7 +85,6 @@ async function main(instanceName) {

let operation = response.latestResponse;

// Wait for the create instance operation to complete.
while (operation.status !== 'DONE') {
[operation] = await zoneOperationsClient.wait({
operation: operation.name,
Expand Down
120 changes: 120 additions & 0 deletions compute/reservations/createInstanceToConsumeSharedReservation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* 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(instancesClient, zoneOperationsClient) {
// [START compute_consume_specific_shared_reservation]
// Import the Compute library
const computeLib = require('@google-cloud/compute');
const compute = computeLib.protos.google.cloud.compute.v1;

/**
* TODO(developer): Uncomment reservationsClient and zoneOperationsClient before running the sample.
*/
// Instantiate an instancesClient
// instancesClient = new computeLib.InstancesClient();
// Instantiate a zoneOperationsClient
// zoneOperationsClient = new computeLib.ZoneOperationsClient();

/**
* TODO(developer): Update these variables before running the sample.
*/
// The ID of the project where instance will be consumed and created.
const reservationConsumerProjectId = 'reservation-consumer-project-id';
// The ID of the project where reservation is created.
const reservationOwnerProjectId = 'reservation-project-id';
// The name of the instance to create.
const instanceName = 'instance-01';
// The name of the reservation to consume.
// Ensure that the specificReservationRequired field in reservation properties is set to true.
const reservationName = 'reservation-1';
// Machine type to use for VM.
const machineType = 'n1-standard-1';
// The zone in which to create instance.
const zone = 'us-central1-a';

// Create instance to consume shared reservation
async function callCreateInstanceToConsumeSharedReservation() {
// Describe the size and source image of the boot disk to attach to the instance.
// Ensure that the VM's properties match the reservation's VM properties,
// including the zone, machine type (machine family, vCPUs, and memory),
// minimum CPU platform, GPU amount and type, and local SSD interface and size
const disk = new compute.Disk({
boot: true,
autoDelete: true,
type: 'PERSISTENT',
initializeParams: {
diskSizeGb: '10',
sourceImage: 'projects/debian-cloud/global/images/family/debian-12',
},
});

// Define networkInterface
const networkInterface = new compute.NetworkInterface({
name: 'global/networks/default',
});

// Define reservationAffinity
const reservationAffinity = new compute.ReservationAffinity({
consumeReservationType: 'SPECIFIC_RESERVATION',
key: 'compute.googleapis.com/reservation-name',
values: [
`projects/${reservationOwnerProjectId}/reservations/${reservationName}`,
],
});

// Create an instance
const instance = new compute.Instance({
name: instanceName,
machineType: `zones/${zone}/machineTypes/${machineType}`,
disks: [disk],
networkInterfaces: [networkInterface],
reservationAffinity,
});

const [response] = await instancesClient.insert({
project: reservationConsumerProjectId,
instanceResource: instance,
zone,
});

let operation = response.latestResponse;

// Wait for the create instance operation to complete.
while (operation.status !== 'DONE') {
[operation] = await zoneOperationsClient.wait({
operation: operation.name,
project: reservationConsumerProjectId,
zone: operation.zone.split('/').pop(),
});
}

console.log(`Instance ${instanceName} created from shared reservation.`);
return response;
}

return await callCreateInstanceToConsumeSharedReservation();
// [END compute_consume_specific_shared_reservation]
}

module.exports = main;

// TODO(developer): Uncomment below lines before running the sample.
// main(...process.argv.slice(2)).catch(err => {
// console.error(err);
// process.exitCode = 1;
// });
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function main(instanceName, reservationName) {
const computeLib = require('@google-cloud/compute');
const compute = computeLib.protos.google.cloud.compute.v1;

// Instantiate a reservationsClient
// Instantiate an instancesClient
const instancesClient = new computeLib.InstancesClient();
// Instantiate a zoneOperationsClient
const zoneOperationsClient = new computeLib.ZoneOperationsClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function main(instanceName) {
const computeLib = require('@google-cloud/compute');
const compute = computeLib.protos.google.cloud.compute.v1;

// Instantiate a reservationsClient
// Instantiate an instancesClient
const instancesClient = new computeLib.InstancesClient();
// Instantiate a zoneOperationsClient
const zoneOperationsClient = new computeLib.ZoneOperationsClient();
Expand Down
5 changes: 4 additions & 1 deletion compute/test/consumeReservations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

const path = require('path');
const assert = require('node:assert/strict');
const {before, describe, it} = require('mocha');
const {before, after, describe, it} = require('mocha');
const cp = require('child_process');
const {ReservationsClient} = require('@google-cloud/compute').v1;
const {
Expand All @@ -40,6 +40,9 @@ describe('Consume reservations', async () => {

before(async () => {
projectId = await reservationsClient.getProjectId();
});

after(async () => {
// Cleanup resources
const instances = await getStaleVMInstances(instancePrefix);
await Promise.all(
Expand Down
16 changes: 2 additions & 14 deletions compute/test/createComputeHyperdisk.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@

const path = require('path');
const assert = require('node:assert/strict');
const {before, after, describe, it} = require('mocha');
const {after, describe, it} = require('mocha');
const cp = require('child_process');
const {DisksClient} = require('@google-cloud/compute').v1;
const {getStaleDisks, deleteDisk} = require('./util');

const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
Expand All @@ -30,24 +29,13 @@ describe('Create compute hyperdisk', async () => {
const prefix = 'hyperdisk-name-941ad2d';
const diskName = `${prefix}${Math.floor(Math.random() * 1000 + 1)}`;
const zone = 'europe-central2-b';
const disksClient = new DisksClient();
let projectId;

before(async () => {
projectId = await disksClient.getProjectId();
after(async () => {
// Cleanup resources
Copy link
Contributor Author

@gryczj gryczj Oct 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR I also moved cleanup methods to after() to prevent keeping not used resources in our project after running the tests and to reduce the code.

const disks = await getStaleDisks(prefix);
await Promise.all(disks.map(disk => deleteDisk(disk.zone, disk.diskName)));
});

after(async () => {
await disksClient.delete({
project: projectId,
disk: diskName,
zone,
});
});

it('should create a new hyperdisk', () => {
const response = execSync(
`node ./disks/createComputeHyperdisk.js ${diskName} ${zone}`,
Expand Down
10 changes: 2 additions & 8 deletions compute/test/createComputeHyperdiskFromPool.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

const path = require('path');
const assert = require('node:assert/strict');
const {after, before, describe, it} = require('mocha');
const {after, describe, it} = require('mocha');
const cp = require('child_process');
const {
getStaleDisks,
Expand All @@ -37,7 +37,7 @@ describe('Create compute hyperdisk from pool', async () => {
const storagePoolName = `${poolPrefix}${Math.floor(Math.random() * 1000 + 1)}5f`;
const zone = 'us-central1-a';

before(async () => {
after(async () => {
// Cleanup resources
const disks = await getStaleDisks(diskPrefix);
await Promise.all(disks.map(disk => deleteDisk(disk.zone, disk.diskName)));
Expand All @@ -49,12 +49,6 @@ describe('Create compute hyperdisk from pool', async () => {
);
});

after(async () => {
// Cleanup resources
await deleteDisk(zone, diskName);
await deleteStoragePool(zone, storagePoolName);
});

it('should create a new storage pool', async () => {
const response = execSync(
`node ./disks/createComputeHyperdiskPool.js ${storagePoolName} ${zone}`,
Expand Down
2 changes: 1 addition & 1 deletion compute/test/createInstanceTemplates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

const compute = require('@google-cloud/compute');

const {describe, it} = require('mocha');
const {after, describe, it} = require('mocha');
const cp = require('child_process');
const {assert} = require('chai');

Expand Down
67 changes: 67 additions & 0 deletions compute/test/createInstanceToConsumeSharedReservation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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 {beforeEach, afterEach, describe, it} = require('mocha');
const assert = require('node:assert/strict');
const sinon = require('sinon');
const createInstanceToConsumeSharedReservation = require('../reservations/createInstanceToConsumeSharedReservation.js');

describe('Create instance to consume shared reservation', async () => {
const instanceName = 'instance-1';
let instancesClientMock;
let zoneOperationsClientMock;

beforeEach(() => {
instancesClientMock = {
insert: sinon.stub().resolves([
{
name: instanceName,
latestResponse: {
status: 'DONE',
name: 'operation-1234567890',
zone: {
value: 'us-central1-a',
},
},
},
]),
};
zoneOperationsClientMock = {
wait: sinon.stub().resolves([
{
latestResponse: {
status: 'DONE',
},
},
]),
};
});

afterEach(() => {
sinon.restore();
});

it('should create instance', async () => {
const response = await createInstanceToConsumeSharedReservation(
instancesClientMock,
zoneOperationsClientMock
);

assert(response.name.includes(instanceName));
});
});
Loading
Loading