diff --git a/cmd/backup/stop_restart.go b/cmd/backup/stop_restart.go index 73af5d2c..0baae201 100644 --- a/cmd/backup/stop_restart.go +++ b/cmd/backup/stop_restart.go @@ -81,6 +81,16 @@ func awaitContainerCountForService(cli *client.Client, serviceID string, count i } } +func isSwarm(c interface { + Info(context.Context) (types.Info, error) +}) (bool, error) { + info, err := c.Info(context.Background()) + if err != nil { + return false, errwrap.Wrap(err, "error getting docker info") + } + return info.Swarm.LocalNodeState != "" && info.Swarm.LocalNodeState != swarm.LocalNodeStateInactive, nil +} + // stopContainersAndServices stops all Docker containers that are marked as to being // stopped during the backup and returns a function that can be called to // restart everything that has been stopped. @@ -89,11 +99,10 @@ func (s *script) stopContainersAndServices() (func() error, error) { return noop, nil } - dockerInfo, err := s.cli.Info(context.Background()) + isDockerSwarm, err := isSwarm(s.cli) if err != nil { - return noop, errwrap.Wrap(err, "error getting docker info") + return noop, errwrap.Wrap(err, "error determining swarm state") } - isDockerSwarm := dockerInfo.Swarm.LocalNodeState != "inactive" labelValue := s.c.BackupStopDuringBackupLabel if s.c.BackupStopContainerLabel != "" { diff --git a/test/balena/Dockerfile b/test/balena/Dockerfile new file mode 100644 index 00000000..cb018a70 --- /dev/null +++ b/test/balena/Dockerfile @@ -0,0 +1,76 @@ +#syntax=docker/dockerfile:1.2 + +# BUILDPLATFORM is set by buildkit (DOCKER_BUILDKIT=1) +# hadolint ignore=DL3029 +FROM --platform=$BUILDPLATFORM debian:bullseye-20211220-slim AS buildroot-base + +# hadolint ignore=DL3008 +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + bc \ + build-essential \ + ca-certificates \ + cmake \ + cpio \ + file \ + git \ + locales \ + python3 \ + rsync \ + unzip \ + wget && \ + apt-get clean && rm -rf /var/lib/apt/lists/* + +# hadolint ignore=DL3059 +RUN sed -i 's/# \(en_US.UTF-8\)/\1/' /etc/locale.gen && \ + /usr/sbin/locale-gen && \ + useradd -ms /bin/bash br-user && \ + chown -R br-user:br-user /home/br-user + +USER br-user + +WORKDIR /home/br-user + +ENV HOME=/home/br-user + +ENV LC_ALL=en_US.UTF-8 + +ARG BR_VERSION=2021.11 + +RUN git clone --depth 1 --branch ${BR_VERSION} https://git.busybox.net/buildroot + +FROM buildroot-base as rootfs + +WORKDIR /home/br-user/buildroot + +# set by buildkit (DOCKER_BUILDKIT=1) +ARG TARGETARCH +ARG TARGETVARIANT + +# musl or glibc (musl is smaller) +ARG ROOTFS_LIBC=musl + +COPY config ./config + +RUN support/kconfig/merge_config.sh -m \ + config/arch/"${TARGETARCH}${TARGETVARIANT}".cfg \ + config/libc/"${ROOTFS_LIBC}".cfg \ + config/*.cfg + +RUN --mount=type=cache,target=/cache,uid=1000,gid=1000,sharing=private \ + make olddefconfig && make source && make + +# hadolint ignore=DL3002 +USER root + +WORKDIR /rootfs + +RUN tar xpf /home/br-user/buildroot/output/images/rootfs.tar -C /rootfs + +FROM scratch + +COPY --from=rootfs rootfs/ / + +ENTRYPOINT [ "/usr/bin/balena-engine-daemon" ] + +CMD [ "-H", "tcp://0.0.0.0:2375" ] diff --git a/test/balena/NOTICE b/test/balena/NOTICE new file mode 100644 index 00000000..f5aff99d --- /dev/null +++ b/test/balena/NOTICE @@ -0,0 +1,4 @@ +Dockerfile and content in `config` is taken from +https://github.com/balena-io-experimental/balena-engine-docker which is +distributed under the Apache-2.0 license: +https://github.com/balena-io-experimental/balena-engine-docker/blob/532d24e746240a5d26bcd55112e8cf68dd6b8227/LICENSE diff --git a/test/balena/config/arch/amd64.cfg b/test/balena/config/arch/amd64.cfg new file mode 100644 index 00000000..447655bd --- /dev/null +++ b/test/balena/config/arch/amd64.cfg @@ -0,0 +1 @@ +BR2_x86_64=y diff --git a/test/balena/config/arch/arm64.cfg b/test/balena/config/arch/arm64.cfg new file mode 100644 index 00000000..1c771472 --- /dev/null +++ b/test/balena/config/arch/arm64.cfg @@ -0,0 +1 @@ +BR2_aarch64=y diff --git a/test/balena/config/arch/armv6.cfg b/test/balena/config/arch/armv6.cfg new file mode 100644 index 00000000..560b9a9b --- /dev/null +++ b/test/balena/config/arch/armv6.cfg @@ -0,0 +1,2 @@ +BR2_arm=y +BR2_arm1176jzf_s=y diff --git a/test/balena/config/arch/armv7.cfg b/test/balena/config/arch/armv7.cfg new file mode 100644 index 00000000..5d689c0b --- /dev/null +++ b/test/balena/config/arch/armv7.cfg @@ -0,0 +1 @@ +BR2_arm=y diff --git a/test/balena/config/balena-engine.cfg b/test/balena/config/balena-engine.cfg new file mode 100644 index 00000000..d56f2873 --- /dev/null +++ b/test/balena/config/balena-engine.cfg @@ -0,0 +1,3 @@ +BR2_PACKAGE_TINI=y +BR2_PACKAGE_BALENA_ENGINE=y +BR2_PACKAGE_CA_CERTIFICATES=y diff --git a/test/balena/config/common.cfg b/test/balena/config/common.cfg new file mode 100644 index 00000000..d4ac76b7 --- /dev/null +++ b/test/balena/config/common.cfg @@ -0,0 +1,20 @@ +BR2_TOOLCHAIN_BUILDROOT_CXX=y +BR2_KERNEL_HEADERS_4_19=y +BR2_GCC_ENABLE_LTO=y + +# We don't need init inside a container +BR2_INIT_NONE=y + +# Also unselect busybox +BR2_PACKAGE_BUSYBOX=n + +# We don't need a system shell or ifupdown-scripts +BR2_SYSTEM_BIN_SH_NONE=y +BR2_PACKAGE_IFUPDOWN_SCRIPTS=n + +# Setup cache paths +BR2_DL_DIR="/cache/dl" + +BR2_CCACHE=y +BR2_CCACHE_DIR="/cache/ccache" +BR2_CCACHE_USE_BASEDIR=y diff --git a/test/balena/config/libc/glibc.cfg b/test/balena/config/libc/glibc.cfg new file mode 100644 index 00000000..94c0be83 --- /dev/null +++ b/test/balena/config/libc/glibc.cfg @@ -0,0 +1 @@ +BR2_TOOLCHAIN_BUILDROOT_GLIBC=y diff --git a/test/balena/config/libc/musl.cfg b/test/balena/config/libc/musl.cfg new file mode 100644 index 00000000..cb38dfbc --- /dev/null +++ b/test/balena/config/libc/musl.cfg @@ -0,0 +1 @@ +BR2_TOOLCHAIN_BUILDROOT_MUSL=y diff --git a/test/balena/docker-compose.yml b/test/balena/docker-compose.yml new file mode 100644 index 00000000..33832c20 --- /dev/null +++ b/test/balena/docker-compose.yml @@ -0,0 +1,30 @@ +version: '3' + +services: + balena: + build: . + privileged: true + + backup: + image: offen/docker-volume-backup:${TEST_VERSION:-canary} + hostname: hostnametoken + restart: always + environment: + BACKUP_CRON_EXPRESSION: 0 0 5 31 2 ? + BACKUP_FILENAME: test.tar.gz + DOCKER_HOST: tcp://balena:2375 + volumes: + - ${LOCAL_DIR:-./local}:/archive + - app_data:/backup/app_data:ro + + offen: + image: offen/offen:latest + labels: + - docker-volume-backup.stop-during-backup=true + volumes: + - app_data:/var/opt/offen + +volumes: + minio_backup_data: + name: minio_backup_data + app_data: diff --git a/test/balena/run.sh b/test/balena/run.sh new file mode 100755 index 00000000..f52b78f3 --- /dev/null +++ b/test/balena/run.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +cd $(dirname $0) +. ../util.sh +current_test=$(basename $(pwd)) + +export LOCAL_DIR=$(mktemp -d) + +docker compose up -d + +sleep 20 + +expect_running_containers "3" + +docker compose exec backup backup + +sleep 5 + +if [ ! -f $LOCAL_DIR/test.tar.gz ]; then + fail "Archive was not created" +fi +pass "Found expected file." + +expect_running_containers "3"