From bf98b457e05af98b870f46da8048dd05760dd64a Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Wed, 7 Feb 2024 23:11:21 +0100 Subject: [PATCH 1/5] add unzip to test container --- images/Dockerfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/images/Dockerfile b/images/Dockerfile index 8bd8678..9ead109 100644 --- a/images/Dockerfile +++ b/images/Dockerfile @@ -11,9 +11,8 @@ RUN install -m 0755 -d /etc/apt/keyrings \ RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ docker-ce-cli \ - docker-compose-plugin - # && groupadd docker \ - # && usermod -aG docker + docker-compose-plugin \ + unzip COPY ./images/container-env /etc/tedge-container-plugin/env From 004fbe75c2d6e23b54fbb3c258f7f6f27df7a702 Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Wed, 7 Feb 2024 23:12:45 +0100 Subject: [PATCH 2/5] feat(container-group): support gzip and zip formats --- src/container-group | 68 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/container-group b/src/container-group index f019e4f..916f195 100755 --- a/src/container-group +++ b/src/container-group @@ -171,13 +171,77 @@ case "$COMMAND" in $COMPOSE_CLI down ||: fi + if [ -n "$LOCAL_MODULE_PATH" ]; then + log "Removing files in $LOCAL_MODULE_PATH" + rm -Rf "${LOCAL_MODULE_PATH:?}/"* + fi + + # Try getting the mime-type from the file + # Use file if available, otherwise try to validate + # the file using various tools to guess the correct type. + # Note: alpine does not have "file" installed out of the box + FILE_TYPE="unknown" + if command -v file >/dev/null 2>&1; then + FILE_TYPE=$(file -db --mime-type "$FILE") + elif unzip -t "$FILE" >/dev/null 2>&1; then + FILE_TYPE="application/zip" + elif tar tf "$FILE" >/dev/null 2>&1; then + FILE_TYPE="application/gzip" + fi + + EXTRA_OPIONS="" + + log "Detected file type: $FILE_TYPE ($FILE)" + case "$FILE_TYPE" in + application/zip) + if ! command -v unzip >/dev/null 2>&1; then + log "unzip is not installed on your system. It is required to handle zip files" + exit 1 + fi + + if ! unzip -l "$FILE" "docker-compose.yaml" >/dev/null 2>&1 && ! unzip -l "$FILE" "docker-compose.yml" >/dev/null 2>&1; then + log "No docker-compose file found in the zip archive." + exit "$EXIT_FAILURE" + fi + + log "Extracting zip file to $LOCAL_MODULE_PATH" + unzip -o "$FILE" -d "$LOCAL_MODULE_PATH" + EXTRA_OPIONS="$EXTRA_OPIONS --build" + ;; + + application/gzip) + if ! command -v tar >/dev/null 2>&1; then + log "tar is not installed on your system. It is required to handle gzip files" + exit 1 + fi + if ! tar tf "$FILE" "docker-compose.yaml" >/dev/null 2>&1 && ! tar tf "$FILE" "docker-compose.yml" >/dev/null 2>&1; then + log "No docker-compose file found in the gzip archive." + exit "$EXIT_FAILURE" + fi + + log "Extracting gzip file to $LOCAL_MODULE_PATH" + tar xzvf "$FILE" -C "$LOCAL_MODULE_PATH" >&2 + EXTRA_OPIONS="$EXTRA_OPIONS --build" + ;; + text/plain) + log "Copying file to $LOCAL_MODULE_PATH" + cp "$FILE" "$LOCAL_MODULE_PATH/docker-compose.yaml" + ;; + *) + # let's assume it is a text file and try anyway, docker compose + # will fail if it is not in the correct format + log "Copying file (of unrecognized file type $FILE_TYPE) to $LOCAL_MODULE_PATH" + cp "$FILE" "$LOCAL_MODULE_PATH/docker-compose.yaml" + ;; + esac + log "Storing module version: $VERSION_FILE" - cp "$FILE" "$LOCAL_MODULE_PATH/docker-compose.yaml" echo "${MODULE_VERSION}" > "$VERSION_FILE" EXIT_CODE="$EXIT_OK" log "Deploying project from path $LOCAL_MODULE_PATH" - if ! $COMPOSE_CLI up --detach --remove-orphans; then + # shellcheck disable=SC2086 + if ! $COMPOSE_CLI up --detach --remove-orphans $EXTRA_OPIONS; then log "Failed to start project" EXIT_CODE="$EXIT_FAILURE" From a7bd9926d066a15ea305615712e96bb5a429313b Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Wed, 7 Feb 2024 23:13:17 +0100 Subject: [PATCH 3/5] add system tests to check control group archives --- tests/data/apps/app1.tar.gz | Bin 0 -> 617 bytes tests/data/apps/app1/Dockerfile | 2 ++ tests/data/apps/app1/docker-compose.yaml | 13 ++++++++++++ tests/data/apps/app1/static/index.html | 25 +++++++++++++++++++++++ tests/data/apps/app2.zip | Bin 0 -> 947 bytes tests/data/apps/app2/Dockerfile | 2 ++ tests/data/apps/app2/docker-compose.yaml | 13 ++++++++++++ tests/data/apps/app2/static/index.html | 25 +++++++++++++++++++++++ tests/data/apps/build.sh | 13 ++++++++++++ tests/operations.robot | 16 +++++++++++++++ 10 files changed, 109 insertions(+) create mode 100644 tests/data/apps/app1.tar.gz create mode 100644 tests/data/apps/app1/Dockerfile create mode 100644 tests/data/apps/app1/docker-compose.yaml create mode 100644 tests/data/apps/app1/static/index.html create mode 100644 tests/data/apps/app2.zip create mode 100644 tests/data/apps/app2/Dockerfile create mode 100644 tests/data/apps/app2/docker-compose.yaml create mode 100644 tests/data/apps/app2/static/index.html create mode 100755 tests/data/apps/build.sh diff --git a/tests/data/apps/app1.tar.gz b/tests/data/apps/app1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..8326b47792ae00a3eeee0c556f2e8cffd88a941d GIT binary patch literal 617 zcmV-v0+#(BiwFSw{=;Pe1MQYkPunmMfcujk4lGpnA#9nia(%96Bs_ zs5Gx-0!OnWPouiy8S2CXU`-Rc7GT|Skq;t3-oKZE3ryf_FFz`?S{i&X2~7F{iRQjm zTfLh*27~zqJ@2Wa9~vwqtL&~eK|d-WAu@RwdXG`2;SFZXJxb4p20{zj?k01zwAP9mW2!bF8f*=TjAP9mWh&SX9B%J(M04M+e Di@r8O literal 0 HcmV?d00001 diff --git a/tests/data/apps/app1/Dockerfile b/tests/data/apps/app1/Dockerfile new file mode 100644 index 0000000..9094145 --- /dev/null +++ b/tests/data/apps/app1/Dockerfile @@ -0,0 +1,2 @@ +FROM nginx +COPY static /usr/share/nginx/html diff --git a/tests/data/apps/app1/docker-compose.yaml b/tests/data/apps/app1/docker-compose.yaml new file mode 100644 index 0000000..307b873 --- /dev/null +++ b/tests/data/apps/app1/docker-compose.yaml @@ -0,0 +1,13 @@ +version: "3" +services: + app1: + build: + dockerfile: Dockerfile + context: . + networks: + - tedge + +networks: + tedge: + name: tedge + external: true diff --git a/tests/data/apps/app1/static/index.html b/tests/data/apps/app1/static/index.html new file mode 100644 index 0000000..38c2011 --- /dev/null +++ b/tests/data/apps/app1/static/index.html @@ -0,0 +1,25 @@ + + + + + My Custom Web Application + + + + +

