3 // VERSION_FOR_PARSER: 0.0.1
6 var fs = require("fs");
8 var debug_output = false;
9 var default_loop_time = 2000;
11 // set the global context
12 global.lxcnodejs = new Object();
15 if(process.getuid() == 0) {
18 console.log("Not running as root, assuming debug mode, config file should be ./config");
21 if(asroot) var mnt = require("/node_modules/mount");
24 console.log("Mounting proc");
26 mnt.mount("proc", "/proc", "proc");
28 //console.log("fake mount");
29 console.log("(debug) pass /proc mount");
32 // get the global space setup
35 // read main and node config file and parse
37 console.log("Reading config file /config");
38 loadConfig("/config");
39 loadNodeConfig("/node_base/appconfig", "/node_base");
41 console.log("Reading config file ./config (debug mode)");
42 loadConfig("./config");
43 loadNodeConfig("./appconfig", ".");
46 // begin the main loop
50 if(debug_output) console.log("(debug) main loop now begins with process monitor");
60 function loadNodeConfig(file, basedir) {
61 var configFile = fs.readFileSync(file).toString();
62 var lines = configFile.split("\n");
63 var nodes = new Object();
65 for(var i=0; i < lines.length; i++) {
66 //console.log("line: ", lines[i].trim());
67 var sks = lines[i].match(/^[^#][a-zA-Z0-9:]+/);
69 if(sks != null) lks = lines[i].split(":");
71 stl = lines[i].split(":");
72 //console.log("lks is: '%s', '%s'", stl[0], stl[1]);
74 console.log("Invalid config line '%s', should be 'appname:directory:appfilepath[:options]'", lines[i].trim());
77 if(stl[3] != null) args = stl[3];
78 nodes[stl[0]] = new Object();
79 nodes[stl[0]].directory = stl[1];
80 nodes[stl[0]].file = stl[2];
81 nodes[stl[0]].args = args;
82 console.log("Adding node config for '%s'", stl[0]);
87 // check our config against the current global
88 for(key in global.lxcnodejs) {
89 if(typeof nodes[key] == "undefined") {
90 global.lxcnodejs[key].stop_and_kill = true;
92 if(global.lxcnodejs[key].directory != nodes[key].directory) {
93 if(debug_output) console.log("(debug) marking '%s' for restart on config change (directory)", key);
94 global.lxcnodejs[key].directory = nodes[key].directory;
95 global.lxcnodejs[key].restart = true;
97 if(global.lxcnodejs[key].file != nodes[key].file) {
98 if(debug_output) console.log("(debug) marking '%s' for restart on config change (file)", key);
99 global.lxcnodejs[key].file = nodes[key].file;
100 global.lxcnodejs[key].restart = true;
102 if(global.lxcnodejs[key].args != nodes[key].args) {
103 if(debug_output) console.log("(debug) marking '%s' for restart on config change (options)", key);
104 global.lxcnodejs[key].args = nodes[key].args;
105 global.lxcnodejs[key].restart = true;
110 // check for new configs and load them
112 if(typeof global.lxcnodejs[key] == "undefined") {
113 if(debug_output) console.log("(debug) application '%s' is a new config, creating", key);
114 global.lxcnodejs[key] = new Object();
115 global.lxcnodejs[key].directory = nodes[key].directory;
116 global.lxcnodejs[key].file = nodes[key].file;
117 global.lxcnodejs[key].args = nodes[key].args;
118 global.lxcnodejs[key].pid = -1;
123 function loadConfig(file) {
124 var configFile = fs.readFileSync(file).toString();
126 var lines = configFile.split("\n");
128 for(var i=0; i < lines.length; i++) {
129 //console.log("line: ", lines[i].trim());
130 var lks = lines[i].match(/^[^#][a-zA-Z0-9]+\=.*/);
132 stl = lines[i].split("=");
133 //console.log("lks is: '%s', '%s'", stl[0], stl[1]);
135 console.log("Invalid config line '%s', should be name=value format", lines[i].trim());
137 parseConfigLine(stl[0].trim(), stl[1].trim());
143 function parseConfigLine(key, value) {
144 //console.log("parsing config '%s' = '%s'", key, value);
147 var lxon = value.split(":");
151 console.log("Address config isnt correct, expect 'interface:address/mask'");
155 console.log("IPv4 address for '%s' is '%s'", iface, addrs);
157 var nodespawn = require("child_process").spawn,
158 nodeproc = nodespawn("/sbin/ip", ["link", "set", iface, "address", addrs, "up"], opts);
160 if(debug_output) console.log("(debug) would run /sbin/ip link set %s address %s up", iface, addrs);
165 var lxon = value.split(":");
169 console.log("Address config isnt correct, expect 'interface:address/mask'");
173 console.log("IPv4 address for '%s' is '%s'", iface, addrs);
177 console.log("Default IPv4 gateway is: '%s'", value);
179 var nodespawn = require("child_process").spawn,
180 nodeproc = nodespawn("/sbin/ip", ["route", "add", "default", "via", value], opts);
182 if(debug_output) console.log("(debug) would run /sbin/ip route add default via %s", value);
186 console.log("Setting health check timer to %s ms", value);
187 default_loop_time = parseInt(value);
188 if(default_loop_time < 100) {
189 console.log("(warning) health check timer must be larger then 100, setting to 100, was %s", value);
190 default_loop_time = 100;
194 console.log("Default IPv6 gateway is: '%s'", value);
197 console.log("DNS address set to: '%s'", value);
200 console.log("Hostname set to: '%s'", value);
203 if(value == "true") {
205 console.log("(debug) Turning debugging on");
208 console.log("Unknown config line: '%s' = '%s'", key, value);
212 function startApp(appname, directory, file, uid) {
214 var opts = { uid: uid, env: process.env, cwd: directory };
215 var sleeplen = Math.floor(Math.random()*60);
216 var nodespawn = require("child_process").spawn;
220 nodeproc = nodespawn("/node/bin/node", ["/node_code/nc.js"], opts);
222 if(debug_output) console.log("(debug) using sleep to emulator process '%s'", appname);
223 nodeproc = nodespawn("sleep", [sleeplen], opts);
226 nodeproc.procname = appname;
227 global.lxcnodejs[appname].pid = nodeproc.pid;
229 if(debug_output) console.log("(debug) application started with pid of %d", nodeproc.pid);
231 nodeproc.stdout.on("data", function(data) {
232 console.log("data from nodespawn: '%s', '%s'", data, nodeproc.procname);
234 nodeproc.stderr.on("data", function(data) {
235 console.log("stderrdata from nodespawn: '%s', '%s'", data, nodeproc.procname);
237 nodeproc.on("exit", function(data) {
238 console.log("nodespawn died for '%s'", nodeproc.procname);
239 global.lxcnodejs[nodeproc.procname].pid = 0;
243 // main loop does all starting/restarting of applications
244 function startMainLoop() {
245 // this loop kicks around every 5 seconds and just checks on the health of the processes or whatever
246 for(key in global.lxcnodejs) {
247 if(debug_output) console.log("(debug) checking state of '%s'", key);
248 if(typeof global.lxcnodejs[key].pid == "undefined") {
250 console.log("Starting application '%s' (no pid was defined)", key);
251 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
252 } else if(global.lxcnodejs[key].pid == -1) {
254 console.log("Starting application '%s' (initial start)", key);
255 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
256 } else if(global.lxcnodejs[key].pid == 0) {
258 console.log("Starting application '%s' (pid 0, possible application crash?)", key);
259 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
260 } else if(typeof global.lxcnodejs[key].restart != "undefined") {
262 console.log("Restarting application '%s' (restart defined)", key);
263 startApp(key, global.lxcnodejs[key].directory, global.lxcnodejs[key].file, null);
264 } else if(typeof global.lxcnodejs[key].stop_and_kill != "undefined") {
266 console.log("Restarting application '%s'", key);
268 if(debug_output) console.log("(debug) state of '%s' is healthy", key);
271 // we also need to check the control directory and see
272 // if theres any control files
275 // and restart the loop
276 setTimeout(startMainLoop, default_loop_time);