conlink 2.0.1 → 2.0.2

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 (74) hide show
  1. package/README.md +11 -6
  2. package/examples/test4-multiple/modes/all/deps +1 -0
  3. package/examples/test4-multiple/{base-compose.yaml → modes/base/compose.yaml} +3 -3
  4. package/examples/test4-multiple/{node1-compose.yaml → modes/node1/compose.yaml} +0 -3
  5. package/examples/test4-multiple/{nodes2-compose.yaml → modes/nodes2/compose.yaml} +0 -5
  6. package/examples/test4-multiple/modes/web/compose.yaml +5 -0
  7. package/examples/test4-multiple/modes/web/deps +1 -0
  8. package/mdc +108 -0
  9. package/package.json +2 -1
  10. package/scripts/copy.sh +48 -0
  11. package/scripts/wait.sh +73 -0
  12. package/.env +0 -3
  13. package/TODO +0 -34
  14. package/examples/data.dot +0 -457
  15. package/examples/net2dot-data.dot +0 -123
  16. package/examples/net2dot.dot +0 -457
  17. package/examples/test1-data.dot +0 -82
  18. package/examples/test1.dot +0 -286
  19. package/examples/test4-multiple/all-compose.yaml +0 -5
  20. package/examples/test4-multiple/web-network.yaml +0 -2
  21. package/host-build.yaml +0 -1
  22. package/inspect.json +0 -210
  23. package/modes0/a/deps +0 -1
  24. package/modes0/b/deps +0 -1
  25. package/modes0/c/deps +0 -1
  26. package/modes0/e/deps +0 -1
  27. package/modes1/a/deps +0 -1
  28. package/modes1/b/deps +0 -1
  29. package/modes1/c/deps +0 -1
  30. package/modes1/d/deps +0 -1
  31. package/modes2/a/deps +0 -1
  32. package/modes2/b/deps +0 -1
  33. package/modes2/c/deps +0 -1
  34. package/modes2/d/de +0 -1
  35. package/modes2/d/deps +0 -1
  36. package/modes3/accel/deps +0 -1
  37. package/modes4/a/deps +0 -1
  38. package/modes4/b/deps +0 -1
  39. package/net2dot.mjs +0 -21
  40. package/notes.txt +0 -82
  41. package/old/Dockerfile.bak +0 -26
  42. package/old/add-link.sh +0 -82
  43. package/old/conlink +0 -12
  44. package/old/conlink.cljs +0 -131
  45. package/old/dot_gitignore +0 -1
  46. package/old/examples/test2-compose.yaml +0 -32
  47. package/old/examples/test2-network.yaml +0 -42
  48. package/old/graphviz.cljs +0 -14
  49. package/old/move-link.sh +0 -108
  50. package/old/net2dot.cljs +0 -114
  51. package/old/net2dot.py +0 -122
  52. package/old/notes-old.txt +0 -97
  53. package/old/package.json +0 -16
  54. package/old/schema.yaml +0 -138
  55. package/old/schema.yaml.bak +0 -76
  56. package/old/set-cover-old.cljs +0 -205
  57. package/old/set-cover-old2.cljs +0 -150
  58. package/old/test2b-compose.yaml +0 -18
  59. package/old/veth-link.sh +0 -96
  60. package/read-stream.cljs +0 -12
  61. package/resolve-deps.cljs +0 -183
  62. package/schema-ish.yaml +0 -29
  63. package/tests/invalid-schema-1.yaml +0 -6
  64. package/tests/invalid-schema-2.yaml +0 -6
  65. package/tests/invalid-schema-3.yaml +0 -17
  66. package/tests/invalid-schema-4.yaml +0 -14
  67. package/tests/invalid-schema-5.yaml +0 -12
  68. package/tests/invalid-schema-6.yaml +0 -12
  69. package/tmp/conlink/.env +0 -1
  70. package/topo1.cljs +0 -35
  71. package/topo2.cljs +0 -36
  72. package/topo3.cljs +0 -44
  73. /package/{modes3/ab → examples/test4-multiple/modes/node1}/deps +0 -0
  74. /package/{modes3/mach3 → examples/test4-multiple/modes/nodes2}/deps +0 -0
package/README.md CHANGED
@@ -258,8 +258,7 @@ container (`node1`) and switch (`s1`) that is connected to the router
258
258
  defined in the first compose file.
259
259
 
260
260
  ```
261
- echo "COMPOSE_FILE=examples/test4-multiple/base-compose.yaml:examples/test4-multiple/node1-compose.yaml" > .env
262
- docker-compose up --build --force-recreate
261
+ MODES_DIR=./examples/test4-multiple/modes ./mdc node1 up --build --force-recreate
263
262
  ```
264
263
 
265
264
  Ping the router host from `node`:
@@ -273,8 +272,7 @@ two node2 replicas and a switch (`s2`) that is connected to the
273
272
  router.
274
273
 
275
274
  ```
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
275
+ MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2 up --build --force-recreate
278
276
  ```
279
277
 
280
278
  From both `node2` replicas, ping `node1` across the switches and `r0` router:
@@ -289,8 +287,7 @@ conlink using an addition network file `web-network.yaml`. The network
289
287
  file starts up a simple web server on the router.
290
288
 
291
289
  ```
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
290
+ MODES_DIR=./examples/test4-multiple/modes ./mdc node1,nodes2,web up --build --force-recreate
294
291
  ```
295
292
 
296
293
  From the second `node2`, perform a download from the web server running on the
@@ -300,6 +297,14 @@ router host:
300
297
  docker-compose exec --index 2 node2 wget -O- 10.0.0.100
301
298
  ```
302
299
 
300
+ We can simplify the above launch by using the `all` mode, which contains
301
+ depends on `node1`, `nodes2`, and `web`. Each of those modes depends on
302
+ `base`, so there's no need to specify that again (transitive deps).
303
+
304
+ ```
305
+ MODES_DIR=./examples/test4-multiple/modes ./mdc all up --build --force-recreate
306
+ ```
307
+
303
308
  Remove the `.env` file as a final cleanup step:
304
309
 
305
310
  ```
@@ -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
+ #!/bin/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.2",
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,48 @@
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
+
30
+ [ -z "${TEMPLATE}" ] && continue
31
+
32
+ # match all {{FOO}} style variables and replace from environment
33
+ for v in $(cat "${dst}" | grep -o '{{[^ }{]*}}' | sed 's/[}{]//g' | sort -u); do
34
+ if set | grep -qs "^${v}="; then
35
+ val=$(set | grep "^${v}=" | cut -f 2 -d '=' \
36
+ | sed "s/^['\"]\(.*\)['\"]$/\1/" \
37
+ | sed 's/[\/&]/\\&/g')
38
+ echo "Replacing '{{${v}}}' with '${val}' in '${dst}'"
39
+ sed -i "s/{{${v}}}/${val}/g" "${dst}"
40
+ fi
41
+ done
42
+ done
43
+
44
+ if [ "${*}" ]; then
45
+ exec "${@}"
46
+ else
47
+ true
48
+ 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
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
-