conlink 2.0.1 → 2.0.3

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.
Files changed (77) hide show
  1. package/.github/workflows/push.yml +17 -0
  2. package/Dockerfile +1 -1
  3. package/README.md +51 -16
  4. package/examples/test4-multiple/modes/all/deps +1 -0
  5. package/examples/test4-multiple/{base-compose.yaml → modes/base/compose.yaml} +3 -3
  6. package/examples/test4-multiple/{node1-compose.yaml → modes/node1/compose.yaml} +0 -3
  7. package/examples/test4-multiple/{nodes2-compose.yaml → modes/nodes2/compose.yaml} +0 -5
  8. package/examples/test4-multiple/modes/web/compose.yaml +5 -0
  9. package/examples/test4-multiple/modes/web/deps +1 -0
  10. package/mdc +108 -0
  11. package/package.json +2 -1
  12. package/scripts/copy.sh +52 -0
  13. package/scripts/wait.sh +73 -0
  14. package/src/conlink/core.cljs +35 -16
  15. package/.env +0 -3
  16. package/TODO +0 -34
  17. package/examples/data.dot +0 -457
  18. package/examples/net2dot-data.dot +0 -123
  19. package/examples/net2dot.dot +0 -457
  20. package/examples/test1-data.dot +0 -82
  21. package/examples/test1.dot +0 -286
  22. package/examples/test4-multiple/all-compose.yaml +0 -5
  23. package/examples/test4-multiple/web-network.yaml +0 -2
  24. package/host-build.yaml +0 -1
  25. package/inspect.json +0 -210
  26. package/modes0/a/deps +0 -1
  27. package/modes0/b/deps +0 -1
  28. package/modes0/c/deps +0 -1
  29. package/modes0/e/deps +0 -1
  30. package/modes1/a/deps +0 -1
  31. package/modes1/b/deps +0 -1
  32. package/modes1/c/deps +0 -1
  33. package/modes1/d/deps +0 -1
  34. package/modes2/a/deps +0 -1
  35. package/modes2/b/deps +0 -1
  36. package/modes2/c/deps +0 -1
  37. package/modes2/d/de +0 -1
  38. package/modes2/d/deps +0 -1
  39. package/modes3/accel/deps +0 -1
  40. package/modes4/a/deps +0 -1
  41. package/modes4/b/deps +0 -1
  42. package/net2dot.mjs +0 -21
  43. package/notes.txt +0 -82
  44. package/old/Dockerfile.bak +0 -26
  45. package/old/add-link.sh +0 -82
  46. package/old/conlink +0 -12
  47. package/old/conlink.cljs +0 -131
  48. package/old/dot_gitignore +0 -1
  49. package/old/examples/test2-compose.yaml +0 -32
  50. package/old/examples/test2-network.yaml +0 -42
  51. package/old/graphviz.cljs +0 -14
  52. package/old/move-link.sh +0 -108
  53. package/old/net2dot.cljs +0 -114
  54. package/old/net2dot.py +0 -122
  55. package/old/notes-old.txt +0 -97
  56. package/old/package.json +0 -16
  57. package/old/schema.yaml +0 -138
  58. package/old/schema.yaml.bak +0 -76
  59. package/old/set-cover-old.cljs +0 -205
  60. package/old/set-cover-old2.cljs +0 -150
  61. package/old/test2b-compose.yaml +0 -18
  62. package/old/veth-link.sh +0 -96
  63. package/read-stream.cljs +0 -12
  64. package/resolve-deps.cljs +0 -183
  65. package/schema-ish.yaml +0 -29
  66. package/tests/invalid-schema-1.yaml +0 -6
  67. package/tests/invalid-schema-2.yaml +0 -6
  68. package/tests/invalid-schema-3.yaml +0 -17
  69. package/tests/invalid-schema-4.yaml +0 -14
  70. package/tests/invalid-schema-5.yaml +0 -12
  71. package/tests/invalid-schema-6.yaml +0 -12
  72. package/tmp/conlink/.env +0 -1
  73. package/topo1.cljs +0 -35
  74. package/topo2.cljs +0 -36
  75. package/topo3.cljs +0 -44
  76. /package/{modes3/ab → examples/test4-multiple/modes/node1}/deps +0 -0
  77. /package/{modes3/mach3 → examples/test4-multiple/modes/nodes2}/deps +0 -0
