3 // this next line is used by the parse_dist.php bit to create its version info
4 // VERSION_FOR_PARSER: 0.0.1
7 var fs = require("fs");
9 var debug_output = false;
10 var default_loop_time = 2000;
12 // set the global context
13 global.lxcnodejs = new Object();
16 if(process.getuid() == 0) {
19 console.log("Not running as root, assuming debug mode, config file should be ./config");
22 if(asroot) var mnt = require("/node_modules/mount");
25 console.log("Mounting proc");
27 mnt.mount("proc", "/proc", "proc");
29 //console.log("fake mount");
30 console.log("(debug) pass /proc mount");
33 // get the global space setup
36 // read main and node config file and parse
38 console.log("Reading config file /config");
39 loadConfig("/config");
40 loadNodeConfig("/node_base/appconfig", "/node_base");
42 console.log("Reading config file ./config (debug mode)");
43 loadConfig("./config");
44 loadNodeConfig("./appconfig", ".");
47 // begin the main loop
51 if(debug_output) console.log("(debug) main loop now begins with process monitor");
61 function loadNodeConfig(file, basedir) {
62 var configFile = fs.readFileSync(file).toString();
63 var lines = configFile.split("\n");
64 var nodes = new Object();
66 for(var i=0; i < lines.length; i++) {
67 //console.log("line: ", lines[i].trim());
68 var sks = lines[i].match(/^[^#][a-zA-Z0-9:]+/);
70 if(sks != null) lks = lines[i].split(":");
72 stl = lines[i].split(":");
73 //console.log("lks is: '%s', '%s'", stl[0], stl[1]);
75 console.log("Invalid config line '%s', should be 'appname:directory:appfilepath[:options]'", lines[i].trim());
78 if(stl[3] != null) args = stl[3];
79 nodes[stl[0]] = new Object();
80 nodes[stl[0]].directory = stl[1];
81 nodes[stl[0]].file = stl[2];
82 nodes[stl[0]].args = args;
83 console.log("Adding node config for '%s'", stl[0]);
88 // check our config against the current global
89 for(key in global.lxcnodejs) {
90 if(typeof nodes[key] == "undefined") {
91 global.lxcnodejs[key].stop_and_kill = true;
93 if(global.lxcnodejs[key].directory != nodes[key].directory) {
94 if(debug_output) console.log("(debug) marking '%s' for restart on config change (directory)", key);
95 global.lxcnodejs[key].directory = nodes[key].directory;
96 global.lxcnodejs[key].restart = true;
98 if(global.lxcnodejs[key].file != nodes[key].file) {
99 if(debug_output) console.log("(debug) marking '%s' for restart on config change (file)", key);
100 global.lxcnodejs[key].file = nodes[key].file;
101 global.lxcnodejs[key].restart = true;
103 if(global.lxcnodejs[key].args != nodes[key].args) {
104 if(debug_output) console.log("(debug) marking '%s' for restart on config change (options)", key);
105 global.lxcnodejs[key].args = nodes[key].args;
106 global.lxcnodejs[key].restart = true;
111 // check for new configs and load them
113 if(typeof global.lxcnodejs[key] == "undefined") {
114 if(debug_output) console.log("(debug) application '%s' is a new config, creating", key);
115 global.lxcnodejs[key] = new Object();
116 global.lxcnodejs[key].directory = nodes[key].directory;
117 global.lxcnodejs[key].file = nodes[key].file;
118 global.lxcnodejs[key].args = nodes[key].args;
119 global.lxcnodejs[key].pid = -1;
124 function loadConfig(file) {
125 var configFile = fs.readFileSync(file).toString();
127 var lines = configFile.split("\n");
129 for(var i=0; i < lines.length; i++) {
130 //console.log("line: ", lines[i].trim());
131 var lks = lines[i].match(/^[^#][a-zA-Z0-9]+\=.*/);
133 stl = lines[i].split("=");
134 //console.log("lks is: '%s', '%s'", stl[0], stl[1]);
136 console.log("Invalid config line '%s', should be name=value format", lines[i].trim());
138 parseConfigLine(stl[0].trim(), stl[1].trim());
144 function parseConfigLine(key, value) {
145 //console.log("parsing config '%s' = '%s'", key, value);
148 var lxon = value.split(":");
152 console.log("Address config isnt correct, expect 'interface:address/mask'");
156 console.log("IPv4 address for '%s' is '%s'", iface, addrs);
158 var nodespawn = require("child_process").spawn,
159 nodeproc = nodespawn("/sbin/ip", ["link", "set", iface, "address", addrs, "up"], opts);
161 if(debug_output) console.log("(debug) would run /sbin/ip link set %s address %s up", iface, addrs);
166 var lxon = value.split(":");
170 console.log("Address config isnt correct, expect 'interface:address/mask'");
174 console.log("IPv4 address for '%s' is '%s'", iface, addrs);
178 console.log("Default IPv4 gateway is: '%s'", value);
180 var nodespawn = require("child_process").spawn,
181 nodeproc = nodespawn("/sbin/ip", ["route", "add", "default", "via", value], opts);
183 if(debug_output) console.log("(debug) would run /sbin/ip route add default via %s", value);
187 console.log("Setting health check timer to %s ms", value);
188 default_loop_time = parseInt(value);
189 if(default_loop_time < 100) {
190 console.log("(warning) health check timer must be larger then 100, setting to 100, was %s", value);
191 default_loop_time = 100;
195 console.log("Default IPv6 gateway is: '%s'", value);
198 console.log("DNS address set to: '%s'", value);
201 console.log("Hostname set to: '%s'", value);
204 if(value == "true") {
206 console.log("(debug) Turning debugging on");
209 console.log("Unknown config line: '%s' = '%s'", key, value);
213 function startApp(appname, directory, file, uid) {
215 var opts = { uid: uid, env: process.env, cwd: directory };
216 var sleeplen = Math.floor(Math.random()*60);
217 var nodespawn = require("child_process").spawn;
221 nodeproc = nodespawn("/node/bin/node", ["/node_code/nc.js"], opts);
223 if(debug_output) console.log("(debug) using sleep to emulator process '%s'", appname);
224 nodeproc = nodespawn("sleep", [sleeplen], opts);
227 nodeproc.procname = appname;
228 global.lxcnodejs[appname].pid = nodeproc.pid;
230 if(debug_output) console.log("(debug) application started with pid of %d", nodeproc.pid);
232 nodeproc.stdout.on("data", function(data) {
233 console.log("data from nodespawn: '%s', '%s'", data, nodeproc.procname);
235 nodeproc.stderr.on("data", function(data) {
236 console.log("stderrdata from nodespawn: '%s', '%s'", data, nodeproc.procname);
238 nodeproc.on("exit", function(data) {
239 console.log("nodespawn died for '%s'", nodeproc.procname);
240 global.lxcnodejs[nodeproc.procname].pid = 0;
244 // main loop does all starting/restarting of applications
245 function startMainLoop() {
246 // this loop kicks around every 5 seconds and just checks on the health of the processes or whatever
247 for(key in global.lxcnodejs) {
248 if(debug_output) console.log("(debug) checking state of '%s'", key);
249 if(typeof global.lxcnodejs[key].pid == "undefined") {
251 console.log("Starting application '%s' (no pid was defined)", key);
252 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
253 } else if(global.lxcnodejs[key].pid == -1) {
255 console.log("Starting application '%s' (initial start)", key);
256 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
257 } else if(global.lxcnodejs[key].pid == 0) {
259 console.log("Starting application '%s' (pid 0, possible application crash?)", key);
260 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
261 } else if(typeof global.lxcnodejs[key].restart != "undefined") {
263 console.log("Restarting application '%s' (restart defined)", key);
264 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
265 } else if(typeof global.lxcnodejs[key].stop_and_kill != "undefined") {
267 console.log("Restarting application '%s'", key);
269 if(debug_output) console.log("(debug) state of '%s' is healthy", key);
272 // we also need to check the control directory and see
273 // if theres any control files
276 // and restart the loop
277 setTimeout(startMainLoop, default_loop_time);