conlink 2.2.0 → 2.4.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/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "conlink",
3
- "version": "2.2.0",
3
+ "version": "2.4.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.2",
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,18 @@ 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
- type: array
50
- items: {type: string, pattern: "^[0-9]{1,5}:[0-9]{1,5}/(tcp|udp)$"}
51
+ oneOf: [{ "$ref": "#/$defs/fwd" },
52
+ {type: array, items: { "$ref": "#/$defs/fwd" }}]
53
+ netem:
54
+ oneOf: [{type: string},
55
+ {type: array, items: {type: string}}]
51
56
 
52
57
  bridges:
53
58
  type: array
@@ -66,7 +71,9 @@ properties:
66
71
  bridge: {type: string}
67
72
  remote: { "$ref": "#/$defs/ip" }
68
73
  vni: {type: number}
69
- netem: {type: string}
74
+ netem:
75
+ oneOf: [{type: string},
76
+ {type: array, items: {type: string}}]
70
77
 
71
78
  commands:
72
79
  type: array
package/scripts/copy.sh CHANGED
@@ -46,7 +46,8 @@ dst_dir="${1}"; shift || die 2 "Usage: ${0} [-T|--template] SRC_DIR DST_DIR"
46
46
  done
47
47
 
48
48
  if [ "${*}" ]; then
49
- exec "${@}"
49
+ echo "Running: ${*}"
50
+ exec "${@}"
50
51
  else
51
- true
52
+ true
52
53
  fi
package/scripts/wait.sh CHANGED
@@ -69,5 +69,5 @@ done
69
69
 
70
70
  if [ "${*}" ]; then
71
71
  echo "Running: ${*}"
72
- exec ${*}
72
+ exec "${@}"
73
73
  fi
@@ -77,6 +77,11 @@ General Options:
77
77
  (defn indent-pprint-str [o pre]
78
78
  (indent (trim (with-out-str (pprint o))) pre))
79
79
 
80
+ (defn random-mac
81
+ "Return a random MAC address starting with '0xc2'"
82
+ []
83
+ (addrs/int->mac (reduce #(+ (rand-int 256) (* %1 256))
84
+ 0xc2 [1 2 3 4 5])))
80
85
 