@@ -0,0 +1,17 @@
1
+ name: Push (compose tests)
2
+
3
+ on:
4
+ push: {}
5
+ pull_request:
6
+ branches: [ master ]
7
+ workflow_dispatch: {}
8
+
9
+ jobs:
10
+ compose-tests:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v3
15
+
16
+ - name: stub step
17
+ run: "echo stub stub"
package/Dockerfile CHANGED
@@ -24,7 +24,7 @@ FROM node:16-slim as run
24
24
  RUN apt-get -y update
25
25
  # Runtime deps and utilities
26
26
  RUN apt-get -y install libpcap-dev tcpdump iproute2 iputils-ping curl \
27
- iptables \
27
+ iptables bridge-utils \
28
28
  openvswitch-switch openvswitch-testcontroller
29
29
 
30
30
  COPY --from=build /app/ /app/
package/README.md CHANGED
@@ -1,14 +1,24 @@
1
1
  # conlink: Declarative Low-Level Networking for Containers
2
2
 
3
+
3
4
  Create (layer 2 and layer 3) networking between containers using
4
5
  a declarative configuration.
5
6
 
6
7
  ## Prerequisites
7
8
 
9
+ General:
10
+ * docker
8
11
  * docker-compose version 1.25.4 or later.
9
- * `openvswitch` kernel module loaded on the host
10
- * `geneve` (and/or `vxlan`) kernel module loaded on the host (only
11
- needed for `test5-geneve-compose` example)
12
+
13
+ Other:
14
+ * For Open vSwtich (OVS) bridging, the `openvswitch` kernel module
15
+ must loaded on the host system (where docker engine is running).
16
+ * For podman usage (e.g. second part of `test3`), podman is required.
17
+ * For remote connections/links (e.g. `test5`), the `geneve` (and/or
18
+ `vxlan`) kernel module must be loaded on the host system (where
19
+ docker engine is running)
20
+ * For CloudFormation deployment (e.g. `test6`), the AWS CLI is
21
+ required.
12
22
 
13
23
  ## Usage Notes
14
24
 
@@ -34,6 +44,18 @@ will also be required for the conlink container. In particular, if the
34
44
  container uses systemd, then it will likely use `SYS_NICE` and
35
45
  `NET_BROADCAST` and conlink will likewise need those capabilities.
36
46
 
47
+ ### Bridging: Open vSwtich/OVS or Linux bridge
48
+
49
+ Conlink creates bridges/switches and connects veth container links to
50
+ those bridges (specified by `bridge:` in the link specification).
51
+ By default, conlink will attempt to create Open vSwitch/OVS bridges
52
+ for these connections, however, if the kernel does not provide support
53
+ (`openvswitch` kernel module loaded), then conlink will fallback to
54
+ using standard Linux bridges. The fallback behavior can be changed by
55
+ setting the `--bridge-mode` option to either "ovs" or "linux". If the
56
+ bridge mode is set to "ovs" then conlink will fail to start if the
57
+ `openvswitch` kernel module is not detected.
58
+
37
59
  ## Network Configuration Syntax
38
60
 
39
61
  Network configuration can either be loaded directly from configuration
@@ -71,8 +93,8 @@ The following table describes the link properties:
71
93
  | route | * | string | | ip route add args |
72
94
  | nat | * | IP | | DNAT/SNAT to IP |
73
95
  | netem | * | string | | tc qdisc NetEm options |
74
- | mode | 5 | IP | | virt intf mode |
75
- | vlanid | vlan | IP | | VLAN ID |
96
+ | mode | 5 | string | | virt intf mode |
97
+ | vlanid | vlan | number | | VLAN ID |
76
98
 
77
99
  - 1 - veth, dummy, vlan, ipvlan, macvlan, ipvtap, macvtap
78
100
  - 2 - defaults to outer compose service
@@ -186,11 +208,11 @@ From the second node ping an address in the internet service:
186
208
  docker-compose -f examples/test2-compose.yaml exec --index 2 node ping 8.8.8.8
