conlink 2.2.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/push.yml +3 -3
- package/Dockerfile +1 -1
- package/README.md +207 -12
- package/examples/test10-compose.yaml +14 -3
- package/examples/test7-compose.yaml +7 -1
- package/examples/test9-compose.yaml +8 -3
- package/link-add.sh +27 -16
- package/link-forward.sh +2 -1
- package/link-mirred.sh +8 -29
- package/mdc +38 -25
- package/net2dot.cljs +3 -3
- package/package.json +3 -2
- package/schema.yaml +15 -5
- package/scripts/copy.sh +3 -2
- package/scripts/wait.sh +1 -1
- package/src/conlink/core.cljs +117 -55
- package/src/conlink/util.cljs +1 -1
- package/test/test1.yaml +26 -0
- package/test/test10.yaml +46 -0
- package/test/test2.yaml +37 -0
- package/test/test4.yaml +80 -0
- package/test/test7.yaml +34 -0
- package/test/test9.yaml +110 -0
- package/run-tests.sh +0 -219
package/net2dot.cljs
CHANGED
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
(S/replace #"[*]" "_STAR_")
|
|
30
30
|
(S/replace #"[$]" "_DOLLAR_")
|
|
31
31
|
(S/replace #"[{]" "_LCURLY_")
|
|
32
|
-
(S/replace #"[}]" "
|
|
32
|
+
(S/replace #"[}]" "_RCURLY_")
|
|
33
33
|
(S/replace #"[ ]" "_SPACE_")))
|
|
34
34
|
|
|
35
35
|
(defn node-props [label props]
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
#(->> (subgraph conlink (str "cluster_bridge_" %2)
|
|
62
62
|
%2 BRIDGE-PROPS)
|
|
63
63
|
(assoc %1 %2))
|
|
64
|
-
{} (keep :bridge (:links network-config)))
|
|
64
|
+
{} (map :bridge (keep :bridge (:links network-config))))
|
|
65
65
|
services (reduce
|
|
66
66
|
#(->> (subgraph host (str "cluster_service_" (dot-id %2))
|
|
67
67
|
(str "service '" (name %2) "'") SVC-PROPS)
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"-" (name dev)))
|
|
86
86
|
out-id (str "out-" outer-dev)
|
|
87
87
|
out-parent (condp = (keyword base)
|
|
88
|
-
:conlink (get bridges bridge)
|
|
88
|
+
:conlink (get bridges (:bridge bridge))
|
|
89
89
|
:host host)
|
|
90
90
|
{:keys [type vlanid]} link
|
|
91
91
|
[elabel iprops] (if (= "host" base)
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "conlink",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "conlink - Declarative Low-Level Networking for Containers",
|
|
5
5
|
"repository": "https://github.com/LonoCloud/conlink",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@lonocloud/resolve-deps": "^0.0
|
|
8
|
+
"@lonocloud/resolve-deps": "^0.1.0",
|
|
9
9
|
"ajv": "^8.12.0",
|
|
10
10
|
"dockerode": "^3.3.4",
|
|
11
11
|
"nbb": "^1.2.179",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"yaml": "^2.2.1"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
+
"@lonocloud/dctest": "0.1.1",
|
|
17
18
|
"shadow-cljs": "^2.25.7",
|
|
18
19
|
"source-map-support": "^0.5.21"
|
|
19
20
|
}
|
package/schema.yaml
CHANGED
|
@@ -3,6 +3,7 @@ $defs:
|
|
|
3
3
|
ip: {type: string, pattern: "^([0-9]{1,3}[.]){3}[0-9]+$"}
|
|
4
4
|
mac: {type: string, pattern: "^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$"}
|
|
5
5
|
intf: {type: string, pattern: "^.{1,15}$"}
|
|
6
|
+
fwd: {type: string, pattern: "^[0-9]{1,5}:[0-9]{1,5}/(tcp|udp)$"}
|
|
6
7
|
|
|
7
8
|
type: object
|
|
8
9
|
additionalProperties: false
|
|
@@ -40,14 +41,21 @@ properties:
|
|
|
40
41
|
ip: { "$ref": "#/$defs/cidr" }
|
|
41
42
|
mac: { "$ref": "#/$defs/mac" }
|
|
42
43
|
mtu: {type: number}
|
|
43
|
-
route: {type: string}
|
|
44
44
|
nat: { "$ref": "#/$defs/ip" }
|
|
45
|
-
netem: {type: string}
|
|
46
45
|
mode: {type: string}
|
|
47
46
|
vlanid: {type: number}
|
|
47
|
+
route:
|
|
48
|
+
oneOf: [{type: string},
|
|
49
|
+
{type: array, items: {type: string}}]
|
|
48
50
|
forward:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
+
oneOf: [{ "$ref": "#/$defs/fwd" },
|
|
52
|
+
{type: array, items: { "$ref": "#/$defs/fwd" }}]
|
|
53
|
+
netem:
|
|
54
|
+
oneOf: [{type: string},
|
|
55
|
+
{type: array, items: {type: string}}]
|
|
56
|
+
ethtool:
|
|
57
|
+
oneOf: [{type: string},
|
|
58
|
+
{type: array, items: {type: string}}]
|
|
51
59
|
|
|
52
60
|
bridges:
|
|
53
61
|
type: array
|
|
@@ -66,7 +74,9 @@ properties:
|
|
|
66
74
|
bridge: {type: string}
|
|
67
75
|
remote: { "$ref": "#/$defs/ip" }
|
|
68
76
|
vni: {type: number}
|
|
69
|
-
netem:
|
|
77
|
+
netem:
|
|
78
|
+
oneOf: [{type: string},
|
|
79
|
+
{type: array, items: {type: string}}]
|
|
70
80
|
|
|
71
81
|
commands:
|
|
72
82
|
type: array
|
package/scripts/copy.sh
CHANGED
package/scripts/wait.sh
CHANGED
package/src/conlink/core.cljs
CHANGED
|
@@ -32,6 +32,8 @@ General Options:
|
|
|
32
32
|
[default: auto] [env: CONLINK_BRIDGE_MODE]
|
|
33
33
|
--default-mtu MTU Default link MTU (for non *vlan types)
|
|
34
34
|
[default: 65535]
|
|
35
|
+
--keep-veth-offload Do not add '--offload tx off' as the first
|
|
36
|
+
ethtool setting for container veth interfaces
|
|
35
37
|
--network-file NETWORK-FILE... Network config file
|
|
36
38
|
--compose-file COMPOSE-FILE... Docker compose file with network config
|
|
37
39
|
--compose-project NAME Docker compose project name for resolving
|
|
@@ -57,7 +59,8 @@ General Options:
|
|
|
57
59
|
" --system-id=random --no-mlockall --delete-bridges"))
|
|
58
60
|
|
|
59
61
|
(def VLAN-TYPES #{:vlan :macvlan :macvtap :ipvlan :ipvtap})
|
|
60
|
-
(def LINK-ADD-OPTS [:ip :mac :route :mtu :nat :netem :
|
|
62
|
+
(def LINK-ADD-OPTS [:ip :mac :route :mtu :nat :netem :ethtool
|
|
63
|
+
:mode :vlanid :remote :vni])
|
|
61
64
|
(def INTF-MAX-LEN 15)
|
|
62
65
|
(def DOCKER-INTF "DOCKER-ETH0")
|
|
63
66
|
|
|
@@ -77,6 +80,11 @@ General Options:
|
|
|
77
80
|
(defn indent-pprint-str [o pre]
|
|
78
81
|
(indent (trim (with-out-str (pprint o))) pre))
|
|
79
82
|
|
|
83
|
+
(defn random-mac
|
|
84
|
+
"Return a random MAC address starting with '0xc2'"
|
|
85
|
+
[]
|
|
86
|
+
(addrs/int->mac (reduce #(+ (rand-int 256) (* %1 256))
|
|
87
|
+
0xc2 [1 2 3 4 5])))
|
|
80
88
|
|
|
81
89
|
(defn load-configs
|
|
82
90
|
"Load network configs from a list of compose file paths and a list
|
|
@@ -104,31 +112,49 @@ General Options:
|
|
|
104
112
|
- Add default values to a link:
|
|
105
113
|
- type: veth
|
|
106
114
|
- dev: eth0
|
|
115
|
+
- mac: random MAC starting with first octet of 'c2'
|
|
107
116
|
- mtu: --default-mtu (for non *vlan type)
|
|
108
117
|
- base: :conlink for veth type, :host for *vlan types, :local otherwise"
|
|
109
|
-
[{:as link :keys [type
|
|
110
|
-
(let [{:keys [
|
|
118
|
+
[{:as link :keys [type bridge ip route forward netem ethtool]} bridges opts]
|
|
119
|
+
(let [{:keys [docker-eth0? docker-eth0-address]} @ctx
|
|
120
|
+
{:keys [default-mtu keep-veth-offload]} opts
|
|
111
121
|
type (keyword (or type "veth"))
|
|
112
122
|
dev (get link :dev "eth0")
|
|
123
|
+
mac (get link :mac (random-mac))
|
|
113
124
|
base-default (cond (= :veth type) :conlink
|
|
114
125
|
(VLAN-TYPES type) :host
|
|
115
126
|
:else :local)
|
|
116
127
|
base (get link :base base-default)
|
|
117
128
|
bridge (get bridges bridge)
|
|
129
|
+
route (if (string? route) [route] route)
|
|
130
|
+
forward (if (string? forward) [forward] forward)
|
|
131
|
+
netem (if (string? netem) [netem] netem)
|
|
132
|
+
ethtool-pre (if (and (= :veth type) (not keep-veth-offload))
|
|
133
|
+
["--offload tx off"]
|
|
134
|
+
[])
|
|
135
|
+
ethtool (into ethtool-pre (if (string? ethtool) [ethtool] ethtool))
|
|
118
136
|
link (merge
|
|
119
137
|
link
|
|
120
138
|
{:type type
|
|
121
139
|
:dev dev
|
|
122
|
-
:base base
|
|
140
|
+
:base base
|
|
141
|
+
:mac mac
|
|
142
|
+
:ethtool ethtool}
|
|
123
143
|
(when bridge
|
|
124
144
|
{:bridge bridge})
|
|
125
145
|
(when (not (VLAN-TYPES type))
|
|
126
146
|
{:mtu (get link :mtu default-mtu)})
|
|
147
|
+
(when route
|
|
148
|
+
{:route route})
|
|
127
149
|
(when forward
|
|
128
150
|
{:forward
|
|
129
151
|
(map #(let [[port_a port_b proto] (S/split % #"[:/]")]
|
|
130
152
|
[(js/parseInt port_a) (js/parseInt port_b) proto])
|
|
131
|
-
forward)})
|
|
153
|
+
forward)})
|
|
154
|
+
(when (and forward docker-eth0-address)
|
|
155
|
+
{:route (conj route (str docker-eth0-address "/32"))})
|
|
156
|
+
(when netem
|
|
157
|
+
{:netem netem}))]
|
|
132
158
|
(when forward
|
|
133
159
|
(let [link-id (str (or (:service link) (:container link)) ":" dev)
|
|
134
160
|
pre (str "link '" link-id "' has forward setting")]
|
|
@@ -148,8 +174,9 @@ General Options:
|
|
|
148
174
|
is loaded otherwise fall back to :linux. Exit with an error if mode is :ovs
|
|
149
175
|
or :patch and the 'openvswitch' or 'act_mirred' kernel modules are not
|
|
150
176
|
loaded respectively."
|
|
151
|
-
[{:as bridge-opts :keys [bridge mode]}]
|
|
152
|
-
(let [{:keys [warn
|
|
177
|
+
[{:as bridge-opts :keys [bridge mode]} opts]
|
|
178
|
+
(let [{:keys [warn kmod-ovs? kmod-mirred?]} @ctx
|
|
179
|
+
{:keys [default-bridge-mode]} opts
|
|
153
180
|
mode (keyword (or mode default-bridge-mode))
|
|
154
181
|
_ (when (and (= :ovs mode) (not kmod-ovs?))
|
|
155
182
|
(fatal 1 (str "bridge " bridge " mode is 'ovs', "
|
|
@@ -157,11 +184,11 @@ General Options:
|
|
|
157
184
|
_ (when (and (= :patch mode) (not kmod-mirred?))
|
|
158
185
|
(warn (str "bridge " bridge " mode is 'patch', "
|
|
159
186
|
"but no 'act_mirred' kernel module loaded, "
|
|
160
|
-
"
|
|
187
|
+
"assuming it will load when needed.")))
|
|
161
188
|
_ (when (and (= :auto mode) (not kmod-ovs?))
|
|
162
189
|
(warn (str "bridge " bridge " mode is 'auto', "
|
|
163
|
-
"
|
|
164
|
-
"
|
|
190
|
+
"but no 'openvswitch' kernel module loaded, "
|
|
191
|
+
"so falling back to 'linux'")))
|
|
165
192
|
mode (if (= :auto mode)
|
|
166
193
|
(if kmod-ovs? :ovs :linux)
|
|
167
194
|
mode)]
|
|
@@ -172,8 +199,9 @@ General Options:
|
|
|
172
199
|
add :bridges, :containers, and :services maps with restructured bridge, link,
|
|
173
200
|
and command configuration to provide a more efficient structure for looking
|
|
174
201
|
up configuration later."
|
|
175
|
-
[{:as cfg :keys [links commands
|
|
176
|
-
(let [bridge-map (reduce (fn [
|
|
202
|
+
[{:as cfg :keys [links bridges tunnels commands]} opts]
|
|
203
|
+
(let [bridge-map (reduce (fn [bs b]
|
|
204
|
+
(assoc bs (:bridge b) b))
|
|
177
205
|
{} bridges)
|
|
178
206
|
;; Add bridges specified in links only
|
|
179
207
|
all-bridges (reduce (fn [bs b]
|
|
@@ -181,21 +209,33 @@ General Options:
|
|
|
181
209
|
bridge-map
|
|
182
210
|
(keep :bridge links))
|
|
183
211
|
;; Enrich each bridge
|
|
184
|
-
bridges (reduce (fn [bs [k v]]
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
212
|
+
enriched-bridges (reduce (fn [bs [k v]]
|
|
213
|
+
(assoc bs k (enrich-bridge v opts)))
|
|
214
|
+
{} all-bridges)
|
|
215
|
+
;; Restructure links into a map to merge
|
|
216
|
+
link-map (reduce (fn [ls link]
|
|
217
|
+
;; Merge key is server/container + dev
|
|
218
|
+
(let [lid (str (or (:service link)
|
|
219
|
+
(:container link))
|
|
220
|
+
":" (get link :dev "eth0"))]
|
|
221
|
+
(update ls lid deep-merge link)))
|
|
222
|
+
{} links)
|
|
223
|
+
enriched-links (map #(enrich-link % enriched-bridges opts)
|
|
224
|
+
(vals link-map))
|
|
225
|
+
|
|
226
|
+
cfg {:bridges enriched-bridges
|
|
227
|
+
:tunnels tunnels
|
|
228
|
+
:containers {}
|
|
229
|
+
:services {}}
|
|
191
230
|
rfn (fn [kind cfg {:as x :keys [container service]}]
|
|
192
231
|
(cond-> cfg
|
|
193
232
|
container (update-in [:containers container kind] conjv x)
|
|
194
233
|
service (update-in [:services service kind] conjv x)))
|
|
195
|
-
cfg (reduce (partial rfn :links) cfg links)
|
|
234
|
+
cfg (reduce (partial rfn :links) cfg enriched-links)
|
|
196
235
|
cfg (reduce (partial rfn :commands) cfg commands)]
|
|
197
236
|
cfg))
|
|
198
237
|
|
|
238
|
+
|
|
199
239
|
(defn ajv-error-to-str [error]
|
|
200
240
|
(let [path (:instancePath error)
|
|
201
241
|
params (dissoc (:params error) :type :pattern :missingProperty)]
|
|
@@ -204,8 +244,7 @@ General Options:
|
|
|
204
244
|
(if (not (empty? params)) (str " " params) ""))))
|
|
205
245
|
|
|
206
246
|
(defn check-schema [data schema verbose]
|
|
207
|
-
(let [{:
|
|
208
|
-
ajv (Ajv. #js {:allErrors true})
|
|
247
|
+
(let [ajv (Ajv. #js {:allErrors true})
|
|
209
248
|
validator (.compile ajv (->js schema))
|
|
210
249
|
valid (validator (->js data))]
|
|
211
250
|
(if valid
|
|
@@ -272,7 +311,6 @@ General Options:
|
|
|
272
311
|
container properties from an event and the current pid of the
|
|
273
312
|
network container. Updates iterable properties of the link
|
|
274
313
|
(via link-add-offset) and adds the following keys:
|
|
275
|
-
- :container - the container properties (passed in)
|
|
276
314
|
- :outer-pid - PID of the network namespace (passed in)
|
|
277
315
|
- :pid - PID of this container
|
|
278
316
|
- :dev-id - container name + container interface name
|
|
@@ -288,8 +326,7 @@ General Options:
|
|
|
288
326
|
link (if (and outer-pid (not (:outer-dev link)))
|
|
289
327
|
(assoc link :outer-dev (link-outer-dev link id index))
|
|
290
328
|
link)
|
|
291
|
-
link (merge link {:
|
|
292
|
-
:dev-id dev-id
|
|
329
|
+
link (merge link {:dev-id dev-id
|
|
293
330
|
:pid pid
|
|
294
331
|
:outer-pid outer-pid})]
|
|
295
332
|
link))
|
|
@@ -350,6 +387,19 @@ General Options:
|
|
|
350
387
|
res (run cmd {:quiet true})]
|
|
351
388
|
(= 0 (:code res))))
|
|
352
389
|
|
|
390
|
+
(defn intf-ipv4-addresses
|
|
391
|
+
"Return a sequence of IPv4 addresses for the interface."
|
|
392
|
+
[intf]
|
|
393
|
+
(P/let [cmd (str "ip -json addr show dev " intf)
|
|
394
|
+
res (run cmd {:quiet true})
|
|
395
|
+
addrs (when (= 0 (:code res))
|
|
396
|
+
(js->clj (js/JSON.parse (:stdout res))
|
|
397
|
+
:keywordize-keys true))]
|
|
398
|
+
(->> addrs
|
|
399
|
+
(mapcat :addr_info)
|
|
400
|
+
(filter #(= "inet" (:family %)))
|
|
401
|
+
(map :local))))
|
|
402
|
+
|
|
353
403
|
(defn rename-docker-eth0
|
|
354
404
|
"Rename docker's provided eth0 to DOCKER-INTF to prevent 'RTNETLINK
|
|
355
405
|
answers: File exists' errors during creation of links that use
|
|
@@ -411,7 +461,8 @@ General Options:
|
|
|
411
461
|
(if (not cmd)
|
|
412
462
|
(info (str "Ignoring bridge/switch " bridge " for mode " mode))
|
|
413
463
|
(P/let [_ (info "Creating bridge/switch" bridge)
|
|
414
|
-
res (run* [cmd (str "ip link set " bridge " up")]
|
|
464
|
+
res (run* [cmd (str "ip link set " bridge " up")]
|
|
465
|
+
{:id "bridge-create"})]
|
|
415
466
|
(if (not= 0 (:code res))
|
|
416
467
|
(error (str "Unable to create bridge/switch " bridge))
|
|
417
468
|
(swap! ctx assoc-in [:network-state :bridges bridge :status] :created))
|
|
@@ -510,9 +561,10 @@ General Options:
|
|
|
510
561
|
(when outer-pid (str " --pid1 " outer-pid))
|
|
511
562
|
(when outer-dev (str " --intf1 " outer-dev))
|
|
512
563
|
(S/join ""
|
|
513
|
-
(for [o LINK-ADD-OPTS
|
|
514
|
-
|
|
515
|
-
|
|
564
|
+
(for [o LINK-ADD-OPTS
|
|
565
|
+
:let [v (get link o [])]
|
|
566
|
+
vo (if (sequential? v) v [v])]
|
|
567
|
+
(str " --" (name o) " '" vo "'"))))
|
|
516
568
|
res (run cmd {:id dev-id})]
|
|
517
569
|
(when (not= 0 (:code res))
|
|
518
570
|
(error (str "Unable to add " (name type) " " dev-id)))
|
|
@@ -540,7 +592,7 @@ General Options:
|
|
|
540
592
|
forwards defined by :forward property of 'link'."
|
|
541
593
|
[link action]
|
|
542
594
|
(P/let [{:keys [error]} @ctx
|
|
543
|
-
{:keys [
|
|
595
|
+
{:keys [dev-id bridge ip forward]} link]
|
|
544
596
|
(P/all (for [fwd forward]
|
|
545
597
|
(P/let [[port_a port_b proto] fwd
|
|
546
598
|
ip (S/replace ip #"/.*" "")
|
|
@@ -562,8 +614,9 @@ General Options:
|
|
|
562
614
|
running in a container)"
|
|
563
615
|
[]
|
|
564
616
|
(P/let [[cgroup mountinfo]
|
|
565
|
-
, (P/all [(read-file "/proc/self/cgroup" "utf8")
|
|
566
|
-
|
|
617
|
+
, (P/catch (P/all [(read-file "/proc/self/cgroup" "utf8")
|
|
618
|
+
(read-file "/proc/self/mountinfo" "utf8")])
|
|
619
|
+
#(vector "" ""))
|
|
567
620
|
;; docker
|
|
568
621
|
d-cgroups (map second (re-seq #"/docker/([^/\n]*)" cgroup))
|
|
569
622
|
;; podman (root)
|
|
@@ -604,6 +657,18 @@ General Options:
|
|
|
604
657
|
(S/replace #"\." "-")))
|
|
605
658
|
v])))
|
|
606
659
|
|
|
660
|
+
(defn query-container-data
|
|
661
|
+
[container-obj]
|
|
662
|
+
(P/let
|
|
663
|
+
[container (inspect-container container-obj)
|
|
664
|
+
clabels (get-compose-labels container)
|
|
665
|
+
svc-num (:container-number clabels)]
|
|
666
|
+
{:name (->> container :Name (re-seq #"(.*/)?(.*)") first last)
|
|
667
|
+
:index (if svc-num (js/parseInt svc-num) 1)
|
|
668
|
+
:service (:service clabels)
|
|
669
|
+
:pid (-> container :State :Pid)
|
|
670
|
+
:labels clabels}))
|
|
671
|
+
|
|
607
672
|
;;;
|
|
608
673
|
|
|
609
674
|
(defn docker-client
|
|
@@ -659,7 +724,7 @@ General Options:
|
|
|
659
724
|
(condp = action
|
|
660
725
|
"start"
|
|
661
726
|
(if link-status
|
|
662
|
-
(error (str "Link " dev-id " already
|
|
727
|
+
(error (str "Link " dev-id " already in state: " link-status))
|
|
663
728
|
(P/do
|
|
664
729
|
(swap! ctx assoc-in status-path :creating)
|
|
665
730
|
(link-add link)
|
|
@@ -730,29 +795,26 @@ General Options:
|
|
|
730
795
|
if all containers/services are connected."
|
|
731
796
|
[client {:keys [status id]}]
|
|
732
797
|
(P/let
|
|
733
|
-
[{:keys [log info network-config compose-opts self-pid]} @ctx
|
|
798
|
+
[{:keys [log info network-config network-state compose-opts self-pid]} @ctx
|
|
734
799
|
container-obj (get-container client id)
|
|
735
|
-
container (
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
:index cindex
|
|
746
|
-
:service svc-name
|
|
747
|
-
:pid pid
|
|
748
|
-
:labels clabels}
|
|
800
|
+
container-data (if (= "die" status)
|
|
801
|
+
(P/let [ci (get-in network-state [:containers id])]
|
|
802
|
+
(swap! ctx update-in [:network-state :containers]
|
|
803
|
+
dissoc id)
|
|
804
|
+
ci)
|
|
805
|
+
(P/let [ci (query-container-data container-obj)]
|
|
806
|
+
(swap! ctx update-in [:network-state :containers]
|
|
807
|
+
assoc id ci)
|
|
808
|
+
ci))
|
|
809
|
+
{cname :name clabels :labels} container-data
|
|
749
810
|
|
|
750
811
|
svc-match? (and (let [p (:project compose-opts)]
|
|
751
812
|
(or (not p) (= p (:project clabels))))
|
|
752
813
|
(let [d (:project-working_dir compose-opts)]
|
|
753
814
|
(or (not d) (= d (:project-working_dir clabels)))))
|
|
754
815
|
containers (get-in network-config [:containers cname])
|
|
755
|
-
services (when svc-match?
|
|
816
|
+
services (when svc-match?
|
|
817
|
+
(get-in network-config [:services (:service clabels)]))
|
|
756
818
|
links (concat (:links containers) (:links services))
|
|
757
819
|
commands (concat (:commands containers) (:commands services))]
|
|
758
820
|
(if (and (not (seq links)) (not (seq commands)))
|
|
@@ -761,7 +823,7 @@ General Options:
|
|
|
761
823
|
(info "Event:" status cname id)
|
|
762
824
|
(P/all (for [link links
|
|
763
825
|
:let [link (link-instance-enrich
|
|
764
|
-
link container-
|
|
826
|
+
link container-data self-pid)]]
|
|
765
827
|
(modify-link link status)))
|
|
766
828
|
(when (= "start" status)
|
|
767
829
|
(P/all (for [{:keys [command]} commands]
|
|
@@ -838,15 +900,15 @@ General Options:
|
|
|
838
900
|
kmod-ovs? (kmod-loaded? "openvswitch")
|
|
839
901
|
kmod-mirred? (kmod-loaded? "act_mirred")
|
|
840
902
|
docker-eth0? (and self-cid (intf-exists? "eth0"))
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
:kmod-ovs? kmod-ovs?
|
|
903
|
+
docker-eth0-addresses (when docker-eth0? (intf-ipv4-addresses "eth0"))
|
|
904
|
+
_ (swap! ctx merge {:kmod-ovs? kmod-ovs?
|
|
844
905
|
:kmod-mirred? kmod-mirred?
|
|
845
|
-
:docker-eth0? docker-eth0?
|
|
906
|
+
:docker-eth0? docker-eth0?
|
|
907
|
+
:docker-eth0-address (first docker-eth0-addresses)})
|
|
846
908
|
network-config (P/-> (load-configs compose-file network-file)
|
|
847
909
|
(interpolate-walk env)
|
|
848
910
|
(check-schema schema verbose)
|
|
849
|
-
(enrich-network-config))
|
|
911
|
+
(enrich-network-config opts))
|
|
850
912
|
_ (when show-config
|
|
851
913
|
(println (js/JSON.stringify (->js network-config)))
|
|
852
914
|
(js/process.exit 0))
|
package/src/conlink/util.cljs
CHANGED
package/test/test1.yaml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: "test1: compose file with embedded network config"
|
|
2
|
+
|
|
3
|
+
env:
|
|
4
|
+
DC: "${{ process.env.DOCKER_COMPOSE || 'docker compose' }}"
|
|
5
|
+
COMPOSE_FILE: examples/test1-compose.yaml
|
|
6
|
+
|
|
7
|
+
tests:
|
|
8
|
+
test1:
|
|
9
|
+
name: "compose file with embedded network config"
|
|
10
|
+
steps:
|
|
11
|
+
- exec: :host
|
|
12
|
+
run: |
|
|
13
|
+
${DC} down --remove-orphans --volumes -t1
|
|
14
|
+
${DC} up -d --force-recreate
|
|
15
|
+
- exec: :host
|
|
16
|
+
run: |
|
|
17
|
+
echo "waiting for conlink startup"
|
|
18
|
+
${DC} logs network | grep "All links connected"
|
|
19
|
+
repeat: { retries: 30, interval: '1s' }
|
|
20
|
+
|
|
21
|
+
- {exec: h1, run: ping -c1 -w2 10.0.0.100}
|
|
22
|
+
- {exec: h2, run: ping -c1 -w2 192.168.1.100}
|
|
23
|
+
- {exec: h3, run: ping -c1 -w2 172.16.0.100}
|
|
24
|
+
|
|
25
|
+
- exec: :host
|
|
26
|
+
run: ${DC} down --remove-orphans --volumes -t1
|
package/test/test10.yaml
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: "test10: port forwarding"
|
|
2
|
+
|
|
3
|
+
env:
|
|
4
|
+
DC: "${{ process.env.DOCKER_COMPOSE || 'docker compose' }}"
|
|
5
|
+
COMPOSE_FILE: examples/test10-compose.yaml
|
|
6
|
+
|
|
7
|
+
tests:
|
|
8
|
+
test10:
|
|
9
|
+
name: "port forwarding"
|
|
10
|
+
steps:
|
|
11
|
+
- exec: :host
|
|
12
|
+
run: |
|
|
13
|
+
${DC} down --remove-orphans --volumes -t1
|
|
14
|
+
${DC} up -d --force-recreate
|
|
15
|
+
- exec: :host
|
|
16
|
+
run: |
|
|
17
|
+
echo "waiting for conlink startup"
|
|
18
|
+
${DC} logs network | grep "All links connected"
|
|
19
|
+
repeat: { retries: 30, interval: '1s' }
|
|
20
|
+
- exec: node1
|
|
21
|
+
run: ip addr | grep "10\.1\.0\.1"
|
|
22
|
+
repeat: { retries: 10, interval: '2s' }
|
|
23
|
+
|
|
24
|
+
# Check ping between replicas
|
|
25
|
+
- {exec: node2, run: ping -c1 -w2 10.2.0.2}
|
|
26
|
+
# Check ping across router
|
|
27
|
+
- {exec: node1, run: ping -c1 -w2 10.2.0.1}
|
|
28
|
+
- {exec: node1, run: ping -c1 -w2 10.2.0.2}
|
|
29
|
+
- {exec: node2, run: ping -c1 -w2 10.1.0.1}
|
|
30
|
+
# Check ping across router
|
|
31
|
+
- exec: :host
|
|
32
|
+
run: 'curl -sS "http://0.0.0.0:3080" | grep "log"'
|
|
33
|
+
repeat: { retries: 10, interval: '2s' }
|
|
34
|
+
- exec: :host
|
|
35
|
+
run: 'curl -sS "http://0.0.0.0:8080" | grep "log"'
|
|
36
|
+
repeat: { retries: 10, interval: '2s' }
|
|
37
|
+
- exec: :host
|
|
38
|
+
run: 'curl -sS "http://0.0.0.0:80" | grep "share"'
|
|
39
|
+
repeat: { retries: 10, interval: '2s' }
|
|
40
|
+
- exec: :host
|
|
41
|
+
run: 'curl -sS "http://0.0.0.0:81" | grep "share"'
|
|
42
|
+
repeat: { retries: 10, interval: '2s' }
|
|
43
|
+
|
|
44
|
+
- exec: :host
|
|
45
|
+
run: ${DC} down --remove-orphans --volumes -t1
|
|
46
|
+
|
package/test/test2.yaml
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: "test2: separate config and scaling"
|
|
2
|
+
|
|
3
|
+
env:
|
|
4
|
+
DC: "${{ process.env.DOCKER_COMPOSE || 'docker compose' }}"
|
|
5
|
+
COMPOSE_FILE: examples/test2-compose.yaml
|
|
6
|
+
|
|
7
|
+
tests:
|
|
8
|
+
test2:
|
|
9
|
+
name: "separate config and scaling"
|
|
10
|
+
steps:
|
|
11
|
+
- exec: :host
|
|
12
|
+
run: |
|
|
13
|
+
${DC} down --remove-orphans --volumes -t1
|
|
14
|
+
${DC} up -d --force-recreate
|
|
15
|
+
- exec: :host
|
|
16
|
+
run: |
|
|
17
|
+
echo "waiting for conlink startup"
|
|
18
|
+
${DC} logs network | grep "All links connected"
|
|
19
|
+
repeat: { retries: 30, interval: '1s' }
|
|
20
|
+
- {exec: node, index: 1, run: ping -c1 -w2 10.0.1.2}
|
|
21
|
+
- {exec: node, index: 2, run: ping -c1 -w2 10.0.1.1}
|
|
22
|
+
- {exec: node, index: 1, run: ping -c1 -w2 8.8.8.8}
|
|
23
|
+
- {exec: node, index: 2, run: ping -c1 -w2 8.8.8.8}
|
|
24
|
+
|
|
25
|
+
- exec: :host
|
|
26
|
+
run: |
|
|
27
|
+
echo "Scale the nodes from 2 to 5"
|
|
28
|
+
${DC} up -d --scale node=5
|
|
29
|
+
- exec: node
|
|
30
|
+
index: 5
|
|
31
|
+
run: ip addr | grep "10\.0\.1\.5"
|
|
32
|
+
repeat: { retries: 10, interval: '2s' }
|
|
33
|
+
- {exec: node, index: 2, run: ping -c1 -w2 10.0.1.5}
|
|
34
|
+
- {exec: node, index: 5, run: ping -c1 -w2 8.8.8.8}
|
|
35
|
+
|
|
36
|
+
- exec: :host
|
|
37
|
+
run: ${DC} down --remove-orphans --volumes -t1
|
package/test/test4.yaml
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: "test4: multiple compose and mdc"
|
|
2
|
+
|
|
3
|
+
env:
|
|
4
|
+
DC: "${{ process.env.DOCKER_COMPOSE || 'docker compose' }}"
|
|
5
|
+
MODES_DIR: examples/test4-multiple/modes
|
|
6
|
+
|
|
7
|
+
tests:
|
|
8
|
+
node1:
|
|
9
|
+
name: "mdc node1"
|
|
10
|
+
steps:
|
|
11
|
+
- exec: :host
|
|
12
|
+
run: |
|
|
13
|
+
./mdc node1
|
|
14
|
+
${DC} down --remove-orphans --volumes -t1
|
|
15
|
+
${DC} up -d --force-recreate
|
|
16
|
+
- exec: :host
|
|
17
|
+
run: |
|
|
18
|
+
echo "waiting for conlink startup"
|
|
19
|
+
${DC} logs network | grep "All links connected"
|
|
20
|
+
repeat: { retries: 30, interval: '1s' }
|
|
21
|
+
- exec: r0
|
|
22
|
+
run: ip addr | grep "10\.1\.0\.100"
|
|
23
|
+
repeat: { retries: 10, interval: '2s' }
|
|
24
|
+
|
|
25
|
+
# Ping the r0 router host from node1
|
|
26
|
+
- {exec: node1, index: 1, run: ping -c1 -w2 10.0.0.100}
|
|
27
|
+
|
|
28
|
+
- exec: :host
|
|
29
|
+
run: ${DC} down --remove-orphans --volumes -t1
|
|
30
|
+
|
|
31
|
+
node1-nodes2:
|
|
32
|
+
name: "mdc node1,nodes2"
|
|
33
|
+
steps:
|
|
34
|
+
- exec: :host
|
|
35
|
+
run: |
|
|
36
|
+
./mdc node1,nodes2
|
|
37
|
+
${DC} down --remove-orphans --volumes -t1
|
|
38
|
+
${DC} up -d --force-recreate
|
|
39
|
+
- exec: :host
|
|
40
|
+
run: |
|
|
41
|
+
echo "waiting for conlink startup"
|
|
42
|
+
${DC} logs network | grep "All links connected"
|
|
43
|
+
repeat: { retries: 30, interval: '1s' }
|
|
44
|
+
- exec: node2
|
|
45
|
+
index: 2
|
|
46
|
+
run: ip addr | grep "10\.2\.0\.2"
|
|
47
|
+
repeat: { retries: 10, interval: '2s' }
|
|
48
|
+
|
|
49
|
+
# From both node2 replicas, ping node1 across the r0 router
|
|
50
|
+
- {exec: node2, index: 1, run: ping -c1 -w2 10.1.0.1}
|
|
51
|
+
- {exec: node2, index: 2, run: ping -c1 -w2 10.1.0.1}
|
|
52
|
+
# From node1, ping both node2 replicas across the r0 router
|
|
53
|
+
- {exec: node1, index: 1, run: ping -c1 -w2 10.2.0.1}
|
|
54
|
+
- {exec: node1, index: 1, run: ping -c1 -w2 10.2.0.2}
|
|
55
|
+
|
|
56
|
+
- exec: :host
|
|
57
|
+
run: ${DC} down --remove-orphans --volumes -t1
|
|
58
|
+
|
|
59
|
+
all:
|
|
60
|
+
name: "mdc all"
|
|
61
|
+
steps:
|
|
62
|
+
- exec: :host
|
|
63
|
+
run: |
|
|
64
|
+
./mdc all
|
|
65
|
+
${DC} down --remove-orphans --volumes -t1
|
|
66
|
+
${DC} up -d --force-recreate
|
|
67
|
+
- exec: :host
|
|
68
|
+
run: |
|
|
69
|
+
echo "waiting for conlink startup"
|
|
70
|
+
${DC} logs network | grep "All links connected"
|
|
71
|
+
repeat: { retries: 30, interval: '1s' }
|
|
72
|
+
- exec: r0
|
|
73
|
+
run: /scripts/wait.sh -t 10.0.0.100:80
|
|
74
|
+
|
|
75
|
+
# From node2, download from the web server in r0
|
|
76
|
+
- {exec: node2, index: 1, run: wget -O- 10.0.0.100}
|
|
77
|
+
- {exec: node2, index: 2, run: wget -O- 10.0.0.100}
|
|
78
|
+
|
|
79
|
+
- exec: :host
|
|
80
|
+
run: ${DC} down --remove-orphans --volumes -t1
|