81
86
  (defn load-configs
82
87
  "Load network configs from a list of compose file paths and a list
@@ -104,31 +109,44 @@ General Options:
104
109
  - Add default values to a link:
105
110
  - type: veth
106
111
  - dev: eth0
112
+ - mac: random MAC starting with first octet of 'c2'
107
113
  - mtu: --default-mtu (for non *vlan type)
108
114
  - base: :conlink for veth type, :host for *vlan types, :local otherwise"
109
- [{:as link :keys [type base bridge ip forward]} bridges]
110
- (let [{:keys [default-mtu docker-eth0?]} @ctx
115
+ [{:as link :keys [type base bridge ip route forward netem]} bridges opts]
116
+ (let [{:keys [docker-eth0? docker-eth0-address]} @ctx
117
+ {:keys [default-mtu]} opts
111
118
  type (keyword (or type "veth"))
112
119
  dev (get link :dev "eth0")
120
+ mac (get link :mac (random-mac))
113
121
  base-default (cond (= :veth type) :conlink
114
122
  (VLAN-TYPES type) :host
115
123
  :else :local)
116
124
  base (get link :base base-default)
117
125
  bridge (get bridges bridge)
126
+ route (if (string? route) [route] route)
127
+ forward (if (string? forward) [forward] forward)
128
+ netem (if (string? netem) [netem] netem)
118
129
  link (merge
119
130
  link
120
131
  {:type type
121
132
  :dev dev
122
- :base base}
133
+ :base base
134
+ :mac mac}
123
135
  (when bridge
124
136
  {:bridge bridge})
125
137
  (when (not (VLAN-TYPES type))
126
138
  {:mtu (get link :mtu default-mtu)})
139
+ (when route
140
+ {:route route})
127
141
  (when forward
128
142
  {:forward
129
143
  (map #(let [[port_a port_b proto] (S/split % #"[:/]")]
130
144
  [(js/parseInt port_a) (js/parseInt port_b) proto])
131
- forward)}))]
145
+ forward)})
146
+ (when (and forward docker-eth0-address)
147
+ {:route (conj route (str docker-eth0-address "/32"))})
148
+ (when netem
149
+ {:netem netem}))]
132
150
  (when forward
133
151
  (let [link-id (str (or (:service link) (:container link)) ":" dev)
134
152
  pre (str "link '" link-id "' has forward setting")]
@@ -148,8 +166,9 @@ General Options:
148
166
  is loaded otherwise fall back to :linux. Exit with an error if mode is :ovs
149
167
  or :patch and the 'openvswitch' or 'act_mirred' kernel modules are not
150
168
  loaded respectively."
151
- [{:as bridge-opts :keys [bridge mode]}]
152
- (let [{:keys [warn default-bridge-mode kmod-ovs? kmod-mirred?]} @ctx
169
+ [{:as bridge-opts :keys [bridge mode]} opts]
170
+ (let [{:keys [warn kmod-ovs? kmod-mirred?]} @ctx
171
+ {:keys [default-bridge-mode]} opts
153
172
  mode (keyword (or mode default-bridge-mode))
154
173
  _ (when (and (= :ovs mode) (not kmod-ovs?))
155
174
  (fatal 1 (str "bridge " bridge " mode is 'ovs', "
@@ -157,11 +176,11 @@ General Options:
157
176
  _ (when (and (= :patch mode) (not kmod-mirred?))
158
177
  (warn (str "bridge " bridge " mode is 'patch', "
159
178
  "but no 'act_mirred' kernel module loaded, "
160
- " assuming it will load when needed.")))
179
+ "assuming it will load when needed.")))
161
180
  _ (when (and (= :auto mode) (not kmod-ovs?))
162
181
  (warn (str "bridge " bridge " mode is 'auto', "
163
- " but no 'openvswitch' kernel module loaded, "
164
- " so falling back to 'linux'")))
182
+ "but no 'openvswitch' kernel module loaded, "
183
+ "so falling back to 'linux'")))
165
184
  mode (if (= :auto mode)
166
185
  (if kmod-ovs? :ovs :linux)
167
186
  mode)]
@@ -172,8 +191,9 @@ General Options:
172
191
  add :bridges, :containers, and :services maps with restructured bridge, link,
173
192
  and command configuration to provide a more efficient structure for looking
174
193
  up configuration later."
175
- [{:as cfg :keys [links commands bridges]}]
176
- (let [bridge-map (reduce (fn [acc b] (assoc acc (:bridge b) b))
194
+ [{:as cfg :keys [links bridges tunnels commands]} opts]
195
+ (let [bridge-map (reduce (fn [bs b]
196
+ (assoc bs (:bridge b) b))
177
197
  {} bridges)
178
198
  ;; Add bridges specified in links only
179
199
  all-bridges (reduce (fn [bs b]
@@ -181,21 +201,33 @@ General Options:
181
201
  bridge-map
182
202
  (keep :bridge links))
183
203
  ;; Enrich each bridge
184
- bridges (reduce (fn [bs [k v]] (assoc bs k (enrich-bridge v)))
204
+ bridges (reduce (fn [bs [k v]]
205
+ (assoc bs k (enrich-bridge v opts)))
185
206
  {} all-bridges)
186
- links (mapv #(enrich-link % bridges) links)
187
- cfg (merge cfg {:links links
188
- :bridges bridges
189
- :containers {}
190
- :services {}})
207
+ ;; Restructure links into map to merge and enrich.
208
+ ;; Merge key is server/container + dev
209
+ link-map (reduce (fn [ls link]
210
+ (let [elink (enrich-link link bridges opts)
211
+ lid (str (or (:service link)
212
+ (:container link))
213
+ ":" (:dev elink))
214
+ mlink (deep-merge (get ls lid) elink)]
215
+ (assoc ls lid mlink)))
216
+ {} links)
217
+
218
+ cfg {:bridges bridges
219
+ :tunnels tunnels
220
+ :containers {}
221
+ :services {}}
191
222
  rfn (fn [kind cfg {:as x :keys [container service]}]
192
223
  (cond-> cfg
193
224
  container (update-in [:containers container kind] conjv x)
194
225
  service (update-in [:services service kind] conjv x)))
195
- cfg (reduce (partial rfn :links) cfg links)
226
+ cfg (reduce (partial rfn :links) cfg (vals link-map))
196
227
  cfg (reduce (partial rfn :commands) cfg commands)]
197
228
  cfg))
198
229
 
230
+
199
231
  (defn ajv-error-to-str [error]
200
232
  (let [path (:instancePath error)
201
233
  params (dissoc (:params error) :type :pattern :missingProperty)]
@@ -204,8 +236,7 @@ General Options:
204
236
  (if (not (empty? params)) (str " " params) ""))))
205
237
 
206
238
  (defn check-schema [data schema verbose]
207
- (let [{:keys [info warn]} @ctx
208
- ajv (Ajv. #js {:allErrors true})
239
+ (let [ajv (Ajv. #js {:allErrors true})
209
240
  validator (.compile ajv (->js schema))
210
241
  valid (validator (->js data))]
211
242
  (if valid
@@ -272,7 +303,6 @@ General Options:
272
303
  container properties from an event and the current pid of the
273
304
  network container. Updates iterable properties of the link
274
305
  (via link-add-offset) and adds the following keys:
275
- - :container - the container properties (passed in)
276
306
  - :outer-pid - PID of the network namespace (passed in)
277
307
  - :pid - PID of this container
278
308
  - :dev-id - container name + container interface name
@@ -288,8 +318,7 @@ General Options:
288
318
  link (if (and outer-pid (not (:outer-dev link)))
289
319
  (assoc link :outer-dev (link-outer-dev link id index))
290
320
  link)
291
- link (merge link {:container container
292
- :dev-id dev-id
321
+ link (merge link {:dev-id dev-id
293
322
  :pid pid
294
323
  :outer-pid outer-pid})]
295
324
  link))
@@ -350,6 +379,19 @@ General Options:
350
379
  res (run cmd {:quiet true})]
351
380
  (= 0 (:code res))))
352
381
 
382
+ (defn intf-ipv4-addresses
383
+ "Return a sequence of IPv4 addresses for the interface."
384
+ [intf]
385
+ (P/let [cmd (str "ip -json addr show dev " intf)
386
+ res (run cmd {:quiet true})
387
+ addrs (when (= 0 (:code res))
388
+ (js->clj (js/JSON.parse (:stdout res))
389
+ :keywordize-keys true))]
390
+ (->> addrs
391
+ (mapcat :addr_info)
392
+ (filter #(= "inet" (:family %)))
393
+ (map :local))))
394
+
353
395
  (defn rename-docker-eth0
354
396
  "Rename docker's provided eth0 to DOCKER-INTF to prevent 'RTNETLINK
355
397
  answers: File exists' errors during creation of links that use
@@ -411,7 +453,8 @@ General Options:
411
453
  (if (not cmd)
412
454
  (info (str "Ignoring bridge/switch " bridge " for mode " mode))
413
455
  (P/let [_ (info "Creating bridge/switch" bridge)
414
- res (run* [cmd (str "ip link set " bridge " up")])]
456
+ res (run* [cmd (str "ip link set " bridge " up")]
457
+ {:id "bridge-create"})]
415
458
  (if (not= 0 (:code res))
416
459
  (error (str "Unable to create bridge/switch " bridge))
417
460
  (swap! ctx assoc-in [:network-state :bridges bridge :status] :created))
@@ -510,9 +553,10 @@ General Options:
510
553
  (when outer-pid (str " --pid1 " outer-pid))
511
554
  (when outer-dev (str " --intf1 " outer-dev))
512
555
  (S/join ""
513
- (for [o LINK-ADD-OPTS]
514
- (when-let [v (get link o)]
515
- (str " --" (name o) " '" v "'")))))
556
+ (for [o LINK-ADD-OPTS
557
+ :let [v (get link o [])]
558
+ vo (if (sequential? v) v [v])]
559
+ (str " --" (name o) " '" vo "'"))))
516
560
  res (run cmd {:id dev-id})]
517
561
  (when (not= 0 (:code res))
518
562
  (error (str "Unable to add " (name type) " " dev-id)))
@@ -540,7 +584,7 @@ General Options:
540
584
  forwards defined by :forward property of 'link'."
541
585
  [link action]
542
586
  (P/let [{:keys [error]} @ctx
543
- {:keys [outer-dev dev-id bridge ip forward]} link]
587
+ {:keys [dev-id bridge ip forward]} link]
544
588
  (P/all (for [fwd forward]
545
589
  (P/let [[port_a port_b proto] fwd
546
590
  ip (S/replace ip #"/.*" "")
@@ -562,8 +606,9 @@ General Options:
562
606
  running in a container)"
563
607
  []
564
608
  (P/let [[cgroup mountinfo]
565
- , (P/all [(read-file "/proc/self/cgroup" "utf8")
566
- (read-file "/proc/self/mountinfo" "utf8")])
609
+ , (P/catch (P/all [(read-file "/proc/self/cgroup" "utf8")
610
+ (read-file "/proc/self/mountinfo" "utf8")])
611
+ #(vector "" ""))
567
612
  ;; docker
568
613
  d-cgroups (map second (re-seq #"/docker/([^/\n]*)" cgroup))
569
614
  ;; podman (root)
@@ -604,6 +649,18 @@ General Options:
604
649
  (S/replace #"\." "-")))
605
650
  v])))
606
651
 
652
+ (defn query-container-data
653
+ [container-obj]
654
+ (P/let
655
+ [container (inspect-container container-obj)
656
+ clabels (get-compose-labels container)
657
+ svc-num (:container-number clabels)]
658
+ {:name (->> container :Name (re-seq #"(.*/)?(.*)") first last)
659
+ :index (if svc-num (js/parseInt svc-num) 1)
660
+ :service (:service clabels)
661
+ :pid (-> container :State :Pid)
662
+ :labels clabels}))
663
+
607
664
  ;;;
608
665
 
609
666
  (defn docker-client
@@ -659,7 +716,7 @@ General Options:
659
716
  (condp = action
660
717
  "start"
661
718
  (if link-status
662
- (error (str "Link " dev-id " already exists"))
719
+ (error (str "Link " dev-id " already in state: " link-status))
663
720
  (P/do
664
721
  (swap! ctx assoc-in status-path :creating)
665
722
  (link-add link)
@@ -730,29 +787,26 @@ General Options:
730
787
  if all containers/services are connected."
731
788
  [client {:keys [status id]}]
732
789
  (P/let
733
- [{:keys [log info network-config compose-opts self-pid]} @ctx
790
+ [{:keys [log info network-config network-state compose-opts self-pid]} @ctx
734
791
  container-obj (get-container client id)
735
- container (inspect-container container-obj)
736
- cname (->> container :Name (re-seq #"(.*/)?(.*)") first last)
737
- pid (-> container :State :Pid)
738
-
739
- clabels (get-compose-labels container)
740
- svc-name (:service clabels)
741
- svc-num (:container-number clabels)
742
- cindex (if svc-num (js/parseInt svc-num) 1)
743
- container-info {:id id
744
- :name cname
745
- :index cindex
746
- :service svc-name
747
- :pid pid
748
- :labels clabels}
792
+ container-data (if (= "die" status)
793
+ (P/let [ci (get-in network-state [:containers id])]
794
+ (swap! ctx update-in [:network-state :containers]
795
+ dissoc id)
796
+ ci)
797
+ (P/let [ci (query-container-data container-obj)]
798
+ (swap! ctx update-in [:network-state :containers]
799
+ assoc id ci)
800
+ ci))
801
+ {cname :name clabels :labels} container-data
749
802
 
750
803
  svc-match? (and (let [p (:project compose-opts)]
751
804
  (or (not p) (= p (:project clabels))))
752
805
  (let [d (:project-working_dir compose-opts)]
753
806
  (or (not d) (= d (:project-working_dir clabels)))))
754
807
  containers (get-in network-config [:containers cname])
755
- services (when svc-match? (get-in network-config [:services svc-name]))
808
+ services (when svc-match?
809
+ (get-in network-config [:services (:service clabels)]))
756
810
  links (concat (:links containers) (:links services))
757
811
  commands (concat (:commands containers) (:commands services))]
758
812
  (if (and (not (seq links)) (not (seq commands)))
@@ -761,7 +815,7 @@ General Options:
761
815
  (info "Event:" status cname id)
762
816
  (P/all (for [link links
763
817
  :let [link (link-instance-enrich
764
- link container-info self-pid)]]
818
+ link container-data self-pid)]]
765
819
  (modify-link link status)))
766
820
  (when (= "start" status)
767
821
  (P/all (for [{:keys [command]} commands]
@@ -838,15 +892,15 @@ General Options:
838
892
  kmod-ovs? (kmod-loaded? "openvswitch")
839
893
  kmod-mirred? (kmod-loaded? "act_mirred")
840
894
  docker-eth0? (and self-cid (intf-exists? "eth0"))
841
- _ (swap! ctx merge {:default-bridge-mode (:default-bridge-mode opts)
842
- :default-mtu (:default-mtu opts)
843
- :kmod-ovs? kmod-ovs?
895
+ docker-eth0-addresses (when docker-eth0? (intf-ipv4-addresses "eth0"))
896
+ _ (swap! ctx merge {:kmod-ovs? kmod-ovs?
844
897
  :kmod-mirred? kmod-mirred?
845
- :docker-eth0? docker-eth0?})
898
+ :docker-eth0? docker-eth0?
899
+ :docker-eth0-address (first docker-eth0-addresses)})
846
900
  network-config (P/-> (load-configs compose-file network-file)
847
901
  (interpolate-walk env)
848
902
  (check-schema schema verbose)
849
- (enrich-network-config))
903
+ (enrich-network-config opts))
850
904
  _ (when show-config
851
905
  (println (js/JSON.stringify (->js network-config)))
852
906
  (js/process.exit 0))
@@ -44,7 +44,7 @@
44
44
  (js/process.exit code))
45
45
 
46
46
  (defn deep-merge [a b]
47
- (merge-with #(cond (map? %1) (recur %1 %2)
47
+ (merge-with #(cond (map? %1) (deep-merge %1 %2)
48
48
  (vector? %1) (vec (concat %1 %2))
49
49
  (sequential? %1) (concat %1 %2)
50
50
  :else %2)
@@ -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
@@ -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
+
@@ -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
@@ -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
@@ -0,0 +1,34 @@
1
+ name: "test7: MAC, MTU, and NetEm settings"
2
+
3
+ env:
4
+ DC: "${{ process.env.DOCKER_COMPOSE || 'docker compose' }}"
5
+ COMPOSE_FILE: examples/test7-compose.yaml
6
+
7
+ tests:
8
+ test7:
9
+ name: "MAC, MTU, and NetEm settings"
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
21
+ run: ip addr | grep "10\.0\.1\.1"
22
+ repeat: { retries: 10, interval: '2s' }
23
+
24
+ # Ensure MAC and MTU are set correctly
25
+ - {exec: node, index: 1, run: ip link show eth0 | grep "ether 00:0a:0b:0c:0d:01"}
26
+ - {exec: node, index: 2, run: ip link show eth0 | grep "ether 00:0a:0b:0c:0d:02"}
27
+ - {exec: node, index: 1, run: ip link show eth0 | grep "mtu 4111"}
28
+ - {exec: node, index: 2, run: ip link show eth0 | grep "mtu 4111"}
29
+ # Check for round-trip ping delay of 80ms
30
+ - {exec: node, index: 1, run: 'ping -c5 10.0.1.2 | tail -n1 | grep "min/avg/max = 8[012345]\."'}
31
+ - {exec: node, index: 2, run: 'ping -c5 10.0.1.1 | tail -n1 | grep "min/avg/max = 8[012345]\."'}
32
+
33
+ - exec: :host
34
+ run: ${DC} down --remove-orphans --volumes -t1