-
Notifications
You must be signed in to change notification settings - Fork 0
/
habitat-compose.js
133 lines (98 loc) · 3.89 KB
/
habitat-compose.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
const process = require('process');
const hab = require('hab-client');
const toposort = require('toposort');
const TOML = require('@iarna/toml');
// run main function
run();
async function run() {
// read loaded services
const loadedServiceNames = [];
const loadedServicePackageIdents = {};
for (const loadedService of await hab.getServices()) {
const [serviceName, serviceGroup] = loadedService.service_group.split(/\./);
if (serviceGroup == 'compose') {
loadedServiceNames.push(serviceName);
loadedServicePackageIdents[serviceName] = loadedService.pkg.ident;
}
}
// read configured services
const services = require(process.argv[2]);
// pre-load list of services for sorting
const bindingEdges = [];
for (const serviceId in services) {
const service = services[serviceId];
if (!service.name) {
service.id = serviceId;
}
// fill out package details
if (!service.pkg_ident) {
const {
pkg_origin = process.env.HAB_ORIGIN,
pkg_name = serviceId
} = service;
service.pkg_ident = `${pkg_origin}/${pkg_name}`;
}
if (!service.pkg_name) {
[,service.pkg_name] = service.pkg_ident.split(/\//);
}
if (!service.update_strategy) {
service.update_strategy = 'none';
}
// determine binds
for (const bindName in service.binds) {
const bindServiceId = service.binds[bindName];
const bindService = services[bindServiceId];
if (!bindService) {
console.error(`bound service '${bindServiceId} not found for service '${serviceId}'`);
process.exit(1);
}
bindingEdges.push([bindService, service]);
}
}
// sort services by bind requirements
const sortedServices = toposort.array(Object.values(services), bindingEdges);
const sortedServiceNames = sortedServices.map(service => service.pkg_name);
// unload orphan services
const orphanServiceNames = loadedServiceNames.filter(serviceName => sortedServiceNames.indexOf(serviceName) == -1);
for (const serviceName of orphanServiceNames) {
const pkg_ident = loadedServicePackageIdents[serviceName];
console.error(`Unloading service ${pkg_ident}`);
try {
await hab.svc('unload', pkg_ident);
} catch (err) {
console.error(`Failed to unload service: ${err.message}`);
}
}
// load services via supervisor
const time = Date.now();
for (const { pkg_name, pkg_ident, binds, update_strategy, config } of sortedServices) {
console.error(`Loading service ${pkg_ident}`);
const bindArgs = [];
for (const bindId in binds) {
const bindServiceName = services[binds[bindId]].pkg_name;
console.error(`\tBinding ${bindId}:${bindServiceName}`)
bindArgs.push({ bind: `${bindId}:${bindServiceName}.compose` });
}
try {
await hab.svc('load', pkg_ident, {
group: 'compose',
force: true,
strategy: update_strategy
}, ...bindArgs);
} catch (err) {
console.error(`Failed to load service: ${err.message}`);
}
// apply configuration
if (config) {
console.error(`\tConfiguring service ${pkg_name}.compose`);
try {
const configApply = await hab.config('apply', `${pkg_name}.compose`, time, { $spawn: true, $nullOnError: true });
await configApply.captureOutput(TOML.stringify(config));
} catch (err) {
console.error(`Failed to apply config: ${err.message}`);
}
}
}
// chill out and keep the process open until killed
setInterval(() => {}, 1 << 30);
}