187
209
  ```
188
210
 
189
- Scale the nodes from 2 to 5 and then ping from first node from the fifth:
211
+ Scale the nodes from 2 to 5 and then ping the fifth node from the second:
190
212
 
191
213
  ```
192
214
  docker-compose -f examples/test2-compose.yaml up -d --scale node=5
193
- docker-compose -f examples/test2-compose.yaml exec --index 5 node ping 10.0.1.1
215
+ docker-compose -f examples/test2-compose.yaml exec --index 2 node ping 10.0.1.5
194
216
  ```
195
217
 
196
218
 
@@ -258,11 +280,10 @@ container (`node1`) and switch (`s1`) that is connected to the router
258
280
  defined in the first compose file.
259
281
 
260
282
  ```
261
- echo "COMPOSE_FILE=examples/test4-multiple/base-compose.yaml:examples/test4-multiple/node1-compose.yaml" > .env
262
- docker-compose up --build --force-recreate
283
+ MODES_DIR=./examples/test4-multiple/modes ./mdc node1 up --build --force-recreate
263
284
  ```
264
285
 
265
- Ping the router host from `node`:
286
+ Ping the router host from `node1`:
266
287
 
267
288
  ```
268
289
  docker-compose exec node1 ping 10.0.0.100
@@ -273,8 +294,7 @@ two node2 replicas and a switch (`s2`) that is connected to the
273
294
  router.
274
295
 
275
296
  ```
276
- echo "COMPOSE_FILE=examples/test4-multiple/base-compose.yaml:examples/test4-multiple/node1-compose.yaml:examples/test4-multiple/nodes2-compose.yaml" > .env
277
- docker-compose up --build --force-recreate
297
+ MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2 up --build --force-recreate
278
298
  ```
279
299
 
280
300
  From both `node2` replicas, ping `node1` across the switches and `r0` router:
@@ -284,13 +304,20 @@ docker-compose exec --index 1 node2 ping 10.1.0.1
284
304
  docker-compose exec --index 2 node2 ping 10.1.0.1
285
305
  ```
286
306
 
307
+ From `node1`, ping both `node2` replicas across the switches and `r0` router:
308
+
309
+ ```
310
+ docker-compose exec node1 ping 10.2.0.1
311
+ docker-compose exec node1 ping 10.2.0.2
312
+ ```
313
+
314
+
287
315
  Restart the compose instance and add another compose file that starts
288
316
  conlink using an addition network file `web-network.yaml`. The network
289
317
  file starts up a simple web server on the router.
290
318
 
291
319
  ```
292
- echo "COMPOSE_FILE=examples/test4-multiple/base-compose.yaml:examples/test4-multiple/node1-compose.yaml:examples/test4-multiple/nodes2-compose.yaml:examples/test4-multiple/all-compose.yaml" > .env
293
- docker-compose up --build --force-recreate
320
+ MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2,web up --build --force-recreate
294
321
  ```
295
322
 
296
323
  From the second `node2`, perform a download from the web server running on the
@@ -300,6 +327,14 @@ router host:
300
327
  docker-compose exec --index 2 node2 wget -O- 10.0.0.100
301
328
  ```
302
329
 
330
+ We can simplify the above launch by using the `all` mode, which contains
331
+ depends on `node1`, `nodes2`, and `web`. Each of those modes depends on
332
+ `base`, so there's no need to specify that again (transitive deps).
333
+
334
+ ```
335
+ MODES_DIR=./examples/test4-multiple/modes ./mdc all up --build --force-recreate
336
+ ```
337
+
303
338
  Remove the `.env` file as a final cleanup step:
304
339
 
305
340
  ```
@@ -390,8 +425,8 @@ Show the links in both node containers to see that the MAC addresses
390
425
  are `00:0a:0b:0c:0d:0*` and the MTUs are set to `4111`.
391
426
 
392
427
  ```
