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";
};
};