beterraba

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