My Custom Web Application

+

If you see this page, the nginx web server is successfully installed and + working. Further configuration is required.

+ + + \ No newline at end of file diff --git a/tests/data/apps/app2.zip b/tests/data/apps/app2.zip new file mode 100644 index 0000000000000000000000000000000000000000..1c4954c6feb92ad2d2ee2c99ca8ac8e483336055 GIT binary patch literal 947 zcmWIWW@Zs#U|`^2P~YJm@z;HkP(F~i8i<7%WEfKNle1Hcbd&RQ3-XIo^(qr{b3#Kn z8JJi8J)F7Wm(JApS%vo+ zH|*Qw_w>5$LL-}uGZ$|J`gc@syE^aYKQmX+=~9J4~o9=cZ6u@dFq_>3A>=Lt9MEN zoQICrRd(-J=~JFOD_~?mweJgeSg0D%=l_9N5NKaN@|5(MhP^eK-PjV znzglozW#>|c=mn|pYeNJlfZPnRVKU>EEFt!6#60`n_c@9`03yZf&X(;WJPZ?#{XIL zJ;&bq&7*Ibdn>E=F-vY)#cj51%Eazn4I(-L0TK3m8~W@bc-QY}4ZW|ORiTg_VaesT zk^iv%xrw(AUjK6DVnpiQJLW>BVGCAFW@IVf{dCDMJ+&QMlPp%>pUknT>9zEg)51>0 z*C(!gAXLHgZA$i9&d<}bgPd8V_0~Q!u5eV};hFHXW3^;O-k&>*7k^tn{czONLjAD5 zcFl;gvOAG+f6M0{>D#ogE+cV+pp6oXr(D&&hdPcdljqbQvb(zMr~C_rjdo_dRrlSN zvMD@f4(DPmP*y9ieqENbi}jBC^jkYhVlD@X-%Tvbd-TC}lJmxd)cJ4ww|$oTxwsw} z;EYUi%(#-L1Tdl*7=WSAu%r>h!kSoFA&C_&_>m39OgqR1?*ST&oRWa%VTn$3^H9?U cvUxf{_hLyYxQu0G1Nn>@2tgj5%LL*90PVX;761SM literal 0 HcmV?d00001 diff --git a/tests/data/apps/app2/Dockerfile b/tests/data/apps/app2/Dockerfile new file mode 100644 index 0000000..9094145 --- /dev/null +++ b/tests/data/apps/app2/Dockerfile @@ -0,0 +1,2 @@ +FROM nginx +COPY static /usr/share/nginx/html diff --git a/tests/data/apps/app2/docker-compose.yaml b/tests/data/apps/app2/docker-compose.yaml new file mode 100644 index 0000000..2ed5fbe --- /dev/null +++ b/tests/data/apps/app2/docker-compose.yaml @@ -0,0 +1,13 @@ +version: "3" +services: + app2: + build: + dockerfile: Dockerfile + context: . + networks: + - tedge + +networks: + tedge: + name: tedge + external: true diff --git a/tests/data/apps/app2/static/index.html b/tests/data/apps/app2/static/index.html new file mode 100644 index 0000000..38c2011 --- /dev/null +++ b/tests/data/apps/app2/static/index.html @@ -0,0 +1,25 @@ + + + + + My Custom Web Application + + + + +