393
- docker-compose -f examples/test7-compose.yaml exec --index 1 ip link
394
- docker-compose -f examples/test7-compose.yaml exec --index 2 ip link
428
+ docker-compose -f examples/test7-compose.yaml exec --index 1 node ip link
429
+ docker-compose -f examples/test7-compose.yaml exec --index 2 node ip link
395
430
  ```
396
431
 
397
432
  Ping the second node from the first to show the the NetEm setting is
@@ -0,0 +1 @@
1
+ node1 nodes2 web
@@ -10,7 +10,7 @@ services:
10
10
  - {bridge: s0, dev: e0, ip: "10.0.0.100/24"}
11
11
 
12
12
  network:
13
- build: {context: ../..}
13
+ build: {context: .}
14
14
  image: conlink
15
15
  pid: host
16
16
  network_mode: none
@@ -19,7 +19,7 @@ services:
19
19
  volumes:
20
20
  - /var/run/docker.sock:/var/run/docker.sock
21
21
  - /var/lib/docker:/var/lib/docker
22
- - ../../:/test
22
+ - ./:/test
23
23
  working_dir: /test
24
- command: /app/build/conlink.js --compose-file ${COMPOSE_FILE:-examples/test4-multiple/base-compose.yaml}
24
+ command: /app/build/conlink.js --compose-file ${COMPOSE_FILE:?COMPOSE_FILE must be set}
25
25
 
@@ -5,9 +5,6 @@ x-network:
5
5
  - {service: r0, bridge: s1, dev: e1, ip: "10.1.0.100/24"}
6
6
 
7
7
  services:
8
- network:
9
- command: /app/build/conlink.js --compose-file ${COMPOSE_FILE:-examples/test4-multiple/node1-compose.yaml}
10
-
11
8
  node1:
12
9
  image: alpine
13
10
  network_mode: none
@@ -4,11 +4,7 @@ x-network:
4
4
  links:
5
5
  - {service: r0, bridge: s2, dev: e2, ip: "10.2.0.100/24"}
6
6
 
7
-
8
7
  services:
9
- network:
10
- command: /app/build/conlink.js --compose-file ${COMPOSE_FILE:-examples/test4-multiple/nodes2-compose.yaml}
11
-
12
8
  node2:
13
9
  image: alpine
14
10
  scale: 2
@@ -17,4 +13,3 @@ services:
17
13
  x-network:
18
14
  links:
19
15
  - {bridge: s2, ip: "10.2.0.1/16", route: "default via 10.2.0.100"}
20
-
@@ -0,0 +1,5 @@
1
+ version: "2.4"
2
+
3
+ x-network:
4
+ commands:
5
+ - {service: r0, command: "python3 -m http.server 80"}
@@ -0,0 +1 @@
1
+ base
package/mdc ADDED
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+ shopt -s dotglob # recursive copy of dot files too
5
+
6
+ die() { echo >&2 "${*}"; exit 1; }
7
+ vecho() { [ "${VERBOSE}" ] && echo >&2 "${*}" || true; }
8
+ realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
9
+
10
+ [ "${*}" ] || die "Usage: ${0} MODES [DOCKER-COMPOSE-ARGS]"
11
+
12
+ VERBOSE="${VERBOSE:-}"
13
+ MODES_DIR="${MODES_DIR:-./modes}"
14
+ ENV_FILE="${ENV_FILE:-.env}"
15
+ MDC_FILES_DIR="${MDC_FILES_DIR:-./.files}"
16
+ LS=$(which ls)
17
+ RESOLVE_DEPS="${RESOLVE_DEPS-./node_modules/@lonocloud/resolve-deps/resolve-deps.py}"
18
+ DOCKER_COMPOSE="${DOCKER_COMPOSE:-docker-compose}"
19
+
20
+ MODE_SPEC="${1}"; shift
21
+ if [ "${RESOLVE_DEPS}" ]; then
22
+ MODES="$(${RESOLVE_DEPS} "${MODES_DIR}" ${MODE_SPEC})"
23
+ else
24
+ MODES="${MODE_SPEC//,/ }"
25
+ fi
26
+
27
+ echo >&2 "MODES: ${MODES}"
28
+ vecho "ENV_FILE: ${ENV_FILE}"
29
+
30
+ declare -A FINISHED
31
+ COMPOSE_FILE=./.compose-empty.yaml
32
+ COMPOSE_PROFILES=
33
+ MDC_MODE_DIRS=
34
+ cat /dev/null > ${ENV_FILE}-mdc-tmp
35
+ echo -e "version: '2.4'\nservices: {}" > ./.compose-empty.yaml
36
+
37
+ vecho "Removing ${MDC_FILES_DIR}"
38
+ case "$(basename ${MDC_FILES_DIR})" in
39
+ .|/) die "MDC_FILES_DIR must not be '.' or '/'";;
40
+ esac
41
+ [ -d "${MDC_FILES_DIR}" ] && rm -r${VERBOSE:+v} ${MDC_FILES_DIR}/
42
+ mkdir -p "${MDC_FILES_DIR}"
43
+
44
+ for mode in ${MODES}; do
45
+ # Only process each mode once
46
+ [ "${FINISHED[${mode}]}" ] && continue
47
+ FINISHED["${mode}"]=1
48
+
49
+ # mode dir must exist
50
+ [ -d "${MODES_DIR}/${mode}" ] || \
51
+ die "No mode dir found for ${mode}"
52
+
53
+ MDC_MODE_DIRS="${MDC_MODE_DIRS},${MODES_DIR}/${mode}"
54
+
55
+ # mode can refer to a compose file in multiple ways
56
+ cfiles="${MODES_DIR}/${mode}/compose.yaml ${MODES_DIR}/${mode}/compose.yml ${MODES_DIR}/${mode}/docker-compose.yaml ${MODES_DIR}/${mode}/docker-compose.yml"
57
+ for cfile in ${cfiles}; do
58
+ if [ -e "${cfile}" ]; then
59
+ COMPOSE_FILE="${COMPOSE_FILE}:${cfile}"
60
+ break
61
+ fi
62
+ done
63
+
64
+ # Add MODE_ prefixed compose profile for each mode
65
+ COMPOSE_PROFILES="${COMPOSE_PROFILES},MODE_${mode}"
66
+
67
+ # if there is a mode specific env file then include it
68
+ efiles="${MODES_DIR}/${mode}/env ${MODES_DIR}/${mode}/.env"
69
+ for efile in ${efiles}; do
70
+ if [ -e "${efile}" ]; then
71
+ echo "### mdc begin mode ${mode}" >> ${ENV_FILE}-mdc-tmp
72
+ vecho "cat ${efile} >> ${ENV_FILE}-mdc-tmp"
73
+ cat ${efile} >> ${ENV_FILE}-mdc-tmp
74
+ echo "### mdc end mode ${mode}" >> ${ENV_FILE}-mdc-tmp
75
+ fi
76
+ done
77
+
78
+ # if there are mode specific files then copy them to MDC_FILES_DIR
79
+ if [ -d "${MODES_DIR}/${mode}" ]; then
80
+ for vfd in $(cd ${MODES_DIR}/${mode} && $LS -d */files 2>/dev/null || true); do
81
+ dest=${MDC_FILES_DIR}/${vfd%/files}
82
+ mkdir -p ${dest}
83
+ vecho cp -a ${MODES_DIR}/${mode}/${vfd}/* ${dest}
84
+ cp -a ${MODES_DIR}/${mode}/${vfd}/* ${dest}
85
+ done
86
+ fi
87
+ done
88
+
89
+ COMPOSE_FILE="${COMPOSE_FILE#:}"
90
+ vecho "COMPOSE_FILE: ${COMPOSE_FILE}"
91
+ echo "COMPOSE_FILE=${COMPOSE_FILE}" >> ${ENV_FILE}-mdc-tmp
92
+ echo "COMPOSE_DIR=$(realpath $(dirname ${ENV_FILE}))" >> ${ENV_FILE}-mdc-tmp
93
+
94
+ COMPOSE_PROFILES="${COMPOSE_PROFILES#,}"
95
+ vecho "COMPOSE_PROFILES: ${COMPOSE_PROFILES}"
96
+ echo "COMPOSE_PROFILES=${COMPOSE_PROFILES}" >> ${ENV_FILE}-mdc-tmp
97
+
98
+ MDC_MODE_DIRS="${MDC_MODE_DIRS#,}"
99
+ vecho "MDC_MODE_DIRS: ${MDC_MODE_DIRS}"
100
+ echo "MDC_MODE_DIRS=\"${MDC_MODE_DIRS}\"" >> ${ENV_FILE}-mdc-tmp
101
+
102
+ vecho mv ${ENV_FILE}-mdc-tmp ${ENV_FILE}
103
+ mv ${ENV_FILE}-mdc-tmp ${ENV_FILE}
104
+
105
+ if [ "${*}" ]; then
106
+ vecho "Running: ${DOCKER_COMPOSE} --env-file "${ENV_FILE}" ${@}"
107
+ exec ${DOCKER_COMPOSE} --env-file "${ENV_FILE}" "${@}"
108
+ fi
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "conlink",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
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
9
  "ajv": "^8.12.0",
9
10
  "dockerode": "^3.3.4",
10
11
  "nbb": "^1.2.179",
@@ -0,0 +1,52 @@
1
+ #!/bin/sh
2
+
3
+ # Copyright (c) 2023, Viasat, Inc
4
+ # Licensed under MPL 2.0
5
+
6
+ # Add files from SRC_DIR to DST_DIR with string interpolation.
7
+ # Any '{{FOO}}' tokens are replaced with value of corresponding
8
+ # environment variable FOO (but only if defined).
9
+
10
+ die() { local ret=${1}; shift; echo >&2 "${*}"; exit $ret; }
11
+
12
+ case "${1}" in -T|--template) TEMPLATE=1; shift ;; esac
13
+
14
+ src_dir="${1}"; shift || die 2 "Usage: ${0} [-T|--template] SRC_DIR DST_DIR"
15
+ dst_dir="${1}"; shift || die 2 "Usage: ${0} [-T|--template] SRC_DIR DST_DIR"
16
+ [ "${1}" = "--" ] && shift
17
+
18
+ [ -d "${src_dir}" ] || die 2 "Not a directory: '${src_dir}'"
19
+ [ -d "${dst_dir}" ] || die 2 "Not a directory: '${dst_dir}'"
20
+
21
+ (cd "${src_dir}" && find . -type f) | while read src_file; do
22
+ src="${src_dir}/${src_file}"
23
+ dst="${dst_dir}/${src_file}"
24
+ mkdir -p $(dirname "${dst}") || die 1 "Failed to make target directory"
25
+ echo cp -a "${src}" "${dst}"
26
+ cp -a "${src}" "${dst}" || die 1 "Failed to copy file"
27
+ # TODO: make this configurable
28
+ chown root.root "${dst}" || die 1 "Unable to set ownership"
29
+ chmod +w "${dst}" || die 1 "Unable to make writable"
30
+
31
+ [ -z "${TEMPLATE}" ] && continue
32
+
33
+ tmpfile="$(mktemp)"
34
+ # match all {{FOO}} style variables and replace from environment
35
+ for v in $(cat "${dst}" | grep -o '{{[^ }{]*}}' | sed 's/[}{]//g' | sort -u); do
36
+ if set | grep -qs "^${v}="; then
37
+ val=$(set | grep "^${v}=" | cut -f 2 -d '=' \
38
+ | sed "s/^['\"]\(.*\)['\"]$/\1/" \
39
+ | sed 's/[\/&]/\\&/g')
40
+ echo "Replacing '{{${v}}}' with '${val}' in '${dst}'"
41
+ sed "s/{{${v}}}/${val}/g" "${dst}" > "${tmpfile}"
42
+ cp "${tmpfile}" "${dst}"
43
+ fi
44
+ done
45
+ rm -f "${tmpfile}"
46
+ done
47
+
48
+ if [ "${*}" ]; then
49
+ exec "${@}"
50
+ else
51
+ true
52
+ fi
@@ -0,0 +1,73 @@
1
+ #!/bin/sh
2
+
3
+ # Copyright (c) 2023, Viasat, Inc
4
+ # Licensed under MPL 2.0
5
+
6
+ die() { local ret=${1}; shift; echo >&2 "${*}"; exit $ret; }
7
+
8
+ NC=$(command -v nc 2>/dev/null)
9
+ SOCAT=$(command -v socat 2>/dev/null)
10
+ BASH=$(command -v bash 2>/dev/null)
11
+ WAIT_SLEEP=${WAIT_SLEEP:-1}
12
+
13
+ do_sleep() {
14
+ echo "Failed: '${typ} ${arg}'. Sleep ${WAIT_SLEEP} seconds before retry"
15
+ sleep ${WAIT_SLEEP}
16
+ }
17
+ check_tcp() {
18
+ if [ "${NC}" ]; then ${NC} -z -w 1 ${1} ${2} > /dev/null
19
+ elif [ "${SOCAT}" ]; then ${SOCAT} /dev/null TCP:${1}:${2},connect-timeout=2
20
+ elif [ "${BASH}" ]; then timeout 1 ${BASH} -c "echo > /dev/tcp/${1}/${2}"
21
+ else die 1 "Could not find nc, socat, or bash"
22
+ fi
23
+ }
24
+
25
+ while [ "${*}" ]; do
26
+ typ="${1}"; shift
27
+ arg="${1}"
28
+ [ "${arg}" = "--" ] && die 2 "No arg found for type '${typ}'"
29
+ case "${typ}" in
30
+ --) break; ;;
31
+ -f|--file)
32
+ while [ ! -e "${arg}" ]; do do_sleep; done
33
+ echo "File '${arg}' exists"
34
+ ;;
35
+ -i|--if|--intf)
36
+ while [ ! -e /sys/class/net/${arg}/ifindex ]; do do_sleep; done
37
+ echo "Interface '${arg}' exists"
38
+ ;;
39
+ -I|--ip)
40
+ while ! grep -qs "^${arg}\>" /proc/net/route; do do_sleep; done
41
+ echo "Interface '${arg}' has IP/routing"
42
+ ;;
43
+ -t|--tcp)
44
+ host=${arg%:*}
45
+ port=${arg##*:}
46
+ [ "${host}" -a "${port}" ] || die 2 "Illegal host/port '${arg}'"
47
+ while ! check_tcp ${host} ${port}; do do_sleep; done
48
+ echo "TCP listener is reachable at '${arg}' "
49
+ ;;
50
+ -u|--umask)
51
+ umask ${arg}
52
+ echo "Set umask to ${arg}"
53
+ ;;
54
+ -c|--cmd|--command)
55
+ while ! ${arg}; do do_sleep; done
56
+ echo "Command successful: ${arg}"
57
+ ;;
58
+ -s|--sleep)
59
+ WAIT_SLEEP=${arg}
60
+ echo "Changed WAIT_SLEEP from ${WAIT_SLEEP} to ${arg}"
61
+ ;;
62
+ *)
63
+ echo "Unknown option: ${typ}"
64
+ exit 1
65
+ ;;
66
+ esac
67
+ shift
68
+ done
69
+
70
+ if [ "${*}" ]; then
71
+ echo "Running: ${*}"
72
+ exec ${*}
73
+ fi
@@ -27,9 +27,9 @@ General Options:
27
27
  -v, --verbose Show verbose output (stderr)
28
28
  [env: VERBOSE]
29
29
  --show-config Print loaded network config JSON and exit
30
- --bridge-mode BRIDGE-MODE Bridge mode (ovs or linux) to use for
31
- bridge/switch connections
32
- [default: ovs]
30
+ --bridge-mode BRIDGE-MODE Bridge mode (ovs, linux, or auto)
31
+ to use for bridge/switch connections
32
+ [default: auto] [env: CONLINK_BRIDGE_MODE]
33
33
  --network-file NETWORK-FILE... Network config file
34
34
  --compose-file COMPOSE-FILE... Docker compose file with network config
35
35
  --compose-project NAME Docker compose project name for resolving
@@ -651,17 +651,38 @@ General Options:
651
651
  (fatal 2 "Could not find config-schema" orig-config-schema)))
652
652
 
653
653
  (defn startup-checks
654
- "Check startup state and exit if openvswitch kernel module is not
655
- loaded or if no docker or podman connection could be established."
656
- [bridge-mode docker podman]
654
+ "Check startup state and return map of :bridge-mode, :docker, and
655
+ :podman. If bridge-mode is :auto then return :ovs if the
656
+ 'openvswitch' kernel module is loaded otherwise fall back to :linux.
657
+ Exit with an error if bridge-mode is :ovs and the 'openvswitch'
658
+ kernel module is not loaded or if neither a docker or podman
659
+ connection could be established."
660
+ [{:keys [bridge-mode docker-socket podman-socket]}]
657
661
  (P/let
658
- [kmod-okay? (if (= :ovs bridge-mode)
659
- (kmod-loaded? "openvswitch")
660
- true)]
661
- (when (not kmod-okay?)
662
- (fatal 1 "bridge-mode is 'ovs', but no 'openvswitch' module loaded"))
662
+ [{:keys [info warn]} @ctx
663
+ ovs? (kmod-loaded? "openvswitch")
664
+ bridge-mode (condp = [bridge-mode ovs?]
665
+ [:auto true]
666
+ :ovs
667
+
668
+ [:auto false]
669
+ (do
670
+ (warn (str "bridge-mode is 'auto' but no 'openvswitch' "
671
+ "kernel module loaded, so using 'linux'"))
672
+ :linux)
673
+
674
+ [:ovs false]
675
+ (fatal 1 (str "bridge-mode is 'ovs', but no 'openvswitch' "
676
+ "kernel module loaded"))
677
+
678
+ bridge-mode)
679
+ docker (docker-client docker-socket)
680
+ podman (docker-client podman-socket)]
663
681
  (when (and (not docker) (not podman))
664
- (fatal 1 "Failed to start either docker or podman client/listener"))))
682
+ (fatal 1 "Failed to start either docker or podman client/listener"))
683
+ {:bridge-mode bridge-mode
684
+ :docker docker
685
+ :podman podman}))
665
686
 
666
687
  (defn server
667
688
  "Process:
@@ -691,7 +712,7 @@ General Options:
691
712
  _ (arg-checks opts)
692
713
  _ (info (str "User options:\n" (indent-pprint-str opts " ")))
693
714
 
694
- {:keys [network-file compose-file compose-project bridge-mode]} opts
715
+ {:keys [network-file compose-file compose-project]} opts
695
716
  env (js->clj (js/Object.assign #js {} js/process.env))
696
717
  self-pid js/process.pid
697
718
  schema (load-config (:config-schema opts))
@@ -703,9 +724,7 @@ General Options:
703
724
  (println (js/JSON.stringify (->js network-config)))
704
725
  (js/process.exit 0))
705
726
 
706
- docker (docker-client (:docker-socket opts))
707
- podman (docker-client (:podman-socket opts))
708
- _ (startup-checks bridge-mode docker podman)
727
+ {:keys [bridge-mode docker podman]} (startup-checks opts)
709
728
  self-cid (get-container-id)
710
729
  self-container-obj (when self-cid
711
730
  (get-container (or docker podman) self-cid))
package/.env DELETED
@@ -1,3 +0,0 @@
1
- HOST_INTERFACE=eni0
2
- NODE1_HOST_ADDRESS=192.168.0.32
3
- NODE2_HOST_ADDRESS=192.168.0.33
package/TODO DELETED
@@ -1,34 +0,0 @@
1
- - MVP for ViaBox:
2
- - [x] compose/x-network file loading
3
- - [x] multiple config sources and merging
4
- - [x] link route config
5
- - [x] filtering on project and workdir
6
- - [x] interface and MAC iteration
7
- - [x] variable templating
8
- - [x] *vlan type interfaces
9
-
10
- - Near term:
11
- - [x] dummy interfaces
12
- - [x] arbitrary container commands
13
- - [x] schema validation
14
- - [x] code comments/documentation
15
- - [x] tunnel interfaces
16
- - [x] tc/qdisc settings
17
- - [x] fix/test all examples (6 and 9 remaining)
18
- - [x] add net2dot
19
- - [ ] add outer-netem (and match all link-add params to link keys)
20
-
21
- - Further term:
22
- - [ ] CNI networking support
23
- - conlink runs in container listening for events on a UDS
24
- (intead of docker events)
25
- - an outer conlink command is the CNI client that formats
26
- events to send over the UDS to the inner conlink
27
- - [ ] multiple routes
28
- - [ ] ovs flow config
29
- - [ ] Multiple bridge-modes
30
- - bridge-mode as part of the domain definition so that the
31
- same conlink instances can support multiple bridge modes
32
- simultaneously (with a default for links that don't
33
- specify).
34
-