4 var fs = require("fs");
6 var debug_output = false;
7 var default_loop_time = 2000;
9 // set the global context
10 global.lxcnodejs = new Object();
13 if(process.getuid() == 0) {
16 console.log("Not running as root, assuming debug mode, config file should be ./config");
19 if(asroot) var mnt = require("/node_modules/mount");
22 console.log("Mounting proc");
24 mnt.mount("proc", "/proc", "proc");
26 //console.log("fake mount");
27 console.log("(debug) pass /proc mount");
30 // get the global space setup
33 // read main and node config file and parse
35 console.log("Reading config file /config");
36 loadConfig("/config");
37 loadNodeConfig("/node_base/appconfig", "/node_base");
39 console.log("Reading config file ./config (debug mode)");
40 loadConfig("./config");
41 loadNodeConfig("./appconfig", ".");
44 // begin the main loop
48 if(debug_output) console.log("(debug) main loop now begins with process monitor");
58 function loadNodeConfig(file, basedir) {
59 var configFile = fs.readFileSync(file).toString();
60 var lines = configFile.split("\n");
61 var nodes = new Object();
63 for(var i=0; i < lines.length; i++) {
64 //console.log("line: ", lines[i].trim());
65 var sks = lines[i].match(/^[^#][a-zA-Z0-9:]+/);
67 if(sks != null) lks = lines[i].split(":");
69 stl = lines[i].split(":");
70 //console.log("lks is: '%s', '%s'", stl[0], stl[1]);
72 console.log("Invalid config line '%s', should be 'appname:directory:appfilepath[:options]'", lines[i].trim());
75 if(stl[3] != null) args = stl[3];
76 nodes[stl[0]] = new Object();
77 nodes[stl[0]].directory = stl[1];
78 nodes[stl[0]].file = stl[2];
79 nodes[stl[0]].args = args;
80 console.log("Adding node config for '%s'", stl[0]);
85 // check our config against the current global
86 for(key in global.lxcnodejs) {
87 if(typeof nodes[key] == "undefined") {
88 global.lxcnodejs[key].stop_and_kill = true;
90 if(global.lxcnodejs[key].directory != nodes[key].directory) {
91 if(debug_output) console.log("(debug) marking '%s' for restart on config change (directory)", key);
92 global.lxcnodejs[key].directory = nodes[key].directory;
93 global.lxcnodejs[key].restart = true;
95 if(global.lxcnodejs[key].file != nodes[key].file) {
96 if(debug_output) console.log("(debug) marking '%s' for restart on config change (file)", key);
97 global.lxcnodejs[key].file = nodes[key].file;
98 global.lxcnodejs[key].restart = true;
100 if(global.lxcnodejs[key].args != nodes[key].args) {
101 if(debug_output) console.log("(debug) marking '%s' for restart on config change (options)", key);
102 global.lxcnodejs[key].args = nodes[key].args;
103 global.lxcnodejs[key].restart = true;
108 // check for new configs and load them
110 if(typeof global.lxcnodejs[key] == "undefined") {
111 if(debug_output) console.log("(debug) application '%s' is a new config, creating", key);
112 global.lxcnodejs[key] = new Object();
113 global.lxcnodejs[key].directory = nodes[key].directory;
114 global.lxcnodejs[key].file = nodes[key].file;
115 global.lxcnodejs[key].args = nodes[key].args;
116 global.lxcnodejs[key].pid = -1;
121 function loadConfig(file) {
122 var configFile = fs.readFileSync(file).toString();
124 var lines = configFile.split("\n");
126 for(var i=0; i < lines.length; i++) {
127 //console.log("line: ", lines[i].trim());
128 var lks = lines[i].match(/^[^#][a-zA-Z0-9]+\=.*/);
130 stl = lines[i].split("=");
131 //console.log("lks is: '%s', '%s'", stl[0], stl[1]);
133 console.log("Invalid config line '%s', should be name=value format", lines[i].trim());
135 parseConfigLine(stl[0].trim(), stl[1].trim());
141 function parseConfigLine(key, value) {
142 //console.log("parsing config '%s' = '%s'", key, value);
145 var lxon = value.split(":");
149 console.log("Address config isnt correct, expect 'interface:address/mask'");
153 console.log("IPv4 address for '%s' is '%s'", iface, addrs);
155 var nodespawn = require("child_process").spawn,
156 nodeproc = nodespawn("/sbin/ip", ["link", "set", iface, "address", addrs, "up"], opts);
158 if(debug_output) console.log("(debug) would run /sbin/ip link set %s address %s up", iface, addrs);
163 var lxon = value.split(":");
167 console.log("Address config isnt correct, expect 'interface:address/mask'");
171 console.log("IPv4 address for '%s' is '%s'", iface, addrs);
175 console.log("Default IPv4 gateway is: '%s'", value);
177 var nodespawn = require("child_process").spawn,
178 nodeproc = nodespawn("/sbin/ip", ["route", "add", "default", "via", value], opts);
180 if(debug_output) console.log("(debug) would run /sbin/ip route add default via %s", value);
184 console.log("Setting health check timer to %s ms", value);
185 default_loop_time = parseInt(value);
186 if(default_loop_time < 100) {
187 console.log("(warning) health check timer must be larger then 100, setting to 100, was %s", value);
188 default_loop_time = 100;
192 console.log("Default IPv6 gateway is: '%s'", value);
195 console.log("DNS address set to: '%s'", value);
198 console.log("Hostname set to: '%s'", value);
201 if(value == "true") {
203 console.log("(debug) Turning debugging on");
206 console.log("Unknown config line: '%s' = '%s'", key, value);
210 function startApp(appname, directory, file, uid) {
212 var opts = { uid: uid, env: process.env, cwd: directory };
213 var sleeplen = Math.floor(Math.random()*60);
214 var nodespawn = require("child_process").spawn;
218 nodeproc = nodespawn("/node/bin/node", ["/node_code/nc.js"], opts);
220 if(debug_output) console.log("(debug) using sleep to emulator process '%s'", appname);
221 nodeproc = nodespawn("sleep", [sleeplen], opts);
224 nodeproc.procname = appname;
225 global.lxcnodejs[appname].pid = nodeproc.pid;
227 if(debug_output) console.log("(debug) application started with pid of %d", nodeproc.pid);
229 nodeproc.stdout.on("data", function(data) {
230 console.log("data from nodespawn: '%s', '%s'", data, nodeproc.procname);
232 nodeproc.stderr.on("data", function(data) {
233 console.log("stderrdata from nodespawn: '%s', '%s'", data, nodeproc.procname);
235 nodeproc.on("exit", function(data) {
236 console.log("nodespawn died for '%s'", nodeproc.procname);
237 global.lxcnodejs[nodeproc.procname].pid = 0;
241 // main loop does all starting/restarting of applications
242 function startMainLoop() {
243 // this loop kicks around every 5 seconds and just checks on the health of the processes or whatever
244 for(key in global.lxcnodejs) {
245 if(debug_output) console.log("(debug) checking state of '%s'", key);
246 if(typeof global.lxcnodejs[key].pid == "undefined") {
248 console.log("Starting application '%s' (no pid was defined)", key);
249 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
250 } else if(global.lxcnodejs[key].pid == -1) {
252 console.log("Starting application '%s' (initial start)", key);
253 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
254 } else if(global.lxcnodejs[key].pid == 0) {
256 console.log("Starting application '%s' (pid 0, possible application crash?)", key);
257 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
258 } else if(typeof global.lxcnodejs[key].restart != "undefined") {
260 console.log("Restarting application '%s' (restart defined)", key);
261 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
262 } else if(typeof global.lxcnodejs[key].stop_and_kill != "undefined") {
264 console.log("Restarting application '%s'", key);
266 if(debug_output) console.log("(debug) state of '%s' is healthy", key);
269 // we also need to check the control directory and see
270 // if theres any control files
273 // and restart the loop
274 setTimeout(startMainLoop, default_loop_time);