UNPKG

4.96 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = makePlan;
7
8var _fs = require('fs');
9
10var _fs2 = _interopRequireDefault(_fs);
11
12var _jsYaml = require('js-yaml');
13
14var _jsYaml2 = _interopRequireDefault(_jsYaml);
15
16var _zombieScheduler = require('@zombiec0rn/zombie-scheduler');
17
18var _zombieScheduler2 = _interopRequireDefault(_zombieScheduler);
19
20var _zombieServiceDiff = require('@zombiec0rn/zombie-service-diff');
21
22var _zombieServiceDiff2 = _interopRequireDefault(_zombieServiceDiff);
23
24var _object = require('object.assign');
25
26var _object2 = _interopRequireDefault(_object);
27
28var _lodash = require('lodash.uniq');
29
30var _lodash2 = _interopRequireDefault(_lodash);
31
32var _lodash3 = require('lodash.find');
33
34var _lodash4 = _interopRequireDefault(_lodash3);
35
36var _randomString = require('random-string');
37
38var _randomString2 = _interopRequireDefault(_randomString);
39
40var _utils = require('./utils');
41
42var utils = _interopRequireWildcard(_utils);
43
44function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
45
46function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
47
48function scrambleFingerprint(service) {
49 service.previousFingerprint = service.fingerprint;
50 service.fingerprint = (0, _randomString2.default)();
51}
52
53function getCurrent(nodes) {
54 var services = nodes.reduce(function (services, node) {
55 var nodeServices = utils.extractServices(node);
56 delete node.services;
57 return services.concat(nodeServices);
58 }, []);
59
60 // Detect duplicate fingerprints
61 // Randomize duplicate fingerprint (make sure they are re-evaluated)
62 var duplicates = utils.detectDuplicateFingerprints(services);
63 services.forEach(function (s) {
64 if (duplicates.indexOf(s.fingerprint) >= 0) {
65 scrambleFingerprint(s);
66 }
67 });
68
69 return services;
70}
71
72function makePlan(nodes, _wanted) {
73 /* PREPARING */
74 // Extracting current services from nodes (with fingerprints)
75 // Adding fingerprints to wanted
76 var current = getCurrent(nodes);
77 var wanted = _wanted.map(function (s) {
78 s.fingerprint = _zombieServiceDiff2.default.fingerprint(s);
79 return s;
80 });
81
82 /* TAGS & PLACEMENTS */
83 var tags = (0, _lodash2.default)(nodes.reduce(function (t, n) {
84 return t.concat(n.tags || []);
85 }, []).concat(wanted.reduce(function (t, s) {
86 return t.concat(s.placement || []);
87 }, [])));
88
89 var tagmap = tags.reduce(function (m, t) {
90 m[t] = {};
91 m[t].nodes = nodes.filter(function (n) {
92 return (n.tags || []).indexOf(t) >= 0;
93 });
94 m[t].wanted = wanted.filter(function (s) {
95 return (s.placement || []).indexOf(t) >= 0;
96 });
97 return m;
98 }, {});
99
100 var wantedmap = wanted.reduce(function (m, s) {
101 m[s.id] = s;
102 return m;
103 }, {});
104
105 // TODO: Sometimes we need to place on all tags, or.. ?
106 // Perhaps we need to add another property or expand tag (stick:gateway)
107 // to support both "on one of these" and "on all of these"
108 // Right now I think we only support "on one of these"
109
110 /* TAG & PLACEMENT SCHEDULING */
111 var tagadds = [];
112 tags.forEach(function (t) {
113 var tagplan = _zombieScheduler2.default.spread(tagmap[t].nodes, tagmap[t].wanted);
114 tagplan.add.forEach(function (s) {
115 (0, _object2.default)(s, wantedmap[s.id]);
116 });
117 tagadds = tagadds.concat(tagplan.add);
118 });
119
120 /* FINAL SCHEDULING */
121
122 // We trust tagadds over current (we might have changed tags)
123 // If a tagadd is in current we randomize the fingerprint to ensure re-eval
124 current.forEach(function (s) {
125 var tagadd = (0, _lodash4.default)(tagadds, { id: s.id });
126 if (!tagadd) return;
127 if (tagadd.host.hostname != s.host.hostname) {
128 // Host mismatch
129 scrambleFingerprint(s);
130 } else if (tagadd.fingerprint != s.fingerprint) {
131 // Fingerprint mismatch
132 // Modifications to the same service - still tagged to same host
133 scrambleFingerprint(s);
134 } else {
135 // No mismatch - keep in current / remove from tagadds
136 tagadds = tagadds.filter(function (ta) {
137 return ta.id != s.id;
138 });
139 }
140 });
141
142 var plan = _zombieScheduler2.default.spread(nodes, wanted, current.concat(tagadds));
143 var tagaddids = tagadds.map(function (s) {
144 return s.id;
145 });
146 plan.keep = plan.keep.filter(function (s) {
147 var istagadd = tagaddids.indexOf(s.id) >= 0;
148 if (istagadd) plan.add.push(s); // unshift ? make room for tagged services first ??
149 return !istagadd;
150 });
151
152 /* CLEANUPS */
153 // Add the fingerprint as env variable and remove property
154 plan.add.forEach(function (s) {
155 if (!s.env) s.env = [];
156 s.env.push('ZOMBIE_SWARM_FINGERPRINT=' + s.fingerprint);
157 delete s.fingerprint;
158 });
159 //console.log('PLAN', JSON.stringify(plan, null, 2))
160
161 return plan;
162}
\No newline at end of file