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

Update functions/scheduleinstance code sample with PubSub functions & unit tests #820

Merged
merged 15 commits into from
Nov 6, 2018
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 125 additions & 34 deletions functions/scheduleinstance/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,32 @@

// [START functions_start_instance_http]
// [START functions_stop_instance_http]
// [START functions_start_instance_pubsub]
// [START functions_stop_instance_pubsub]
const Buffer = require('safe-buffer').Buffer;
const Compute = require('@google-cloud/compute');
const compute = new Compute();

// [END functions_stop_instance_http]
// [END functions_start_instance_pubsub]
// [END functions_stop_instance_pubsub]
/**
* Starts a Compute Engine instance.
*
* Expects an HTTP POST request with a request body containing the following
* attributes:
* Expects an HTTP POST request with a JSON-formatted 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) => {
exports.startInstanceHttp = (req, res) => {
try {
const reqBody = _validateReqBody(_parseReqBody(_validateReq(req)));
compute.zone(reqBody.zone)
.vm(reqBody.instance)
const payload = _validatePayload(_parseHttpPayload(_validateHttpReq(req)));
compute.zone(payload.zone)
.vm(payload.instance)
.start()
.then(data => {
// Operation pending.
Expand All @@ -44,7 +49,7 @@ exports.startInstance = (req, res) => {
})
.then(() => {
// Operation complete. Instance successfully started.
const message = 'Successfully started instance ' + reqBody.instance;
const message = 'Successfully started instance ' + payload.instance;
console.log(message);
res.status(200).send(message);
})
Expand All @@ -58,26 +63,26 @@ exports.startInstance = (req, res) => {
}
return res;
};
// [END functions_start_instance_http]

// [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:
* Expects an HTTP POST request with a JSON-formatted 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) => {
exports.stopInstanceHttp = (req, res) => {
try {
const reqBody = _validateReqBody(_parseReqBody(_validateReq(req)));
compute.zone(reqBody.zone)
.vm(reqBody.instance)
const payload = _validatePayload(_parseHttpPayload(_validateHttpReq(req)));
compute.zone(payload.zone)
.vm(payload.instance)
.stop()
.then(data => {
// Operation pending.
Expand All @@ -86,7 +91,7 @@ exports.stopInstance = (req, res) => {
})
.then(() => {
// Operation complete. Instance successfully stopped.
const message = 'Successfully stopped instance ' + reqBody.instance;
const message = 'Successfully stopped instance ' + payload.instance;
console.log(message);
res.status(200).send(message);
})
Expand All @@ -100,15 +105,116 @@ exports.stopInstance = (req, res) => {
}
return res;
};

// [END functions_stop_instance_http]
// [START functions_start_instance_pubsub]
/**
* Starts a Compute Engine instance.
*
* Expects a PubSub message with JSON-formatted event data containing the
* following attributes:
* zone - the GCP zone the instance is located in.
* instance - the name of the instance.
*
* @param {!object} event Cloud Function PubSub message event.
* @param {!object} callback Cloud Function PubSub callback indicating completion.
*/
exports.startInstancePubSub = (event, callback) => {
try {
const pubsubMessage = event.data;
const payload = _validatePayload(JSON.parse(Buffer.from(pubsubMessage.data, 'base64').toString()));
compute.zone(payload.zone)
.vm(payload.instance)
.start()
.then(data => {
// Operation pending.
const operation = data[0];
return operation.promise();
})
.then(() => {
// Operation complete. Instance successfully started.
const message = 'Successfully started instance ' + payload.instance;
console.log(message);
callback(null, message);
})
.catch(err => {
console.log(err);
callback(err);
});
} catch (err) {
console.log(err);
callback(err);
}
};

// [END functions_start_instance_pubsub]
// [START functions_stop_instance_pubsub]
/**
* Stops a Compute Engine instance.
*
* Expects a PubSub message with JSON-formatted event data containing the
* following attributes:
* zone - the GCP zone the instance is located in.
* instance - the name of the instance.
*
* @param {!object} event Cloud Function PubSub message event.
* @param {!object} callback Cloud Function PubSub callback indicating completion.
*/
exports.stopInstancePubSub = (event, callback) => {
try {
const pubsubMessage = event.data;
const payload = _validatePayload(JSON.parse(Buffer.from(pubsubMessage.data, 'base64').toString()));
compute.zone(payload.zone)
.vm(payload.instance)
.stop()
.then(data => {
// Operation pending.
const operation = data[0];
return operation.promise();
})
.then(() => {
// Operation complete. Instance successfully stopped.
const message = 'Successfully stopped instance ' + payload.instance;
console.log(message);
callback(null, message);
})
.catch(err => {
console.log(err);
callback(err);
});
} catch (err) {
console.log(err);
callback(err);
}
};

// [START functions_start_instance_http]
// [START functions_stop_instance_http]
// [START functions_start_instance_pubsub]
/**
* Validates that a request payload contains the expected fields.
*
* @param {!object} payload the request payload to validate.
* @returns {!object} the payload object.
*/
function _validatePayload (payload) {
if (!payload.zone) {
throw new Error(`Attribute 'zone' missing from payload`);
} else if (!payload.instance) {
throw new Error(`Attribute 'instance' missing from payload`);
}
return payload;
}
// [END functions_start_instance_pubsub]
// [END functions_stop_instance_pubsub]

/**
* Parses the request body attributes of an HTTP request based on content-type.
* Parses the request payload 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.
* @returns {!object} an object with attributes matching the request payload.
*/
function _parseReqBody (req) {
function _parseHttpPayload (req) {
const contentType = req.get('content-type');
if (contentType === 'application/json') {
// Request.body automatically parsed as an object.
Expand All @@ -122,28 +228,13 @@ function _parseReqBody (req) {
}
}

/**
* 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) {
function _validateHttpReq (req) {
if (req.method !== 'POST') {
throw new Error('Unsupported HTTP method ' + req.method +
'; use method POST');
Expand Down
10 changes: 5 additions & 5 deletions functions/scheduleinstance/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "schedule-instance",
"name": "cloud-functions-schedule-instance",
"version": "0.0.1",
"private": true,
"license": "Apache-2.0",
Expand All @@ -17,10 +17,10 @@
"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"
"@google-cloud/nodejs-repo-tools": "^2.2.5",
"ava": "^0.25.0",
"proxyquire": "^2.0.0",
"sinon": "^4.4.2"
},
"dependencies": {
"@google-cloud/compute": "^0.10.0",
Expand Down
Loading