Skip to content

Commit

Permalink
Add 'env' to the apps database, which is a String-to-String Object ma…
Browse files Browse the repository at this point in the history
…p that represents the environment variables that an app is to be run with. Add NODE_ENV="production" as a default env variable, but allow it to be overridden. Add RESTful /env API for managing environment variables.
  • Loading branch information
ckknight committed Apr 21, 2011
1 parent b6a1098 commit 4a62ff5
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 5 deletions.
12 changes: 12 additions & 0 deletions app.js
Expand Up @@ -105,6 +105,18 @@ myapp.delete('/gitreset', middle.authenticate, middle.authenticate_app, app.gitr
// curl -u "testuser:123" -d "appname=test" http://localhost:4001/applogs
myapp.get('/applogs/:appname', middle.authenticate, middle.authenticate_app, app.logs);

// Retrieve information about or update a node app's ENV variables
// This fulfills all four RESTful verbs.
// GET will retrieve the list of all keys.
// PUT will either create or update.
// DELETE will delete the key if it exists.
// curl -u GET -u "testuser:123" -d "appname=test" http://localhost:4001/env
// curl -u PUT -u "testuser:123" -d "appname=test&key=NODE_ENV&value=production" http://localhost:4001/env
// curl -u DELETE -u "testuser:123" -d "appname=test&key=NODE_ENV" http://localhost:4001/env
myapp.get('/env', middle.authenticate, middle.authenticate_app, app.env_get);
myapp.put('/env', middle.authenticate, middle.authenticate_app, app.env_put);
myapp.delete('/env', middle.authenticate, middle.authenticate_app, app.env_delete);

// APP NPM Handlers
var npm = require('./lib/npm');
// curl -X POST -u "testuser:123" -d "appname=test&package=express" http://localhost:4001/appnpm
Expand Down
86 changes: 84 additions & 2 deletions lib/app.js
Expand Up @@ -304,7 +304,8 @@ module.exports = {
username: user._id,
repo_id: repo_id,
running: false,
pid: 'unknown'
pid: 'unknown',
env: {}
}, function (err, resp) {
if (err) {
res.writeHead(500, { 'Content-Type': 'application/json' });
Expand Down Expand Up @@ -353,9 +354,89 @@ module.exports = {
res.send({status: "failure", message: "app exists"});
}
});
},
env_get: function(req, res, next) {
var appname = req.body.appname.toLowerCase();
var db = lib.get_couchdb_database('apps');
db.get(appname, function (err, appdoc) {
if (err) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({status: "failure", message: err.error + ' - ' + err.reason}) + '\n');
} else {
var start = req.body.start;
db.get(appname, function (err, doc) {
if (err) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({status: "failure", message: err.error + ' - ' + err.reason}) + '\n');
} else {
res.send({status: "success", message: doc.env || {}});
}
});
}
});
},
env_put: function(req, res, next) {
var appname = req.body.appname.toLowerCase();
var db = lib.get_couchdb_database('apps');
var key = req.body.key,
value = req.body.value;
if (!key || !value) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({status: "false", message: "Must specify both key and value."}) + "\n");
res.end();
return;
}
db.get(appname, function (err, appdoc) {
if (err) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({status: "failure", message: err.error + ' - ' + err.reason}) + '\n');
} else {
env_update(res, db, appname, appdoc, key, value);
}
});
},
env_delete: function(req, res, next) {
var appname = req.body.appname.toLowerCase();
var db = lib.get_couchdb_database('apps');
var key = req.body.key;
if (!key) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({status: "false", message: "Must specify key."}) + "\n");
res.end();
return;
}
db.get(appname, function (err, appdoc) {
if (err) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({status: "failure", message: err.error + ' - ' + err.reason}) + '\n');
} else {
env_update(res, db, appname, appdoc, key, undefined);
}
});
}
}

var env_update = function(res, db, appname, appdoc, key, value) {
var env = {};
if (appdoc.env) {
Object.keys(appdoc.env).forEach(function (k) {
env[k] = appdoc.env[k];
});
}
if (value !== undefined) {
env[key] = value;
} else {
delete env[key];
}
db.merge(appname, {env: env}, function(err, resp) {
if (err) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({status: "failure", message: err.error + ' - ' + err.reason}) + '\n');
} else {
res.send({status: "success", message: value === undefined ? ("DELETE " + key) : (key + "=" + value)});
}
});
};

var force_stop = function(repo_id, callback) {
console.log('Forcing stop for: ', repo_id);
Expand Down Expand Up @@ -433,7 +514,8 @@ var app_start = function (repo_id, callback) {
start: app.start,
port: app.port,
ip: '127.0.0.1',
name: doc.appname
name: doc.appname,
env: app.env || {}
};
console.log('Checking: ', app_home);
if (!path.existsSync(app_home)) {
Expand Down
16 changes: 13 additions & 3 deletions scripts/launch_chrooted_app.js
Expand Up @@ -82,10 +82,20 @@ daemon.daemonize(path.join('.nodester', 'logs', 'daemon.log'), path.join('.nodes
sandbox.process.installPrefix = '/';
sandbox.process.ARGV = ['node', config.start];
sandbox.process.argv = sandbox.process.ARGV;
sandbox.process.env = sandbox.process.ENV = {
'app_port': app_port,
'app_host': app_host
var env = sandbox.process.env = sandbox.process.ENV = {
// defaults which can be overriden
NODE_ENV: "production"
};

if (config.env) {
Object.keys(config.env).forEach(function (key) {
env[key] = String(config.env[key]);
});
}

// environment variables which cannot be overriden by config.
env.app_port = app_port;
env.app_host = app_host;
sandbox.process.mainModule = sandbox.module;
sandbox.process.kill = function () { return 'process.kill is disabled' };
sandbox.process.stdout.write = sandbox.console.warn = sandbox.console.error = function (args) {
Expand Down

0 comments on commit 4a62ff5

Please sign in to comment.