From 854255e52e8af815e133ddb05cc8c1c7db0aaecd Mon Sep 17 00:00:00 2001 From: "Alex Ellis (OpenFaaS Ltd)" Date: Mon, 15 Feb 2021 17:35:35 +0000 Subject: [PATCH] Add node14 template For the current LTS version Signed-off-by: Alex Ellis (OpenFaaS Ltd) --- .gitignore | 3 +- template/node14/.dockerignore | 1 + template/node14/Dockerfile | 62 ++++++++++++ template/node14/function/handler.js | 12 +++ template/node14/function/package.json | 12 +++ template/node14/index.js | 140 ++++++++++++++++++++++++++ template/node14/package.json | 16 +++ template/node14/template.yml | 12 +++ 8 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 template/node14/.dockerignore create mode 100644 template/node14/Dockerfile create mode 100644 template/node14/function/handler.js create mode 100644 template/node14/function/package.json create mode 100644 template/node14/index.js create mode 100644 template/node14/package.json create mode 100644 template/node14/template.yml diff --git a/.gitignore b/.gitignore index b5e074fe..86da40ad 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,5 @@ build .idea **/bin/** .settings - -template +/**/package-lock.json /**/node_modules diff --git a/template/node14/.dockerignore b/template/node14/.dockerignore new file mode 100644 index 00000000..e84c3fba --- /dev/null +++ b/template/node14/.dockerignore @@ -0,0 +1 @@ +*/node_modules diff --git a/template/node14/Dockerfile b/template/node14/Dockerfile new file mode 100644 index 00000000..0f7c6ba3 --- /dev/null +++ b/template/node14/Dockerfile @@ -0,0 +1,62 @@ +FROM --platform=${TARGETPLATFORM:-linux/amd64} ghcr.io/openfaas/of-watchdog:0.8.3 as watchdog +FROM --platform=${TARGETPLATFORM:-linux/amd64} node:14-alpine as ship + +ARG TARGETPLATFORM +ARG BUILDPLATFORM + +COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog +RUN chmod +x /usr/bin/fwatchdog + +RUN apk --no-cache add curl ca-certificates \ + && addgroup -S app && adduser -S -g app app + +# Turn down the verbosity to default level. +ENV NPM_CONFIG_LOGLEVEL warn + +RUN chmod 777 /tmp + +USER app + +RUN mkdir -p /home/app/function + +# Wrapper/boot-strapper +WORKDIR /home/app +COPY package.json ./ + +# This ordering means the npm installation is cached for the outer function handler. +RUN npm i + +# Copy outer function handler +COPY index.js ./ + +# COPY function node packages and install, adding this as a separate +# entry allows caching of npm install + +WORKDIR /home/app/function +COPY function/*.json ./ + +RUN npm i + +# COPY function files and folders +COPY function/ ./ + +# Run any tests that may be available +RUN npm test + +# Set correct permissions to use non root user +WORKDIR /home/app/ + +ENV cgi_headers="true" +ENV fprocess="node index.js" +ENV mode="http" +ENV upstream_url="http://127.0.0.1:3000" + +ENV exec_timeout="10s" +ENV write_timeout="15s" +ENV read_timeout="15s" + +ENV prefix_logs="false" + +HEALTHCHECK --interval=3s CMD [ -e /tmp/.lock ] || exit 1 + +CMD ["fwatchdog"] diff --git a/template/node14/function/handler.js b/template/node14/function/handler.js new file mode 100644 index 00000000..18f543d4 --- /dev/null +++ b/template/node14/function/handler.js @@ -0,0 +1,12 @@ +'use strict' + +module.exports = async (event, context) => { + const result = { + 'body': JSON.stringify(event.body), + 'content-type': event.headers["content-type"] + } + + return context + .status(200) + .succeed(result) +} diff --git a/template/node14/function/package.json b/template/node14/function/package.json new file mode 100644 index 00000000..a3c013b0 --- /dev/null +++ b/template/node14/function/package.json @@ -0,0 +1,12 @@ +{ + "name": "openfaas-function", + "version": "1.0.0", + "description": "OpenFaaS Function", + "main": "handler.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 0" + }, + "keywords": [], + "author": "OpenFaaS Ltd", + "license": "MIT" +} diff --git a/template/node14/index.js b/template/node14/index.js new file mode 100644 index 00000000..fc7f5f52 --- /dev/null +++ b/template/node14/index.js @@ -0,0 +1,140 @@ +// Copyright (c) Alex Ellis 2021. All rights reserved. +// Copyright (c) OpenFaaS Author(s) 2021. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +"use strict" + +const express = require('express') +const app = express() +const handler = require('./function/handler'); +const bodyParser = require('body-parser') + +const defaultMaxSize = '100kb' // body-parser default + +app.disable('x-powered-by'); + +const rawLimit = process.env.MAX_RAW_SIZE || defaultMaxSize +const jsonLimit = process.env.MAX_JSON_SIZE || defaultMaxSize + +app.use(function addDefaultContentType(req, res, next) { + // When no content-type is given, the body element is set to + // nil, and has been a source of contention for new users. + + if(!req.headers['content-type']) { + req.headers['content-type'] = "text/plain" + } + next() +}) + +if (process.env.RAW_BODY === 'true') { + app.use(bodyParser.raw({ type: '*/*' , limit: rawLimit })) +} else { + app.use(bodyParser.text({ type : "text/*" })); + app.use(bodyParser.json({ limit: jsonLimit})); + app.use(bodyParser.urlencoded({ extended: true })); +} + +const isArray = (a) => { + return (!!a) && (a.constructor === Array); +}; + +const isObject = (a) => { + return (!!a) && (a.constructor === Object); +}; + +class FunctionEvent { + constructor(req) { + this.body = req.body; + this.headers = req.headers; + this.method = req.method; + this.query = req.query; + this.path = req.path; + } +} + +class FunctionContext { + constructor(cb) { + this.value = 200; + this.cb = cb; + this.headerValues = {}; + this.cbCalled = 0; + } + + status(value) { + if(!value) { + return this.value; + } + + this.value = value; + return this; + } + + headers(value) { + if(!value) { + return this.headerValues; + } + + this.headerValues = value; + return this; + } + + succeed(value) { + let err; + this.cbCalled++; + this.cb(err, value); + } + + fail(value) { + let message; + this.cbCalled++; + this.cb(value, message); + } +} + +const middleware = async (req, res) => { + const cb = (err, functionResult) => { + if (err) { + console.error(err); + + return res.status(500) + .send(err.toString ? err.toString() : err); + } + + if(isArray(functionResult) || isObject(functionResult)) { + res.set(fnContext.headers()) + .status(fnContext.status()).send(JSON.stringify(functionResult)); + } else { + res.set(fnContext.headers()) + .status(fnContext.status()) + .send(functionResult); + } + }; + + const fnEvent = new FunctionEvent(req); + const fnContext = new FunctionContext(cb); + + Promise.resolve(handler(fnEvent, fnContext, cb)) + .then(res => { + if(!fnContext.cbCalled) { + fnContext.succeed(res); + } + }) + .catch(e => { + cb(e); + }); +}; + +app.post('/*', middleware); +app.get('/*', middleware); +app.patch('/*', middleware); +app.put('/*', middleware); +app.delete('/*', middleware); +app.options('/*', middleware); + +const port = process.env.http_port || 3000; + +app.listen(port, () => { + console.log(`node12 listening on port: ${port}`) +}); + + diff --git a/template/node14/package.json b/template/node14/package.json new file mode 100644 index 00000000..b6a45c5e --- /dev/null +++ b/template/node14/package.json @@ -0,0 +1,16 @@ +{ + "name": "openfaas-node12", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no tests specified\" && exit 0" + }, + "keywords": [], + "author": "OpenFaaS Ltd", + "license": "MIT", + "dependencies": { + "body-parser": "^1.18.2", + "express": "^4.16.2" + } +} diff --git a/template/node14/template.yml b/template/node14/template.yml new file mode 100644 index 00000000..400004b4 --- /dev/null +++ b/template/node14/template.yml @@ -0,0 +1,12 @@ +language: node12 +fprocess: node index.js +welcome_message: | + You have created a new function which uses Node.js 12 (TLS) and the OpenFaaS + of-watchdog which gives greater control over HTTP responses. + + npm i --save can be used to add third-party packages like request or cheerio + npm documentation: https://docs.npmjs.com/ + + Unit tests are run at build time via "npm run", edit package.json to specify + how you want to execute them. +