NodeJS Function Run Container
First cut of a function run container for NodeJS. So far, just the simplest stuff: loads a user function and routes requests to it. The user function is assumed to be in a file at a provided location. The fission runtime is expected to place the file there securely (exactly how we'll do that is TBD). Doesn't handle path template params, query strings, etc. Will also need to be extended later with some sort of hook for graceful shutdown.
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"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": "",
|
||||
|
||||
"require-from-string": ""
|
||||
},
|
||||
"start": "node server.js --codepath '/fission/function' --port 8888"
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var process = require('process');
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
var bodyParser = require('body-parser');
|
||||
|
||||
// Command line opts
|
||||
const argv = require('minimist')(process.argv.slice(1));
|
||||
if (!argv.codepath || !argv.port) {
|
||||
console.log("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();
|
||||
|
||||
const code = fs.readFileSync(argv.codepath).toString();
|
||||
userFunction = eval(code);
|
||||
|
||||
var elapsed = process.hrtime(startTime);
|
||||
console.log(`user code loaded in ${elapsed[0]}sec ${elapsed[1]}ns`);
|
||||
} catch(e) {
|
||||
console.log(`eval 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);
|
||||
Reference in New Issue
Block a user