src/agent/server.js
import { t, config, log, fsAsync } from 'azk';
import { publish } from 'azk/utils/postal';
import { async, promiseResolve } from 'azk/utils/promises';
import { VM } from 'azk/agent/vm';
import { Balancer } from 'azk/agent/balancer';
import { Api } from 'azk/agent/api';
import { net } from 'azk/utils';
import { VmStartError } from 'azk/utils/errors';
var Server = {
starting: false,
stopping: false,
server: null,
vm_started: false,
docker_down: false,
// stop handler
stop_handler() {},
// Warning: Only use test in mac
vm_enabled: !config('agent:dev:force_disable_vm'),
// TODO: log start machine steps
start(stop_handler) {
this.stop_handler = stop_handler;
this.starting = true;
return async(this, function* () {
log.info_t("commands.agent.starting");
// Start api
yield Api.start();
// Virtual machine is required?
if (this.vm_enabled && config('agent:requires_vm')) {
yield this.installVM(true);
}
// Load balancer
yield this.installBalancer();
// active docker monitor
if (config('docker:monitor')) {
this._activeDockerMonitor();
}
log.info_t("commands.agent.started");
this.starting = false;
});
},
stop() {
if (this.stopping) { return promiseResolve(); }
this.stopping = true;
return async(this, function* () {
yield Api.stop();
yield this.removeBalancer(this.docker_down);
if (config('agent:requires_vm') && this.vm_started) {
yield this.stopVM();
}
this.stopping = false;
});
},
installBalancer() {
return Balancer.start(this.vm_enabled);
},
removeBalancer(skip_containers) {
return Balancer.stop(skip_containers);
},
installVM(start = false) {
var vm_name = config("agent:vm:name");
return async(this, function* () {
var installed = yield VM.isInstalled(vm_name);
var running = (installed) ? yield VM.isRunnig(vm_name) : false;
var vm_publish = (status) => {
publish("agent.server.installVM.status", {
type: "status", context: "vm", status
});
};
if (!installed) {
var opts = {
name: vm_name,
ip : config("agent:vm:ip"),
boot: config("agent:vm:boot_disk"),
data: config("agent:vm:data_disk"),
};
yield VM.init(opts);
// Set ssh key
vm_publish("sshkey");
var file = config("agent:vm:ssh_key") + ".pub";
var content = yield fsAsync.readFile(file);
VM.setProperty(vm_name, "/VirtualBox/D2D/SSH_KEY", content.toString());
VM.setProperty(vm_name, "/VirtualBox/D2D/swap_factor", config("agent:vm:swap_factor"));
}
if (!running && start) {
var timeout = config("agent:vm:wait_ready");
var result = yield VM.start(vm_name, timeout);
if (!result) {
var screen = yield VM.saveScreenShot(vm_name);
throw new VmStartError(timeout, screen);
}
}
// Mount shared
vm_publish("mounting");
yield VM.mount(vm_name, "Root", config("agent:vm:mount_point"));
vm_publish("mounted");
// Mark installed
this.vm_started = true;
});
},
stopVM() {
var vm_name = config("agent:vm:name");
return async(this, function* () {
var running = yield VM.isRunnig(vm_name);
if (running) {
yield VM.stop(vm_name, !this.vm_started);
}
});
},
_activeDockerMonitor(retry = 3) {
var docker_host = config("docker:host");
log.debug(t("docker.monitor.start", { docker_host, retry }));
var stop = () => {
publish("agent.docker.check.status", {
type: "status", context: "docker", status: "down"
});
this.docker_down = true;
return this.stop_handler();
};
var wait_options = {
timeout: config('agent:wait_max_timeout'),
publish_retry: false,
};
var check_docker_interval = config('agent:check_interval');
var interval_fn = () => {
net
.waitService(docker_host, wait_options)
.then((success) => {
if (!success) {
log.debug(t("docker.monitor.failed", docker_host));
return stop();
}
log.debug(t("docker.monitor.passed", docker_host));
setTimeout(interval_fn, check_docker_interval);
})
.catch(stop);
};
setTimeout(interval_fn, check_docker_interval);
},
};
export { Server };