My Custom Web Application

+

If you see this page, the nginx web server is successfully installed and + working. Further configuration is required.

+ + + \ No newline at end of file diff --git a/tests/data/apps/build.sh b/tests/data/apps/build.sh new file mode 100755 index 0000000..0959986 --- /dev/null +++ b/tests/data/apps/build.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -e +# +# Package some example docker compose as gzip and zip packages +# + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +pushd "$SCRIPT_DIR" >/dev/null ||: + +(cd app1 && tar czvf ../app1.tar.gz docker-compose.yaml Dockerfile static/*) +(cd app2 && zip ../app2.zip docker-compose.yaml Dockerfile static/*) + +popd ||: diff --git a/tests/operations.robot b/tests/operations.robot index 4f735c3..3e11622 100644 --- a/tests/operations.robot +++ b/tests/operations.robot @@ -25,6 +25,11 @@ Install container-group package Should Contain ${operation.to_json()["c8y_Command"]["result"]} Welcome to nginx Cumulocity.Should Have Services name=nginx@nginx service_type=container-group status=up +Install container-group with multiple files + [Template] Install container-group file + app1 1.0.1 app1 ${CURDIR}/data/apps/app1.tar.gz + app2 1.2.3 app2 ${CURDIR}/data/apps/app2.zip + Uninstall container-group ${operation}= Cumulocity.Uninstall Software {"name": "nginx", "version": "1.0.0", "softwareType": "container-group"} Operation Should Be SUCCESSFUL ${operation} @@ -49,3 +54,14 @@ Uninstall container package Suite Setup Set Main Device + +Install container-group file + [Arguments] ${package_name} ${package_version} ${service_name} ${file} + ${binary_url}= Cumulocity.Create Inventory Binary ${package_name} container-group file=${file} + ${operation}= Cumulocity.Install Software {"name": "${package_name}", "version": "${package_version}", "softwareType": "container-group", "url": "${binary_url}"} + Operation Should Be SUCCESSFUL ${operation} + Device Should Have Installed Software {"name": "${package_name}", "version": "${package_version}", "softwareType": "container-group"} + ${operation}= Cumulocity.Execute Shell Command wget -O- ${service_name}:80 + Operation Should Be SUCCESSFUL ${operation} + Should Contain ${operation.to_json()["c8y_Command"]["result"]} My Custom Web Application + Cumulocity.Should Have Services name=${package_name}@${service_name} service_type=container-group status=up From 32cd28f2137412d4a4873bad1aefa0010a7fe0e0 Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Wed, 7 Feb 2024 23:17:02 +0100 Subject: [PATCH 4/5] add nots about the container-group archive support --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bdea481..deda36b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The instructions assume that you are using thin-edge.io >= 1.0.0 * A service called `tedge-container-monitor`. This provides the monitoring of the containers * The following software management plugins which is called when installing and removing containers/container groups via Cumulocity IoT * `container` - Deploy a single container (`docker run xxx` equivalent) - * `container-group` - Deploy one or more container as defined by a `docker-compose.yaml` file (`docker compose up` equivalent) + * `container-group` - Deploy one or more container as defined by a `docker-compose.yaml` file (`docker compose up` equivalent), or an archive (gzip or zip) **Note** @@ -46,7 +46,7 @@ The following linux package formats are provided on the releases page and also i The following features are supported by the plugin: * Install/remove containers via the Cumulocity IoT software interface -* Install multiple containers as one group using a `docker-compose.yaml` file +* Install multiple containers as one group using a `docker-compose.yaml` file or an archive container a `docker-compose.yaml` file * Monitor container states (e.g. up/down) via Cumulocity IoT Services (only supported from tedge >= 0.10.0) * Download container images via Cumulocity IoT binaries if a URL is provided * Support for multiple container engines (docker, podman, nerdctl) @@ -71,7 +71,7 @@ The software package properties are also describe below: ### Install/remove a `container-group` -A `container-group` is the name given to deploy a `docker-compose.yaml` file. A docker compose file allows use to deploy multiple containers/networks/volumes and allows you maximum control over how the container is started. This means you can create a complex setup of persisted volumes, isolated networks, and also facilitate communication between containers. Check out the [docker compose documentation](https://docs.docker.com/compose/compose-file/) for more details on how to write your own service definition. +A `container-group` is the name given to deploy a `docker-compose.yaml` file or an archive (zip or gzip file) with the `docker-compose.yaml` file at the root level of the archive. A docker compose file allows use to deploy multiple containers/networks/volumes and allows you maximum control over how the container is started. This means you can create a complex setup of persisted volumes, isolated networks, and also facilitate communication between containers. Check out the [docker compose documentation](https://docs.docker.com/compose/compose-file/) for more details on how to write your own service definition. The software package properties are also describe below: From 5b677cde9ba367a4afc173c32eabba6188e159d9 Mon Sep 17 00:00:00 2001 From: Reuben Miller Date: Wed, 7 Feb 2024 23:17:30 +0100 Subject: [PATCH 5/5] add missing step how to locally run tests --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index deda36b..d058070 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,13 @@ To run the tests you will need to have python3 >> 3.9 installed on your syste C8Y_PASSWORD="mypassword" ``` -2. Startup the test setup, and bootstrap it +2. Build the software management plugin + + ``` + just build + ``` + +3. Startup the test setup, and bootstrap it ``` just up @@ -310,13 +316,13 @@ To run the tests you will need to have python3 >> 3.9 installed on your syste just bootstrap ``` -3. Setup the python3 virtual environment and install the test dependencies +4. Setup the python3 virtual environment and install the test dependencies ``` just venv ``` -4. Run the RobotFramework tests +5. Run the RobotFramework tests ``` just test