ref: master
cmd/beterrabad/executor.ha
use log; use fmt; use os; use os::exec; use strings; use beterraba; type booterror = !(exec::error | exec::nocmd); fn status_service(svcname: str, serv: *server) str = { let service: nullable *beterraba::service = null; for (let i = 0z; i < len(serv.services); i += 1) { if (serv.services[i].name == svcname) { service = &serv.services[i]; break; }; }; match (service) { case null => return "Didn't find a service with that name"; case let svc: *beterraba::service => match (peek(svc)) { case let stat: beterraba::status => return beterraba::strstatus(stat); case void => return "WTF"; }; }; }; fn start_service(svcname: str, serv: *server) str = { let service: nullable *beterraba::service = null; for (let i = 0z; i < len(serv.services); i += 1) { if (serv.services[i].name == svcname) { service = &serv.services[i]; break; }; }; match (service) { case null => return "Didn't find a service with that name"; case let svc: *beterraba::service => match (boot(svc)) { case let err: booterror => return bootstrerror(err); case void => return "Started successfully"; }; }; }; fn notify_service(status: str, svcname: str, serv: *server) str = { log::printfln("Notified on {}", svcname); let service: nullable *beterraba::service = null; for (let i = 0z; i < len(serv.services); i += 1) { if (serv.services[i].name == svcname) { service = &serv.services[i]; break; }; }; match (service) { case null => return "Didn't find a service with that name"; case let svc: *beterraba::service => svc.status = beterraba::statusfromstr(status); log::println("Set svc status to {}", beterraba::strstatus(svc.status)); return "ack"; }; }; fn list_services(cmdargs: str, serv: *server) str = { let names: []str = []; defer free(names); for (let i = 0z; i < len(serv.services); i += 1) { append(names, serv.services[i].name); }; return strings::join("|", names...); }; // Check if the process is still alive and bail out if it's ok fn peek(service: *beterraba::service) (void | beterraba::status) = { // TODO: Move this kind of thing into a better structured log facility log::printfln("Peeking on {}", service.name); match (exec::peek(&service.process)) { case let s: exec::status => let status = exec::exit(&s); match (status) { case exec::exit_status => service.status = beterraba::status::STOPPED; return beterraba::status::STOPPED; case exec::signaled => // TODO: Add the exit msg service.status = beterraba::status::CRASHED; }; case void => return beterraba::status::STARTED; case let err: exec::error => service.status = beterraba::status::CRASHED; return beterraba::status::CRASHED; }; }; // Try to recover a service which might have crashed fn recover(service: *beterraba::service) void = { fmt::printfln("Implement!")!; }; // XXX: This method should yield a booterror which we should eventually // translate it back to a str, the same goes to other methods fn boot(service: *beterraba::service) (void | booterror) = { log::printfln("Booting up {}", service.name); log::printfln("Booting up with cmd {} and args {}", service.definition.cmd, service.definition.args); match (exec::fork()) { case let childpid: int => //service.status = beterraba::status::STARTED; service.process = childpid; log::printfln("Starting process {}", service.name); case let err: exec::error => return err; case void => let cmd = exec::cmd("beterrabamon", service.name); match (cmd) { case let cmddef: exec::command => exec::exec(&cmddef); case exec::nocmd => fmt::printfln("Couldn't fire up the executor 'beterrabamon' {}", service.definition.cmd)!; case exec::error => service.status = beterraba::status::CRASHED; fmt::printfln("Couldn't execute cmd {}, error", service.definition.cmd)!; case => fmt::println("Something went terrible wrong, good luck!")!; }; }; }; fn bootstrerror(err: booterror) const str = { match (err) { case let err: exec::error => return exec::strerror(err); case => return "Something awful wen't wrong due to unknown causes"; }; };