diff --git a/scheduler/.eslintrc.yml b/scheduler/.eslintrc.yml new file mode 100644 index 0000000000..282535f55f --- /dev/null +++ b/scheduler/.eslintrc.yml @@ -0,0 +1,3 @@ +--- +rules: + no-console: off diff --git a/scheduler/app.js b/scheduler/app.js new file mode 100644 index 0000000000..40bd71ac91 --- /dev/null +++ b/scheduler/app.js @@ -0,0 +1,43 @@ +// Copyright 2018 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 +// +// 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. +'use strict'; + +// [START cloud_scheduler_app] +const express = require('express'); +const bodyParser = require('body-parser'); + +const app = express(); +app.use(bodyParser.raw()); + +// Define relative URI for job endpoint +app.post('/log_payload', (req, res) => { + // Log the job payload + const message = req.body.toString('utf8'); + console.log(`Received job with payload: ${message}`); + res.send(`Printed job with payload: ${message}`).end(); +}); +// [END cloud_scheduler_app] + +app.get('/', (req, res) => { + res.status(200).send('Hello, World!').end(); +}); + +// Start the server +const PORT = process.env.PORT || 8080; +app.listen(PORT, () => { + console.log(`App listening on port ${PORT}`); + console.log('Press Ctrl+C to quit.'); +}); + +module.exports = app; diff --git a/scheduler/app.yaml b/scheduler/app.yaml new file mode 100644 index 0000000000..d48c70f0b1 --- /dev/null +++ b/scheduler/app.yaml @@ -0,0 +1,18 @@ +# Copyright 2018 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 +# +# 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 cloud_scheduler_yaml] +runtime: nodejs8 +service: my-service +# [END cloud_scheduler_yaml] diff --git a/scheduler/createJob.js b/scheduler/createJob.js new file mode 100644 index 0000000000..257126886c --- /dev/null +++ b/scheduler/createJob.js @@ -0,0 +1,67 @@ +// Copyright 2018 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 +// +// 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. + +// sample-metadata: +// title: Create Job +// description: Create a job that posts to /log_payload on an App Engine service. +// usage: node createJob.js [project-id] [location-id] [app-engine-service-id] + +/** + * Create a job with an App Engine target via the Cloud Scheduler API + */ +async function createJob(projectId, locationId, serviceId) { + // [START cloud_scheduler_create_job] + const scheduler = require('@google-cloud/scheduler'); + + // Create a client. + const client = new scheduler.CloudSchedulerClient(); + + // TODO(developer): Uncomment and set the following variables + // const projectId = "PROJECT_ID" + // const locationId = "LOCATION_ID" + // const serviceId = "my-serivce" + + // Construct the fully qualified location path. + const parent = client.locationPath(projectId, locationId); + + // Construct the request body. + const job = { + appEngineHttpTarget: { + appEngineRouting: { + service: serviceId, + }, + relativeUri: '/log_payload', + httpMethod: 'POST', + body: Buffer.from('Hello World'), + }, + schedule: '* * * * *', + timeZone: 'America/Los_Angeles', + }; + + const request = { + parent: parent, + job: job, + }; + + // Use the client to send the job creation request. + const [response] = await client.createJob(request); + console.log(`Created job: ${response.name}`); + // [END cloud_scheduler_create_job] +} + +const args = process.argv.slice(2); +createJob(...args).catch(err => { + console.error(err.message); + process.exitCode = 1; +}); diff --git a/scheduler/deleteJob.js b/scheduler/deleteJob.js new file mode 100644 index 0000000000..3118f51ed2 --- /dev/null +++ b/scheduler/deleteJob.js @@ -0,0 +1,48 @@ +// Copyright 2018 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 +// +// 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. + +// sample-metadata: +// title: Delete Job +// description: Delete a job by its ID. +// usage: node deleteJob.js [project-id] [location-id] [job-id] + +/** + * Delete a job via the Cloud Scheduler API + */ +async function deleteJob(projectId, locationId, jobId) { + // [START cloud_scheduler_delete_job] + const scheduler = require('@google-cloud/scheduler'); + + // Create a client. + const client = new scheduler.CloudSchedulerClient(); + + // TODO(developer): Uncomment and set the following variables + // const projectId = "PROJECT_ID" + // const locationId = "LOCATION_ID" + // const jobId = "JOB_ID" + + // Construct the fully qualified location path. + const job = client.jobPath(projectId, locationId, jobId); + + // Use the client to send the job creation request. + await client.deleteJob({name: job}); + console.log('Job deleted.'); + // [END cloud_scheduler_delete_job] +} + +const args = process.argv.slice(2); +deleteJob(...args).catch(err => { + console.error(err.message); + process.exitCode = 1; +}); diff --git a/scheduler/package.json b/scheduler/package.json new file mode 100644 index 0000000000..f953e0e264 --- /dev/null +++ b/scheduler/package.json @@ -0,0 +1,26 @@ +{ + "name": "nodejs-scheduler-samples", + "private": true, + "main": "quickstart.js", + "engines": { + "node": ">=12.0.0" + }, + "files": [ + "*.js" + ], + "license": "Apache-2.0", + "scripts": { + "start": "node app.js", + "test": "mocha --timeout 10000 --exit" + }, + "dependencies": { + "@google-cloud/scheduler": "^3.0.5", + "body-parser": "^1.18.3", + "express": "^4.16.4" + }, + "devDependencies": { + "chai": "^4.2.0", + "mocha": "^8.0.0", + "supertest": "^6.0.0" + } +} diff --git a/scheduler/quickstart.js b/scheduler/quickstart.js new file mode 100644 index 0000000000..f65e80d1e9 --- /dev/null +++ b/scheduler/quickstart.js @@ -0,0 +1,62 @@ +// Copyright 2018 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 +// +// 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. + +'use strict'; + +// sample-metadata: +// title: Quickstart +// description: POST "Hello World" to a URL every minute. +// usage: node quickstart.js [project-id] [location-id] [url] + +async function main(projectId, locationId, url) { + // [START scheduler_quickstart] + // const projectId = "PROJECT_ID" + // const locationId = "LOCATION_ID" // see: https://cloud.google.com/about/locations/ + // const url = "https://postb.in/..." // where should we say hello? + + const scheduler = require('@google-cloud/scheduler'); + + // Create a client. + const client = new scheduler.CloudSchedulerClient(); + + // Construct the fully qualified location path. + const parent = client.locationPath(projectId, locationId); + + // Construct the request body. + const job = { + httpTarget: { + uri: url, + httpMethod: 'POST', + body: Buffer.from('Hello World'), + }, + schedule: '* * * * *', + timeZone: 'America/Los_Angeles', + }; + + const request = { + parent: parent, + job: job, + }; + + // Use the client to send the job creation request. + const [response] = await client.createJob(request); + console.log(`Created job: ${response.name}`); + // [END scheduler_quickstart] +} + +const args = process.argv.slice(2); +main(...args).catch(err => { + console.error(err.message); + process.exitCode = 1; +}); diff --git a/scheduler/test/test.samples.js b/scheduler/test/test.samples.js new file mode 100644 index 0000000000..521dfd8499 --- /dev/null +++ b/scheduler/test/test.samples.js @@ -0,0 +1,70 @@ +// Copyright 2018 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 {CloudSchedulerClient} = require('@google-cloud/scheduler'); +const {assert} = require('chai'); +const {describe, it, before} = require('mocha'); +const cp = require('child_process'); +const supertest = require('supertest'); +const app = require('../app.js'); +const request = supertest(app); + +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); +const LOCATION_ID = process.env.LOCATION_ID || 'us-central1'; +const SERVICE_ID = 'my-service'; + +describe('Cloud Scheduler Sample Tests', () => { + let jobName; + let PROJECT_ID; + + before(async () => { + const client = new CloudSchedulerClient(); + PROJECT_ID = await client.getProjectId(); + }); + + it('should create and delete a scheduler job', async () => { + const stdout = execSync( + `node createJob.js ${PROJECT_ID} ${LOCATION_ID} ${SERVICE_ID}` + ); + assert.match(stdout, /Created job/); + jobName = stdout.split('/').pop(); + }); + + it('should update a scheduler job', async () => { + const stdout = execSync( + `node updateJob.js ${PROJECT_ID} ${LOCATION_ID} ${jobName}` + ); + assert.match(stdout, /Updated job/); + }); + + it('should delete a scheduler job', async () => { + const stdout = execSync( + `node deleteJob.js ${PROJECT_ID} ${LOCATION_ID} ${jobName}` + ); + assert.match(stdout, /Job deleted/); + }); +}); + +describe('Server should respond to /log_payload', () => { + it('should log the payload', done => { + const body = Buffer.from('test'); + request + .post('/log_payload') + .type('raw') + .send(body) + .expect(200, /Printed job/, done); + }); +}); diff --git a/scheduler/updateJob.js b/scheduler/updateJob.js new file mode 100644 index 0000000000..398add3afe --- /dev/null +++ b/scheduler/updateJob.js @@ -0,0 +1,58 @@ +// Copyright 2020 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. + +// sample-metadata: +// title: Update Job +// description: Update a job by its ID. +// usage: node updateJob.js [project-id] [location-id] [job-id] + +async function updateJob(projectId, locationId, jobId) { + const scheduler = require('@google-cloud/scheduler'); + + // Create a client. + const client = new scheduler.CloudSchedulerClient(); + + // TODO(developer): Uncomment and set the following variables + // const projectId = "PROJECT_ID" + // const locationId = "LOCATION_ID" + // const jobId = "JOB_ID" + + // Construct the fully qualified location path. + const job = client.jobPath(projectId, locationId, jobId); + + // Construct the request body. + const request = { + job: { + name: job, + description: 'Hello World example.', + timeZone: 'Australia/Perth', + httpTarget: {uri: 'http://example.com'}, + }, + updateMask: { + // Fields name in each path must use lower-camel naming conventions. + // https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#fieldmask + paths: ['description', 'time_zone', 'http_target'], + }, + }; + + // Use the client to send the job update request. + const [response] = await client.updateJob(request); + console.log(`Updated job: ${response.name}`); +} + +const args = process.argv.slice(2); +updateJob(...args).catch(err => { + console.error(err.message); + process.exitCode = 1; +});