Skip to content

NodeJS 6 code sample for Cloud Function to start/stop GCE instances #815

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

Merged
merged 9 commits into from
Nov 2, 2018
13 changes: 13 additions & 0 deletions .kokoro/functions/scheduleinstance.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Format: //devtools/kokoro/config/proto/build.proto

# Set the folder in which the tests are run
env_vars: {
key: "PROJECT"
value: "functions/scheduleinstance"
}

# Tell the trampoline which build file to use.
env_vars: {
key: "TRAMPOLINE_BUILD_FILE"
value: "github/nodejs-docs-samples/.kokoro/build.sh"
}
31 changes: 31 additions & 0 deletions functions/scheduleinstance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<img src="https://avatars2.githubusercontent.com/u/2810941?v=3&s=96" alt="Google Cloud Platform logo" title="Google Cloud Platform" align="right" height="96" width="96"/>

# Google Cloud Functions - Scheduling GCE Instances sample

## Deploy and run the sample

See the [Scheduling Instances with Cloud Scheduler tutorial][tutorial].

[tutorial]: https://cloud.google.com/scheduler/docs/scheduling-instances-with-cloud-scheduler

## Run the tests

1. Read and follow the [prerequisites](../../#how-to-run-the-tests).

1. Install dependencies:

npm install

1. Run the tests:

npm test

## Additional resources

* [Cloud Scheduler documentation][docs]
* [HTTP Cloud Functions documentation][http_docs]
* [HTTP Cloud Functions tutorial][http_tutorial]

[docs]: https://cloud.google.com/scheduler/docs/
[http_docs]: https://cloud.google.com/functions/docs/writing/http
[http_tutorial]: https://cloud.google.com/functions/docs/tutorials/http
156 changes: 156 additions & 0 deletions functions/scheduleinstance/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/**
* Copyright 2018, Google, Inc.
* 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
*
* http://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.
*/

// [START functions_start_instance_http]
// [START functions_stop_instance_http]
const Compute = require('@google-cloud/compute');
const compute = new Compute();

// [END functions_stop_instance_http]
/**
* Starts a Compute Engine instance.
*
* Expects an HTTP POST request with a request body containing the following
* attributes:
* zone - the GCP zone the instance is located in.
* instance - the name of the instance.
*
* @param {!object} req Cloud Function HTTP request data.
* @param {!object} res Cloud Function HTTP response data.
* @returns {!object} Cloud Function response data with status code and message.
*/
exports.startInstance = (req, res) => {
try {
const reqBody = _validateReqBody(_parseReqBody(_validateReq(req)));
compute.zone(reqBody.zone)
.vm(reqBody.instance)
.start()
.then(data => {
// Operation pending.
const operation = data[0];
return operation.promise();
})
.then(() => {
// Operation complete. Instance successfully started.
const message = 'Successfully started instance ' + reqBody.instance;
console.log(message);
res.status(200).send(message);
})
.catch(err => {
console.log(err);
res.status(500).send({error: err.message});
});
} catch (err) {
console.log(err);
res.status(400).send({error: err.message});
}
return res;
};
// [END functions_start_instance_http]

// [START functions_stop_instance_http]
/**
* Stops a Compute Engine instance.
*
* Expects an HTTP POST request with a request body containing the following
* attributes:
* zone - the GCP zone the instance is located in.
* instance - the name of the instance.
*
* @param {!object} req Cloud Function HTTP request data.
* @param {!object} res Cloud Function HTTP response data.
* @returns {!object} Cloud Function response data with status code and message.
*/
exports.stopInstance = (req, res) => {
try {
const reqBody = _validateReqBody(_parseReqBody(_validateReq(req)));
compute.zone(reqBody.zone)
.vm(reqBody.instance)
.stop()
.then(data => {
// Operation pending.
const operation = data[0];
return operation.promise();
})
.then(() => {
// Operation complete. Instance successfully stopped.
const message = 'Successfully stopped instance ' + reqBody.instance;
console.log(message);
res.status(200).send(message);
})
.catch(err => {
console.log(err);
res.status(500).send({error: err.message});
});
} catch (err) {
console.log(err);
res.status(400).send({error: err.message});
}
return res;
};
// [START functions_start_instance_http]

/**
* Parses the request body attributes of an HTTP request based on content-type.
*
* @param {!object} req a Cloud Functions HTTP request object.
* @returns {!object} an object with attributes matching the HTTP request body.
*/
function _parseReqBody (req) {
const contentType = req.get('content-type');
if (contentType === 'application/json') {
// Request.body automatically parsed as an object.
return req.body;
} else if (contentType === 'application/octet-stream') {
// Convert buffer to a string and parse as JSON string.
return JSON.parse(req.body.toString());
} else {
throw new Error('Unsupported HTTP content-type ' + req.get('content-type') +
'; use application/json or application/octet-stream');
}
}

/**
* Validates that a request body contains the expected fields.
*
* @param {!object} reqBody the request body to validate.
* @returns {!object} the request body object.
*/
function _validateReqBody (reqBody) {
if (!reqBody.zone) {
throw new Error(`Attribute 'zone' missing from POST request`);
} else if (!reqBody.instance) {
throw new Error(`Attribute 'instance' missing from POST request`);
}
return reqBody;
}

/**
* Validates that a HTTP request contains the expected fields.
*
* @param {!object} req the request to validate.
* @returns {!object} the request object.
*/
function _validateReq (req) {
if (req.method !== 'POST') {
throw new Error('Unsupported HTTP method ' + req.method +
'; use method POST');
} else if (typeof req.get('content-type') === 'undefined') {
throw new Error('HTTP content-type missing');
}
return req;
}
// [END functions_start_instance_http]
// [END functions_stop_instance_http]
29 changes: 29 additions & 0 deletions functions/scheduleinstance/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "schedule-instance",
"version": "0.0.1",
"private": true,
"license": "Apache-2.0",
"author": "Google Inc.",
"repository": {
"type": "git",
"url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
},
"engines": {
"node": ">=6.0"
},
"scripts": {
"lint": "repo-tools lint",
"pretest": "npm run lint",
"test": "ava -T 20s --verbose test/*.test.js"
},
"devDependencies": {
"@google-cloud/nodejs-repo-tools": "2.2.1",
"ava": "0.25.0",
"proxyquire": "2.0.0",
"sinon": "4.4.2"
},
"dependencies": {
"@google-cloud/compute": "^0.10.0",
"safe-buffer": "5.1.1"
}
}
Loading