diff --git a/src/function-run/nodejs/Dockerfile b/src/function-run/nodejs/Dockerfile new file mode 100644 index 00000000..8d8b54a9 --- /dev/null +++ b/src/function-run/nodejs/Dockerfile @@ -0,0 +1,7 @@ +# A docker image for the func container. + +FROM node:4-onbuild + +ADD server.js /usr/src/app/server.js + +EXPOSE 8888 diff --git a/src/function-run/nodejs/package.json b/src/function-run/nodejs/package.json new file mode 100644 index 00000000..fcd3f671 --- /dev/null +++ b/src/function-run/nodejs/package.json @@ -0,0 +1,20 @@ +{ + "name": "fission-nodejs-runtime", + "version": "0.0.0", + "author": "Soam Vasani", + "contributors": [ + { + "name": "Soam Vasani", + "email": "soamvasani@platform9.com" + } + ], + "description": "NodeJS run container for the fission framework", + "engines": { + "node": ">=4.2.2" + }, + "dependencies": { + "express": "", + "minimist": "", + "body-parser": "" + } +} diff --git a/src/function-run/nodejs/server.js b/src/function-run/nodejs/server.js new file mode 100644 index 00000000..059189f4 --- /dev/null +++ b/src/function-run/nodejs/server.js @@ -0,0 +1,74 @@ +'use strict'; + +const fs = require('fs'); +const process = require('process'); +const express = require('express'); +const app = express(); +const bodyParser = require('body-parser'); + +// Command line opts +const argv = require('minimist')(process.argv.slice(1)); +if (!argv.codepath || !argv.port) { + console.error("Need --codepath and --port"); + process.exit(1); +} + +// User function. Starts out undefined. +let userFunction; + +// +// Specialize this server to a given user function. The user function +// is read from argv.codepath; it's expected to be placed there by the +// fission runtime. +// +function specialize(req, res) { + // Make sure we're a generic container. (No reuse of containers. + // Once specialized, the container remains specialized.) + if (userFunction) { + res.status(400).send("Not a generic container"); + return; + } + + // Read and load the code. It's placed there securely by the fission runtime. + try { + var startTime = process.hrtime(); + userFunction = require(argv.codepath); + var elapsed = process.hrtime(startTime); + console.log(`user code loaded in ${elapsed[0]}sec ${elapsed[1]/1000000}ms`); + } catch(e) { + console.error(`user code load error: ${e}`); + res.status(500).send(JSON.stringify(e)); + return; + } + res.status(202).send(); +} + + +app.use(bodyParser.json()); +app.post('/specialize', specialize); + +// Generic route -- all http requests go to the user function. +app.all('/', function (req, res) { + if (!userFunction) { + res.status(500).send("Generic container: no requests supported"); + return; + } + const context = { + request: req, + response: res + // TODO: context should also have: URL template params, query string, ...anything else? + }; + function callback(status, body, headers) { + if (!status) + return; + if (headers) { + for (let name of Object.keys(headers)) { + res.set(name, headers[name]); + } + } + res.status(status).send(body); + } + userFunction(context, callback); +}); + +app.listen(argv.port); diff --git a/src/function-run/nodejs/test/test.js b/src/function-run/nodejs/test/test.js new file mode 100644 index 00000000..288ef627 --- /dev/null +++ b/src/function-run/nodejs/test/test.js @@ -0,0 +1,5 @@ +module.exports = function (context, callback) { + console.log("Test function entered"); + callback(200, "Hello, world!\n"); + console.log("Test function exit"); +} diff --git a/src/function-run/nodejs/test/test.sh b/src/function-run/nodejs/test/test.sh new file mode 100755 index 00000000..49907e64 --- /dev/null +++ b/src/function-run/nodejs/test/test.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# TODO placeholder until we have better tests :) + +set +x +set -e + +DIR=$(dirname $0) + +echo "-- Starting server" +node $DIR/../server.js --codepath $DIR/test.js --port 8888 & +function cleanup() { + echo "-- Cleanup" + kill %1 +} +trap cleanup EXIT +sleep 2 + +echo "-- Specializing" +curl -f -X POST http://localhost:8888/specialize + +echo "-- Running user function" +curl -f -X GET http://localhost:8888 +curl -f -X POST http://localhost:8888 +curl -f -X PUT http://localhost:8888 +curl -f -X DELETE http://localhost:8888 +curl -f -X TRACE http://localhost:8888 +curl -f -X OPTIONS http://localhost:8888 + +# -I causes curl to make a HEAD request. +curl -f -I http://localhost:8888