Skip to content

Commit 6ee9020

Browse files
authored
chore(samples): add suspend/resume samples (#735)
1 parent 4cb733f commit 6ee9020

3 files changed

Lines changed: 272 additions & 0 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* Resumes a suspended Google Compute Engine instance (with unencrypted disks).
17+
*
18+
* @param {string} projectId - Project ID or project number of the Cloud project you want to use.
19+
* @param {string} zone - Name of the zone to create the instance in. For example: "us-west3-b"
20+
* @param {string} instanceName - Name of the new virtual machine (VM) instance.
21+
*/
22+
function main(projectId, zone, instanceName) {
23+
// [START compute_resume_instance]
24+
/**
25+
* TODO(developer): Uncomment and replace these variables before running the sample.
26+
*/
27+
// const projectId = 'YOUR_PROJECT_ID';
28+
// const zone = 'europe-central2-b';
29+
// const instanceName = 'YOUR_INSTANCE_NAME';
30+
31+
const compute = require('@google-cloud/compute');
32+
33+
// Resumes a suspended Google Compute Engine instance (with unencrypted disks).
34+
async function resumeInstance() {
35+
const instancesClient = new compute.InstancesClient();
36+
37+
const [instance] = await instancesClient.get({
38+
project: projectId,
39+
zone,
40+
instance: instanceName,
41+
});
42+
43+
if (instance.status !== 'SUSPENDED') {
44+
throw new Error(
45+
'Only suspended instances can be resumed.' +
46+
`Instance ${instanceName} is in ${instance.status} state.`
47+
);
48+
}
49+
50+
const [response] = await instancesClient.resume({
51+
project: projectId,
52+
zone,
53+
instance: instanceName,
54+
});
55+
let operation = response.latestResponse;
56+
const operationsClient = new compute.ZoneOperationsClient();
57+
58+
// Wait for the create operation to complete.
59+
while (operation.status !== 'DONE') {
60+
[operation] = await operationsClient.wait({
61+
operation: operation.name,
62+
project: projectId,
63+
zone: operation.zone.split('/').pop(),
64+
});
65+
}
66+
67+
console.log('Instance resumed.');
68+
}
69+
70+
resumeInstance();
71+
// [END compute_resume_instance]
72+
}
73+
74+
process.on('unhandledRejection', err => {
75+
console.error(err.message);
76+
process.exitCode = 1;
77+
});
78+
79+
main(...process.argv.slice(2));
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* Suspends a running Google Compute Engine instance.
17+
*
18+
* @param {string} projectId - Project ID or project number of the Cloud project you want to use.
19+
* @param {string} zone - Name of the zone to create the instance in. For example: "us-west3-b"
20+
* @param {string} instanceName - Name of the new virtual machine (VM) instance.
21+
*/
22+
function main(projectId, zone, instanceName) {
23+
// [START compute_suspend_instance]
24+
/**
25+
* TODO(developer): Uncomment and replace these variables before running the sample.
26+
*/
27+
// const projectId = 'YOUR_PROJECT_ID';
28+
// const zone = 'europe-central2-b';
29+
// const instanceName = 'YOUR_INSTANCE_NAME';
30+
31+
const compute = require('@google-cloud/compute');
32+
33+
// Suspends a running Google Compute Engine instance.
34+
async function suspendInstance() {
35+
const instancesClient = new compute.InstancesClient();
36+
37+
const [response] = await instancesClient.suspend({
38+
project: projectId,
39+
zone,
40+
instance: instanceName,
41+
});
42+
let operation = response.latestResponse;
43+
const operationsClient = new compute.ZoneOperationsClient();
44+
45+
// Wait for the create operation to complete.
46+
while (operation.status !== 'DONE') {
47+
[operation] = await operationsClient.wait({
48+
operation: operation.name,
49+
project: projectId,
50+
zone: operation.zone.split('/').pop(),
51+
});
52+
}
53+
54+
console.log('Instance suspended.');
55+
}
56+
57+
suspendInstance();
58+
// [END compute_suspend_instance]
59+
}
60+
61+
process.on('unhandledRejection', err => {
62+
console.error(err.message);
63+
process.exitCode = 1;
64+
});
65+
66+
main(...process.argv.slice(2));

compute/test/suspendResume.test.js

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
const compute = require('@google-cloud/compute');
18+
19+
const {describe, it} = require('mocha');
20+
const cp = require('child_process');
21+
const {assert} = require('chai');
22+
23+
const {generateTestId, getStaleVMInstances, deleteInstance} = require('./util');
24+
25+
const instancesClient = new compute.InstancesClient();
26+
const zoneOperationsClient = new compute.ZoneOperationsClient();
27+
28+
const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});
29+
30+
describe('suspend/resume instance tests', () => {
31+
const instanceName = generateTestId();
32+
const zone = 'europe-central2-b';
33+
34+
const delay = ms => new Promise(res => setTimeout(res, ms));
35+
36+
const getInstance = async (projectId, zone, instanceName) => {
37+
const [instance] = await instancesClient.get({
38+
project: projectId,
39+
zone,
40+
instance: instanceName,
41+
});
42+
return instance;
43+
};
44+
45+
after(async () => {
46+
const instances = await getStaleVMInstances();
47+
await Promise.all(
48+
instances.map(instance =>
49+
deleteInstance(instance.zone, instance.instanceName)
50+
)
51+
);
52+
});
53+
54+
it('should suspend and resume instance', async () => {
55+
const projectId = await instancesClient.getProjectId();
56+
57+
const [insertResponse] = await instancesClient.insert({
58+
instanceResource: {
59+
name: instanceName,
60+
disks: [
61+
{
62+
initializeParams: {
63+
diskSizeGb: '64',
64+
sourceImage:
65+
'projects/ubuntu-os-cloud/global/images/family/ubuntu-2004-lts',
66+
},
67+
autoDelete: true,
68+
boot: true,
69+
},
70+
],
71+
machineType: `zones/${zone}/machineTypes/n1-standard-1`,
72+
networkInterfaces: [
73+
{
74+
name: 'global/networks/default',
75+
},
76+
],
77+
},
78+
project: projectId,
79+
zone,
80+
});
81+
let operation = insertResponse.latestResponse;
82+
83+
while (operation.status !== 'DONE') {
84+
[operation] = await zoneOperationsClient.wait({
85+
operation: operation.name,
86+
project: projectId,
87+
zone: operation.zone.split('/').pop(),
88+
});
89+
}
90+
91+
// Once the machine is running, give it some time to fully start all processes
92+
// before trying to suspend it.
93+
await delay(45 * 1000);
94+
95+
let output = execSync(
96+
`node instances/suspend-resume/suspend ${projectId} ${zone} ${instanceName}`
97+
);
98+
assert.match(output, /Instance suspended./);
99+
100+
let instance = await getInstance(projectId, zone, instanceName);
101+
102+
while (instance.status === 'SUSPENDING') {
103+
[instance] = await instancesClient.get({
104+
project: projectId,
105+
zone,
106+
instance: instanceName,
107+
});
108+
109+
await delay(5 * 1000);
110+
}
111+
112+
instance = await getInstance(projectId, zone, instanceName);
113+
114+
assert.equal(instance.status, 'SUSPENDED');
115+
116+
output = execSync(
117+
`node instances/suspend-resume/resume ${projectId} ${zone} ${instanceName}`
118+
);
119+
assert.match(output, /Instance resumed./);
120+
121+
instance = await getInstance(projectId, zone, instanceName);
122+
123+
assert.equal(instance.status, 'RUNNING');
124+
125+
execSync(`node deleteInstance ${projectId} ${zone} ${instanceName}`);
126+
});
127+
});

0 commit comments

Comments
 (0)