From 4f449fc554efd7536bb0e561592c8fa0ab0577ec Mon Sep 17 00:00:00 2001
From: Devin Kelley <105753233+devkelley@users.noreply.github.com>
Date: Tue, 28 Nov 2023 16:54:26 -0800
Subject: [PATCH 1/7] Add/Update Dockerfiles to provide arm64 support
---
.cargo/config.toml | 4 +
Cargo.lock | 10 +
Dockerfile | 2 +-
Dockerfile.arm64 | 95 +++++++++
Dockerfile.mosquitto | 19 ++
Dockerfile.mosquitto.arm64 | 19 ++
Dockerfile.samples | 89 ++++++++
Dockerfile.samples.arm64 | 92 ++++++++
README.md | 124 +----------
container/template/docker.env | 9 -
container/template/podman.env | 9 -
docs/containers.md | 199 ++++++++++++++++++
pub-sub-service/Cargo.toml | 4 +-
.../src/connectors/chariott_connector.rs | 5 +-
.../src/connectors/mosquitto_connector.rs | 12 +-
pub-sub-service/src/load_config.rs | 22 --
pub-sub-service/src/topic_manager.rs | 7 +-
samples/README.md | 11 +
samples/connectors/mqtt-five/Cargo.toml | 5 +-
19 files changed, 554 insertions(+), 183 deletions(-)
create mode 100644 Dockerfile.arm64
create mode 100644 Dockerfile.mosquitto
create mode 100644 Dockerfile.mosquitto.arm64
create mode 100644 Dockerfile.samples
create mode 100644 Dockerfile.samples.arm64
delete mode 100644 container/template/docker.env
delete mode 100644 container/template/podman.env
create mode 100644 docs/containers.md
diff --git a/.cargo/config.toml b/.cargo/config.toml
index 7b38eb0..4fd7cf9 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -5,3 +5,7 @@
[env]
AGEMO_HOME = { value = ".agemo", relative = true }
AGEMO_SAMPLES_HOME = { value = ".agemo-samples", relative = true }
+
+[target.aarch64-unknown-linux-gnu]
+linker = "aarch64-linux-gnu-gcc"
+rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc" ]
diff --git a/Cargo.lock b/Cargo.lock
index 50e4d48..fc48c2c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1141,6 +1141,15 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+[[package]]
+name = "openssl-src"
+version = "300.1.6+3.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085"
+dependencies = [
+ "cc",
+]
+
[[package]]
name = "openssl-sys"
version = "0.9.96"
@@ -1149,6 +1158,7 @@ checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f"
dependencies = [
"cc",
"libc",
+ "openssl-src",
"pkg-config",
"vcpkg",
]
diff --git a/Dockerfile b/Dockerfile
index d0b02d1..f616ee2 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -33,7 +33,7 @@ RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
}
# Build the application with the 'containerize' feature.
-RUN cargo build --features containerize --release -p "${APP_NAME}"
+RUN cargo build --release -p "${APP_NAME}"
# Copy the built application to working directory.
RUN cp ./target/release/"${APP_NAME}" /sdv/service
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
new file mode 100644
index 0000000..072721a
--- /dev/null
+++ b/Dockerfile.arm64
@@ -0,0 +1,95 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+# SPDX-License-Identifier: MIT
+
+# syntax=docker/dockerfile:1
+
+# Comments are provided throughout this file to help you get started.
+# If you need more help, visit the Dockerfile reference guide at
+# https://docs.docker.com/engine/reference/builder/
+
+################################################################################
+# Create a stage for building the application.
+
+ARG RUST_VERSION=1.72.1
+FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
+ARG APP_NAME=pub-sub-service
+WORKDIR /sdv
+
+COPY ./ .
+
+# Add Build dependencies.
+RUN apt update && apt upgrade -y && apt install -y \
+ cmake \
+ libssl-dev \
+ pkg-config \
+ protobuf-compiler \
+ gcc-aarch64-linux-gnu
+
+# Check that APP_NAME argument is valid.
+RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
+[ "$sanitized" = "${APP_NAME}" ] || { \
+ echo "ARG 'APP_NAME' is invalid. APP_NAME='${APP_NAME}' sanitized='${sanitized}'"; \
+ exit 1; \
+}
+
+RUN rustup target add aarch64-unknown-linux-gnu
+
+# Build the application with the 'containerize' feature.
+RUN cargo build --release --target=aarch64-unknown-linux-gnu -p "${APP_NAME}"
+
+# Copy the built application to working directory.
+RUN cp ./target/aarch64-unknown-linux-gnu/release/"${APP_NAME}" /sdv/service
+
+################################################################################
+# Create a new stage for running the application that contains the minimal
+# runtime dependencies for the application. This often uses a different base
+# image from the build stage where the necessary files are copied from the build
+# stage.
+#
+# The example below uses the debian bullseye image as the foundation for running the app.
+# By specifying the "bullseye-slim" tag, it will also use whatever happens to be the
+# most recent version of that tag when you build your Dockerfile. If
+# reproducability is important, consider using a digest
+# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
+FROM docker.io/arm64v8/debian:bullseye-slim AS final
+
+# Create a non-privileged user that the app will run under.
+# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
+ARG UID=10001
+RUN adduser \
+ --disabled-password \
+ --gecos "" \
+ --home "/nonexistent" \
+ --shell "/sbin/nologin" \
+ --no-create-home \
+ --uid "${UID}" \
+ appuser
+
+# Create and add user ownership to config directory.
+RUN mkdir -p /sdv/.agemo/config
+RUN chown appuser /sdv/.agemo/config
+
+# Create mnt directory to copy override configs into.
+RUN mkdir -p /mnt/config
+
+USER appuser
+
+WORKDIR /sdv
+
+ENV AGEMO_HOME=/sdv/.agemo
+
+# Copy the executable from the "build" stage.
+COPY --from=build /sdv/service /sdv/
+
+# Copy startup script.
+COPY --from=build /sdv/container_startup.sh /sdv/container_startup.sh
+
+# Copy default configs.
+COPY --from=build /sdv/.agemo/config/ /sdv/.agemo/config/
+
+# Expose the port that the application listens on.
+EXPOSE 50051
+
+# What the container should run when it is started.
+CMD ["/sdv/container_startup.sh"]
diff --git a/Dockerfile.mosquitto b/Dockerfile.mosquitto
new file mode 100644
index 0000000..3905c3e
--- /dev/null
+++ b/Dockerfile.mosquitto
@@ -0,0 +1,19 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+# SPDX-License-Identifier: MIT
+
+# syntax=docker/dockerfile:1
+
+# Comments are provided throughout this file to help you get started.
+# If you need more help, visit the Dockerfile reference guide at
+# https://docs.docker.com/engine/reference/builder/
+
+################################################################################
+# Create a stage for building the application.
+
+FROM docker.io/library/eclipse-mosquitto
+WORKDIR /mosquitto/config
+
+COPY ./pub-sub-service/src/connectors/mosquitto.conf ./mosquitto.conf
+
+EXPOSE 1883
\ No newline at end of file
diff --git a/Dockerfile.mosquitto.arm64 b/Dockerfile.mosquitto.arm64
new file mode 100644
index 0000000..c55b9e5
--- /dev/null
+++ b/Dockerfile.mosquitto.arm64
@@ -0,0 +1,19 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+# SPDX-License-Identifier: MIT
+
+# syntax=docker/dockerfile:1
+
+# Comments are provided throughout this file to help you get started.
+# If you need more help, visit the Dockerfile reference guide at
+# https://docs.docker.com/engine/reference/builder/
+
+################################################################################
+# Create a stage for building the application.
+
+FROM docker.io/arm64v8/eclipse-mosquitto
+WORKDIR /mosquitto/config
+
+COPY ./pub-sub-service/src/connectors/mosquitto.conf ./mosquitto.conf
+
+EXPOSE 1883
\ No newline at end of file
diff --git a/Dockerfile.samples b/Dockerfile.samples
new file mode 100644
index 0000000..c2daa65
--- /dev/null
+++ b/Dockerfile.samples
@@ -0,0 +1,89 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+# SPDX-License-Identifier: MIT
+
+# syntax=docker/dockerfile:1
+
+# Comments are provided throughout this file to help you get started.
+# If you need more help, visit the Dockerfile reference guide at
+# https://docs.docker.com/engine/reference/builder/
+
+################################################################################
+# Create a stage for building the application.
+
+ARG RUST_VERSION=1.72.1
+FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
+ARG APP_NAME=simple-publisher
+WORKDIR /sdv
+
+COPY ./ .
+
+# Add Build dependencies.
+RUN apt update && apt upgrade -y && apt install -y \
+ cmake \
+ libssl-dev \
+ pkg-config \
+ protobuf-compiler
+
+# Check that APP_NAME argument is valid.
+RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
+[ "$sanitized" = "${APP_NAME}" ] || { \
+ echo "ARG 'APP_NAME' is invalid. APP_NAME='${APP_NAME}' sanitized='${sanitized}'"; \
+ exit 1; \
+}
+
+# Build the application with the 'containerize' feature.
+RUN cargo build --release -p "${APP_NAME}"
+
+# Copy the built application to working directory.
+RUN cp ./target/release/"${APP_NAME}" /sdv/service
+
+################################################################################
+# Create a new stage for running the application that contains the minimal
+# runtime dependencies for the application. This often uses a different base
+# image from the build stage where the necessary files are copied from the build
+# stage.
+#
+# The example below uses the debian bullseye image as the foundation for running the app.
+# By specifying the "bullseye-slim" tag, it will also use whatever happens to be the
+# most recent version of that tag when you build your Dockerfile. If
+# reproducability is important, consider using a digest
+# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
+FROM docker.io/library/debian:bullseye-slim AS final
+
+# Create a non-privileged user that the app will run under.
+# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
+ARG UID=10001
+RUN adduser \
+ --disabled-password \
+ --gecos "" \
+ --home "/nonexistent" \
+ --shell "/sbin/nologin" \
+ --no-create-home \
+ --uid "${UID}" \
+ appuser
+
+# Create and add user ownership to config directory.
+RUN mkdir -p /sdv/.agemo/config
+RUN chown appuser /sdv/.agemo/config
+
+# Create mnt directory to copy override configs into.
+RUN mkdir -p /mnt/config
+
+USER appuser
+
+WORKDIR /sdv
+
+ENV AGEMO_SAMPLES_HOME=/sdv/.agemo
+
+# Copy the executable from the "build" stage.
+COPY --from=build /sdv/service /sdv/
+
+# Copy startup script.
+COPY --from=build /sdv/container_startup.sh /sdv/container_startup.sh
+
+# Copy default configs.
+COPY --from=build /sdv/.agemo-samples/config/ /sdv/.agemo/config/
+
+# What the container should run when it is started.
+CMD ["/sdv/container_startup.sh"]
diff --git a/Dockerfile.samples.arm64 b/Dockerfile.samples.arm64
new file mode 100644
index 0000000..3f412f5
--- /dev/null
+++ b/Dockerfile.samples.arm64
@@ -0,0 +1,92 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+# SPDX-License-Identifier: MIT
+
+# syntax=docker/dockerfile:1
+
+# Comments are provided throughout this file to help you get started.
+# If you need more help, visit the Dockerfile reference guide at
+# https://docs.docker.com/engine/reference/builder/
+
+################################################################################
+# Create a stage for building the application.
+
+ARG RUST_VERSION=1.72.1
+FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
+ARG APP_NAME=simple-publisher
+WORKDIR /sdv
+
+COPY ./ .
+
+# Add Build dependencies.
+RUN apt update && apt upgrade -y && apt install -y \
+ cmake \
+ libssl-dev \
+ pkg-config \
+ protobuf-compiler \
+ gcc-aarch64-linux-gnu
+
+# Check that APP_NAME argument is valid.
+RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
+[ "$sanitized" = "${APP_NAME}" ] || { \
+ echo "ARG 'APP_NAME' is invalid. APP_NAME='${APP_NAME}' sanitized='${sanitized}'"; \
+ exit 1; \
+}
+
+RUN rustup target add aarch64-unknown-linux-gnu
+
+# Build the application with the 'containerize' feature.
+RUN cargo build --release --target=aarch64-unknown-linux-gnu -p "${APP_NAME}"
+
+# Copy the built application to working directory.
+RUN cp ./target/aarch64-unknown-linux-gnu/release/"${APP_NAME}" /sdv/service
+
+################################################################################
+# Create a new stage for running the application that contains the minimal
+# runtime dependencies for the application. This often uses a different base
+# image from the build stage where the necessary files are copied from the build
+# stage.
+#
+# The example below uses the debian bullseye image as the foundation for running the app.
+# By specifying the "bullseye-slim" tag, it will also use whatever happens to be the
+# most recent version of that tag when you build your Dockerfile. If
+# reproducability is important, consider using a digest
+# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
+FROM docker.io/arm64v8/debian:bullseye-slim AS final
+
+# Create a non-privileged user that the app will run under.
+# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
+ARG UID=10001
+RUN adduser \
+ --disabled-password \
+ --gecos "" \
+ --home "/nonexistent" \
+ --shell "/sbin/nologin" \
+ --no-create-home \
+ --uid "${UID}" \
+ appuser
+
+# Create and add user ownership to config directory.
+RUN mkdir -p /sdv/.agemo/config
+RUN chown appuser /sdv/.agemo/config
+
+# Create mnt directory to copy override configs into.
+RUN mkdir -p /mnt/config
+
+USER appuser
+
+WORKDIR /sdv
+
+ENV AGEMO_SAMPLES_HOME=/sdv/.agemo
+
+# Copy the executable from the "build" stage.
+COPY --from=build /sdv/service /sdv/
+
+# Copy startup script.
+COPY --from=build /sdv/container_startup.sh /sdv/container_startup.sh
+
+# Copy default configs.
+COPY --from=build /sdv/.agemo-samples/config/ /sdv/.agemo/config/
+
+# What the container should run when it is started.
+CMD ["/sdv/container_startup.sh"]
diff --git a/README.md b/README.md
index 2db0eaf..994f0ad 100644
--- a/README.md
+++ b/README.md
@@ -197,127 +197,11 @@ see more full featured examples in
## Running in a Container
-Below are the steps for running the service in a container. Note that the default configuration
-files used by the containerized service are cloned from [.agemo/config](.agemo/config/) defined in
-the project's root.
+Please refer to the following links for how to build and run the service in a OCI container:
-### Docker
-
-#### Prequisites
-
-[Install Docker](https://docs.docker.com/engine/install/)
-
-#### Running in Docker
-
-To run the service in a Docker container:
-
-1. Copy the [docker.env](./container/template/docker.env) template into the project root directory.
-The file sets two environment variables, 'HOST_GATEWAY' and 'LOCALHOST_ALIAS', where 'HOST_GATEWAY'
-is the DNS name used by the container to represent the localhost address and 'LOCALHOST_ALIAS' is
-the localhost address used in the service's configuration settings. This file should already be set
-up with out any modification needed. From the project root directory, the file can be copied with:
-
- ```shell
- cp ./container/template/docker.env .
- ```
-
-1. Run the following command in the project root directory to build the docker container from the
-Dockerfile:
-
- ```shell
- docker build -t pub_sub_service -f Dockerfile .
- ```
-
-1. Once the container has been built, start the container in interactive mode with the following
-command in the project root directory:
-
- ```shell
- docker run --name pub_sub_service -p 50051:50051 --env-file=docker.env --add-host=host.docker.internal:host-gateway -it --rm pub_sub_service
- ```
-
-1. To detach from the container, enter:
-
- Ctrl + p, Ctrl + q
-
-1. To stop the container, enter:
-
- ```shell
- docker stop pub_sub_service
- ```
-
-#### Running in Docker with overriden configuration
-
-Follow the steps in [Running in Docker](#running-in-docker) to build the container.
-
-1. To run the container with overriden configuration, create your config file and set an
-environment variable called CONFIG_HOME to the path to the config file:
-
- ```shell
- export CONFIG_HOME={path to directory containing config file}
- ```
-
-1. Then run the container with the following command:
-
- ```shell
- docker run -v ${CONFIG_HOME}:/mnt/config --name pub_sub_service -p 50051:50051 --env-file=docker.env --add-host=host.docker.internal:host-gateway -it --rm pub_sub_service
- ```
-
-### Podman
-
-#### Prequisites
-
-[Install Podman](https://podman.io/docs/installation)
-
-#### Running in Podman
-
-To run the service in a Podman container:
-
-1. Copy the [podman.env](./container/template/podman.env) template into the project root directory.
-The file sets two environment variables, 'HOST_GATEWAY' and 'LOCALHOST_ALIAS', where 'HOST_GATEWAY'
-is the DNS name used by the container to represent the localhost address and 'LOCALHOST_ALIAS' is
-the localhost address used in the service's configuration settings. This file should already be set
-up with out any modification needed. From the project root directory, the file can be copied with:
-
- ```shell
- cp ./container/template/podman.env .
- ```
-
-1. Run the following command in the project root directory to build the podman container from the
-Dockerfile:
-
- ```shell
- podman build -t pub_sub_service:latest -f Dockerfile .
- ```
-
-1. Once the container has been built, start the container with the following command in the project
-root directory:
-
- ```shell
- podman run -p 50051:50051 --env-file=podman.env --network=slirp4netns:allow_host_loopback=true localhost/pub_sub_service
- ```
-
-1. To stop the container, run:
-
- ```shell
- podman ps -f ancestor=localhost/pub_sub_service:latest --format="{{.Names}}" | xargs podman stop
- ```
-
-#### Running in Podman with overriden configuration
-
-Follow the steps in [Running in Podman](#running-in-podman) to build the container.
-
-1. To run the container with overriden configuration, create your config file and set an
-environment variable called CONFIG_HOME to the path to the config file:
-
- ```shell
- export CONFIG_HOME={path to directory containing config file}
- ```
-
-1. Then run the container with the following command:
-
- ```shell
- podman run --mount=type=bind,src=${CONFIG_HOME},dst=/mnt/config,ro=true -p 50051:50051 --env-file=podman.env --network=slirp4netns:allow_host_loopback=true localhost/pub_sub_service
- ```
+- [Provided Dockerfiles](./docs/containers.md#dockerfiles)
+- [Docker Containers](./docs/containers.md#docker-containers)
+- [Podman Containers](./docs/containers.md#podman-containers)
## Trademarks
diff --git a/container/template/docker.env b/container/template/docker.env
deleted file mode 100644
index 56bafc6..0000000
--- a/container/template/docker.env
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) Microsoft Corporation.
-# Licensed under the MIT license.
-# SPDX-License-Identifier: MIT
-
-# DNS name used by the container to communicate with host.
-HOST_GATEWAY=host.docker.internal
-
-# Alias for localhost to be replaced by HOST_GATEWAY if run in a container.
-LOCALHOST_ALIAS=0.0.0.0
diff --git a/container/template/podman.env b/container/template/podman.env
deleted file mode 100644
index 1abc4a3..0000000
--- a/container/template/podman.env
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) Microsoft Corporation.
-# Licensed under the MIT license.
-# SPDX-License-Identifier: MIT
-
-# DNS name used by the container to communicate with host.
-HOST_GATEWAY=host.containers.internal
-
-# Alias for localhost to be replaced by HOST_GATEWAY if run in a container.
-LOCALHOST_ALIAS=0.0.0.0
diff --git a/docs/containers.md b/docs/containers.md
new file mode 100644
index 0000000..8f7c231
--- /dev/null
+++ b/docs/containers.md
@@ -0,0 +1,199 @@
+## Containers
+
+### Dockerfiles
+
+This repository currently provides the following Dockerfiles:
+
+#### Pub Sub Service
+
+- [Dockerfile](../Dockerfile) - Dockerfile used to build the `Pub Sub Service`.
+- [Dockerfile.arm64](../Dockerfile.arm64) - Dockerfile used to build the `Pub Sub Service` for the
+aarch64 architecture.
+
+>Note: The default configuration files are cloned from [.agemo/config](../.agemo/config/), defined
+in the project's root.
+
+#### Mosquitto MQTT Broker
+
+- [Dockerfile.mosquitto](../Dockerfile.mosquitto) - Dockerfile used to build the
+`Mosquitto MQTT Broker` with the appropriate configuration.
+- [Dockerfile.mosquitto.arm64](../Dockerfile.mosquitto.arm64) - Dockerfile used to build the
+`Mosquitto MQTT Broker` with the appropriate configuration for the aarch64 architecture.
+
+#### Sample Applications
+
+- [Dockerfile.samples](../Dockerfile.samples) - Dockerfile used to build one of the sample
+applications.
+- [Dockerfile.samples.arm64](../Dockerfile.samples.arm64) - Dockerfile used to build one of the
+sample applications for the aarch64 architecture.
+
+>Note: The samples default configuration files are cloned from
+[.agemo-samples/config](../.agemo-samples/config/), defined in the project's root.
+
+### Docker Containers
+
+#### Prequisites
+
+[Install Docker](https://docs.docker.com/engine/install/)
+
+#### Running in Docker
+
+To run the service in a Docker container:
+
+1. Run the following command in the project root directory to build the docker container from the
+Dockerfile:
+
+ ```shell
+ docker build -t -f (optional: --build-arg=APP_NAME=) .
+ ```
+
+ For example, to build an image for the `pub-sub-service` project:
+
+ ```shell
+ docker build -t pub_sub_service -f Dockerfile .
+ ```
+
+ Or to build an image for the `chariott-publisher` sample for aarch64:
+
+ ```shell
+ docker build -t chariott_publisher -f Dockerfile.samples.arm64 --build-arg=APP_NAME=chariott-publisher .
+ ```
+
+ >Note: The build arg `APP_NAME` needs to be passed in for all sample applications to build the
+ correct sample.
+
+1. Once the container has been built, start the container in interactive mode with the following
+command in the project root directory:
+
+ ```shell
+ docker run --name --network=host -it --rm
+ ```
+
+ For example, to run the `pub-sub-service` image built in step 1:
+
+ ```shell
+ docker run --name pub_sub_service --network=host -it --rm pub_sub_service
+ ```
+
+ >Note: A custom network is recommended when using a container for anything but testing.
+
+1. To detach from the container, enter:
+
+ Ctrl + p, Ctrl + q
+
+1. To stop the container, enter:
+
+ ```shell
+ docker stop
+ ```
+
+ For example, to stop the `pub_sub_service` container started in step 2:
+
+ ```shell
+ docker stop pub_sub_service
+ ```
+
+#### Running in Docker with overridden configuration
+
+Follow the steps in [Running in Docker](#running-in-docker) to build the container.
+
+1. To run the container with overridden configuration, create your config file and set an
+environment variable called CONFIG_HOME to the path to the config file:
+
+ ```shell
+ export CONFIG_HOME={path to directory containing config file}
+ ```
+
+1. Then run the container with the following command:
+
+ ```shell
+ docker run -v ${CONFIG_HOME}:/mnt/config --name --network=host -it --rm
+ ```
+
+ For example, to run the `pub_sub_service` image with overridden configuration:
+
+ ```shell
+ docker run -v ${CONFIG_HOME}:/mnt/config --name pub_sub_service --network=host -it --rm pub_sub_service
+ ```
+
+### Podman Containers
+
+#### Prequisites
+
+[Install Podman](https://podman.io/docs/installation)
+
+#### Running in Podman
+
+To run the service in a Podman container:
+
+1. Run the following command in the project root directory to build the podman container from the
+Dockerfile:
+
+ ```shell
+ podman build -t -f .
+ ```
+
+ For example, to build an image for the `pub-sub-service` project:
+
+ ```shell
+ podman build -t pub_sub_service -f Dockerfile .
+ ```
+
+ Or to build an image for the `chariott-publisher` sample for aarch64:
+
+ ```shell
+ podman build -t chariott_publisher -f Dockerfile.samples.arm64 --build-arg=APP_NAME=chariott-publisher .
+ ```
+
+ >Note: The build arg `APP_NAME` needs to be passed in for all sample applications to build the
+ correct sample.
+
+1. Once the container has been built, start the container with the following command in the project
+root directory:
+
+ ```shell
+ podman run --network=host
+ ```
+
+ For example, to run the `pub-sub-service` image built in step 1:
+
+ ```shell
+ podman run --network=host pub_sub_service
+ ```
+
+ >Note: A custom network is recommended when using a container for anything but testing.
+
+1. To stop the container, run:
+
+ ```shell
+ podman ps -f ancestor= --format="{{.Names}}" | xargs podman stop
+ ```
+
+ For example, to stop the `pub_sub_service` container started in step 2:
+
+ ```shell
+ podman ps -f ancestor=localhost/pub_sub_service:latest --format="{{.Names}}" | xargs podman stop
+ ```
+
+#### Running in Podman with overridden configuration
+
+Follow the steps in [Running in Podman](#running-in-podman) to build the container.
+
+1. To run the container with overridden configuration, create your config file and set an
+environment variable called CONFIG_HOME to the path to the config file:
+
+ ```shell
+ export CONFIG_HOME={path to directory containing config file}
+ ```
+
+1. Then run the container with the following command:
+
+ ```shell
+ podman run --mount=type=bind,src=${CONFIG_HOME},dst=/mnt/config,ro=true --network=host
+ ```
+
+ For example, to run the `pub_sub_service` image with overridden configuration:
+
+ ```shell
+ podman run --mount=type=bind,src=${CONFIG_HOME},dst=/mnt/config,ro=true --network=host pub_sub_service
+ ```
diff --git a/pub-sub-service/Cargo.toml b/pub-sub-service/Cargo.toml
index 9faec05..8a3380f 100644
--- a/pub-sub-service/Cargo.toml
+++ b/pub-sub-service/Cargo.toml
@@ -28,5 +28,5 @@ url = { workspace = true }
uuid = { workspace = true, features = [ "v4", "fast-rng", "macro-diagnostics"] }
yaml-rust = { workspace = true }
-[features]
-containerize = []
+[target.'cfg(target_arch = "aarch64")'.dependencies]
+paho-mqtt = { workspace = true, features = ["vendored-ssl"] }
diff --git a/pub-sub-service/src/connectors/chariott_connector.rs b/pub-sub-service/src/connectors/chariott_connector.rs
index 015ae08..01606c0 100644
--- a/pub-sub-service/src/connectors/chariott_connector.rs
+++ b/pub-sub-service/src/connectors/chariott_connector.rs
@@ -13,8 +13,6 @@ use proto::{
service_registry::v1::{RegisterRequest, ServiceMetadata},
};
-use crate::load_config::get_uri;
-
type ChariottClient = ServiceRegistryClient;
/// Object that contains the necessary information for identifying a specific service.
@@ -39,10 +37,9 @@ pub async fn connect_to_chariott_with_retry(
) -> Result> {
let mut client_opt: Option = None;
let mut reason = String::new();
- let uri = get_uri(chariott_uri)?;
while client_opt.is_none() {
- client_opt = match ServiceRegistryClient::connect(uri.clone()).await {
+ client_opt = match ServiceRegistryClient::connect(chariott_uri.to_owned()).await {
Ok(client) => Some(client),
Err(e) => {
let status = Status::from_error(Box::new(e));
diff --git a/pub-sub-service/src/connectors/mosquitto_connector.rs b/pub-sub-service/src/connectors/mosquitto_connector.rs
index 5989164..228535b 100644
--- a/pub-sub-service/src/connectors/mosquitto_connector.rs
+++ b/pub-sub-service/src/connectors/mosquitto_connector.rs
@@ -14,10 +14,7 @@ use log::{error, info, warn};
use paho_mqtt::{self as mqtt, MQTT_VERSION_5};
use std::{process, sync::mpsc};
-use crate::{
- load_config::get_uri,
- pubsub_connector::{self, MonitorMessage, PubSubAction, PubSubConnector},
-};
+use crate::pubsub_connector::{self, MonitorMessage, PubSubAction, PubSubConnector};
/// Mosquitto broker's reserved topic for subscribe related notifications.
const SUBSCRIBE: &str = "$SYS/broker/log/M/subscribe";
@@ -39,13 +36,8 @@ impl MqttFiveBrokerConnector {
/// * `client_id` - Id used when creating a new mqtt client.
/// * `broker_uri` - The uri of the broker that the client is connecting to.
fn new(client_id: String, broker_uri: String) -> Self {
- let host = get_uri(&broker_uri).unwrap_or_else(|e| {
- error!("Error creating the client: {e:?}");
- process::exit(1);
- });
-
let create_opts = mqtt::CreateOptionsBuilder::new()
- .server_uri(host)
+ .server_uri(broker_uri)
.client_id(client_id)
.finalize();
diff --git a/pub-sub-service/src/load_config.rs b/pub-sub-service/src/load_config.rs
index 0544f7c..c1f1f80 100644
--- a/pub-sub-service/src/load_config.rs
+++ b/pub-sub-service/src/load_config.rs
@@ -13,28 +13,6 @@ use serde_derive::{Deserialize, Serialize};
const CONFIG_FILE_NAME: &str = "pub_sub_service_settings";
const CONSTANTS_FILE_NAME: &str = "constants";
-/// If feature 'containerize' is set, will modify a localhost uri to point to container's localhost
-/// DNS alias. Otherwise, returns the uri as a String.
-///
-/// # Arguments
-/// * `uri` - The uri to potentially modify.
-pub fn get_uri(uri: &str) -> Result> {
- #[cfg(feature = "containerize")]
- let uri = {
- // Container env variable names.
- const HOST_GATEWAY_ENV_VAR: &str = "HOST_GATEWAY";
- const LOCALHOST_ALIAS_ENV_VAR: &str = "LOCALHOST_ALIAS";
-
- // Return an error if container env variables are not set.
- let host_gateway = env::var(HOST_GATEWAY_ENV_VAR)?;
- let localhost_alias = env::var(LOCALHOST_ALIAS_ENV_VAR)?; // DevSkim: ignore DS162092
-
- uri.replace(&localhost_alias, &host_gateway) // DevSkim: ignore DS162092
- };
-
- Ok(uri.to_string())
-}
-
/// Object that contains constants used for establishing connection between services.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CommunicationConstants {
diff --git a/pub-sub-service/src/topic_manager.rs b/pub-sub-service/src/topic_manager.rs
index dfb2d9b..f3a8824 100644
--- a/pub-sub-service/src/topic_manager.rs
+++ b/pub-sub-service/src/topic_manager.rs
@@ -19,10 +19,7 @@ use proto::publisher::v1::{
};
use tonic::Request;
-use crate::{
- load_config::get_uri,
- pubsub_connector::{MonitorMessage, PubSubAction},
-};
+use crate::pubsub_connector::{MonitorMessage, PubSubAction};
/// Metadata relevant to a dynamic topic.
#[derive(Clone, Debug, PartialEq)]
@@ -297,7 +294,7 @@ impl TopicManager {
}
// Get information from publisher client
- let uri = get_uri(&action_metadata.uri)?;
+ let uri = action_metadata.uri.clone();
let mut pub_client = PublisherCallbackClient::connect(uri).await?;
let request = Request::new(ManageTopicRequest {
diff --git a/samples/README.md b/samples/README.md
index 8b1ebbb..beed2a9 100644
--- a/samples/README.md
+++ b/samples/README.md
@@ -162,3 +162,14 @@ until the Pub Sub Service registers.
All services will retry every 5 seconds when attempting connection to Chariott until the Chariott
service is up and running.
+
+## Running the samples in a Container
+
+Please refer to [containers.md](../docs/containers.md) for instructions on how to build and run the
+sample applications. All the samples use the same Dockerfile so the build arg `APP_NAME` will need
+to be set when building the sample application image. For the Chariott-enabled samples, one may
+need to override the configuration. Please see
+[Running in Docker with Overridden Configuration](../docs/containers.md#running-in-docker-with-overridden-configuration)
+and
+[Running in Podman with Overridden Configuration](../docs/containers.md#running-in-podman-with-overridden-configuration)
+for more information.
diff --git a/samples/connectors/mqtt-five/Cargo.toml b/samples/connectors/mqtt-five/Cargo.toml
index c66b859..243ded9 100644
--- a/samples/connectors/mqtt-five/Cargo.toml
+++ b/samples/connectors/mqtt-five/Cargo.toml
@@ -11,4 +11,7 @@ license = "MIT"
[dependencies]
async-trait = { workspace = true }
log = { workspace = true }
-paho-mqtt = { workspace = true }
\ No newline at end of file
+paho-mqtt = { workspace = true }
+
+[target.'cfg(target_arch = "aarch64")'.dependencies]
+paho-mqtt = { workspace = true, features = ["vendored-ssl"] }
From b420913f0c2494abbc41c38c3d37a9ca478ad4fa Mon Sep 17 00:00:00 2001
From: Devin Kelley <105753233+devkelley@users.noreply.github.com>
Date: Thu, 30 Nov 2023 12:21:35 -0800
Subject: [PATCH 2/7] Add arg_sanitizer script, update dockerfiles to use
script, move args to top of file, removed old comments
---
Dockerfile => Dockerfile.amd64 | 36 ++++++-----
Dockerfile.arm64 | 32 ++++++----
...le.mosquitto => Dockerfile.mosquitto.amd64 | 2 +-
Dockerfile.mosquitto.arm64 | 3 +-
...erfile.samples => Dockerfile.samples.amd64 | 32 ++++++----
Dockerfile.samples.arm64 | 32 ++++++----
container/scripts/argument_sanitizer.sh | 61 +++++++++++++++++++
.../scripts/container_startup.sh | 2 +-
docs/containers.md | 22 ++++---
9 files changed, 160 insertions(+), 62 deletions(-)
rename Dockerfile => Dockerfile.amd64 (82%)
rename Dockerfile.mosquitto => Dockerfile.mosquitto.amd64 (98%)
rename Dockerfile.samples => Dockerfile.samples.amd64 (82%)
create mode 100755 container/scripts/argument_sanitizer.sh
rename container_startup.sh => container/scripts/container_startup.sh (88%)
diff --git a/Dockerfile b/Dockerfile.amd64
similarity index 82%
rename from Dockerfile
rename to Dockerfile.amd64
index f616ee2..7700aa5 100644
--- a/Dockerfile
+++ b/Dockerfile.amd64
@@ -12,12 +12,21 @@
# Create a stage for building the application.
ARG RUST_VERSION=1.72.1
-FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
ARG APP_NAME=pub-sub-service
+ARG UID=10001
+
+FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
+ARG APP_NAME
WORKDIR /sdv
COPY ./ .
+# Check that APP_NAME argument is valid.
+RUN /sdv/container/scripts/argument_sanitizer.sh \
+ --arg-value "${APP_NAME}" \
+ --regex "^[a-zA-Z_0-9-]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
+
# Add Build dependencies.
RUN apt update && apt upgrade -y && apt install -y \
cmake \
@@ -25,14 +34,7 @@ RUN apt update && apt upgrade -y && apt install -y \
pkg-config \
protobuf-compiler
-# Check that APP_NAME argument is valid.
-RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
-[ "$sanitized" = "${APP_NAME}" ] || { \
- echo "ARG 'APP_NAME' is invalid. APP_NAME='${APP_NAME}' sanitized='${sanitized}'"; \
- exit 1; \
-}
-
-# Build the application with the 'containerize' feature.
+# Build the application.
RUN cargo build --release -p "${APP_NAME}"
# Copy the built application to working directory.
@@ -50,10 +52,19 @@ RUN cp ./target/release/"${APP_NAME}" /sdv/service
# reproducability is important, consider using a digest
# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
FROM docker.io/library/debian:bullseye-slim AS final
+ARG UID
+
+# Copy container scripts.
+COPY ./container/scripts/*.sh /sdv/scripts/
+
+# Check that UID argument is valid.
+RUN /sdv/scripts/argument_sanitizer.sh \
+ --arg-value "${UID}" \
+ --regex "^[0-9]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'UID'"; exit 1 )
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
-ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
@@ -79,9 +90,6 @@ ENV AGEMO_HOME=/sdv/.agemo
# Copy the executable from the "build" stage.
COPY --from=build /sdv/service /sdv/
-# Copy startup script.
-COPY --from=build /sdv/container_startup.sh /sdv/container_startup.sh
-
# Copy default configs.
COPY --from=build /sdv/.agemo/config/ /sdv/.agemo/config/
@@ -89,4 +97,4 @@ COPY --from=build /sdv/.agemo/config/ /sdv/.agemo/config/
EXPOSE 50051
# What the container should run when it is started.
-CMD ["/sdv/container_startup.sh"]
+CMD ["/sdv/scripts/container_startup.sh"]
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index 072721a..8843814 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -12,8 +12,11 @@
# Create a stage for building the application.
ARG RUST_VERSION=1.72.1
-FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
ARG APP_NAME=pub-sub-service
+ARG UID=10001
+
+FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
+ARG APP_NAME
WORKDIR /sdv
COPY ./ .
@@ -27,15 +30,14 @@ RUN apt update && apt upgrade -y && apt install -y \
gcc-aarch64-linux-gnu
# Check that APP_NAME argument is valid.
-RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
-[ "$sanitized" = "${APP_NAME}" ] || { \
- echo "ARG 'APP_NAME' is invalid. APP_NAME='${APP_NAME}' sanitized='${sanitized}'"; \
- exit 1; \
-}
+RUN /sdv/container/scripts/argument_sanitizer.sh \
+ --arg-value "${APP_NAME}" \
+ --regex "^[a-zA-Z_0-9-]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
RUN rustup target add aarch64-unknown-linux-gnu
-# Build the application with the 'containerize' feature.
+# Build the application.
RUN cargo build --release --target=aarch64-unknown-linux-gnu -p "${APP_NAME}"
# Copy the built application to working directory.
@@ -53,10 +55,19 @@ RUN cp ./target/aarch64-unknown-linux-gnu/release/"${APP_NAME}" /sdv/service
# reproducability is important, consider using a digest
# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
FROM docker.io/arm64v8/debian:bullseye-slim AS final
+ARG UID
+
+# Copy container scripts.
+COPY ./container/scripts/*.sh /sdv/scripts/
+
+# Check that UID argument is valid.
+RUN /sdv/scripts/argument_sanitizer.sh \
+ --arg-value "${UID}" \
+ --regex "^[0-9]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'UID'"; exit 1 )
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
-ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
@@ -82,9 +93,6 @@ ENV AGEMO_HOME=/sdv/.agemo
# Copy the executable from the "build" stage.
COPY --from=build /sdv/service /sdv/
-# Copy startup script.
-COPY --from=build /sdv/container_startup.sh /sdv/container_startup.sh
-
# Copy default configs.
COPY --from=build /sdv/.agemo/config/ /sdv/.agemo/config/
@@ -92,4 +100,4 @@ COPY --from=build /sdv/.agemo/config/ /sdv/.agemo/config/
EXPOSE 50051
# What the container should run when it is started.
-CMD ["/sdv/container_startup.sh"]
+CMD ["/sdv/scripts/container_startup.sh"]
diff --git a/Dockerfile.mosquitto b/Dockerfile.mosquitto.amd64
similarity index 98%
rename from Dockerfile.mosquitto
rename to Dockerfile.mosquitto.amd64
index 3905c3e..199d9a0 100644
--- a/Dockerfile.mosquitto
+++ b/Dockerfile.mosquitto.amd64
@@ -16,4 +16,4 @@ WORKDIR /mosquitto/config
COPY ./pub-sub-service/src/connectors/mosquitto.conf ./mosquitto.conf
-EXPOSE 1883
\ No newline at end of file
+EXPOSE 1883
diff --git a/Dockerfile.mosquitto.arm64 b/Dockerfile.mosquitto.arm64
index c55b9e5..4299f0b 100644
--- a/Dockerfile.mosquitto.arm64
+++ b/Dockerfile.mosquitto.arm64
@@ -16,4 +16,5 @@ WORKDIR /mosquitto/config
COPY ./pub-sub-service/src/connectors/mosquitto.conf ./mosquitto.conf
-EXPOSE 1883
\ No newline at end of file
+# Expose the port that the mqtt broker listens on.
+EXPOSE 1883
diff --git a/Dockerfile.samples b/Dockerfile.samples.amd64
similarity index 82%
rename from Dockerfile.samples
rename to Dockerfile.samples.amd64
index c2daa65..23b6749 100644
--- a/Dockerfile.samples
+++ b/Dockerfile.samples.amd64
@@ -12,8 +12,11 @@
# Create a stage for building the application.
ARG RUST_VERSION=1.72.1
-FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
ARG APP_NAME=simple-publisher
+ARG UID=10001
+
+FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
+ARG APP_NAME
WORKDIR /sdv
COPY ./ .
@@ -26,13 +29,12 @@ RUN apt update && apt upgrade -y && apt install -y \
protobuf-compiler
# Check that APP_NAME argument is valid.
-RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
-[ "$sanitized" = "${APP_NAME}" ] || { \
- echo "ARG 'APP_NAME' is invalid. APP_NAME='${APP_NAME}' sanitized='${sanitized}'"; \
- exit 1; \
-}
+RUN /sdv/container/scripts/argument_sanitizer.sh \
+ --arg-value "${APP_NAME}" \
+ --regex "^[a-zA-Z_0-9-]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
-# Build the application with the 'containerize' feature.
+# Build the application.
RUN cargo build --release -p "${APP_NAME}"
# Copy the built application to working directory.
@@ -50,10 +52,19 @@ RUN cp ./target/release/"${APP_NAME}" /sdv/service
# reproducability is important, consider using a digest
# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
FROM docker.io/library/debian:bullseye-slim AS final
+ARG UID
+
+# Copy container scripts.
+COPY ./container/scripts/*.sh /sdv/scripts/
+
+# Check that UID argument is valid.
+RUN /sdv/scripts/argument_sanitizer.sh \
+ --arg-value "${UID}" \
+ --regex "^[0-9]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'UID'"; exit 1 )
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
-ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
@@ -79,11 +90,8 @@ ENV AGEMO_SAMPLES_HOME=/sdv/.agemo
# Copy the executable from the "build" stage.
COPY --from=build /sdv/service /sdv/
-# Copy startup script.
-COPY --from=build /sdv/container_startup.sh /sdv/container_startup.sh
-
# Copy default configs.
COPY --from=build /sdv/.agemo-samples/config/ /sdv/.agemo/config/
# What the container should run when it is started.
-CMD ["/sdv/container_startup.sh"]
+CMD ["/sdv/scripts/container_startup.sh"]
diff --git a/Dockerfile.samples.arm64 b/Dockerfile.samples.arm64
index 3f412f5..2d7544a 100644
--- a/Dockerfile.samples.arm64
+++ b/Dockerfile.samples.arm64
@@ -12,8 +12,11 @@
# Create a stage for building the application.
ARG RUST_VERSION=1.72.1
-FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
ARG APP_NAME=simple-publisher
+ARG UID=10001
+
+FROM docker.io/library/rust:${RUST_VERSION}-slim-bullseye AS build
+ARG APP_NAME
WORKDIR /sdv
COPY ./ .
@@ -27,15 +30,14 @@ RUN apt update && apt upgrade -y && apt install -y \
gcc-aarch64-linux-gnu
# Check that APP_NAME argument is valid.
-RUN sanitized=$(echo "${APP_NAME}" | tr -dc '^[a-zA-Z_0-9-]+$'); \
-[ "$sanitized" = "${APP_NAME}" ] || { \
- echo "ARG 'APP_NAME' is invalid. APP_NAME='${APP_NAME}' sanitized='${sanitized}'"; \
- exit 1; \
-}
+RUN /sdv/container/scripts/argument_sanitizer.sh \
+ --arg-value "${APP_NAME}" \
+ --regex "^[a-zA-Z_0-9-]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
RUN rustup target add aarch64-unknown-linux-gnu
-# Build the application with the 'containerize' feature.
+# Build the application.
RUN cargo build --release --target=aarch64-unknown-linux-gnu -p "${APP_NAME}"
# Copy the built application to working directory.
@@ -53,10 +55,19 @@ RUN cp ./target/aarch64-unknown-linux-gnu/release/"${APP_NAME}" /sdv/service
# reproducability is important, consider using a digest
# (e.g., debian@sha256:ac707220fbd7b67fc19b112cee8170b41a9e97f703f588b2cdbbcdcecdd8af57).
FROM docker.io/arm64v8/debian:bullseye-slim AS final
+ARG UID
+
+# Copy container scripts.
+COPY ./container/scripts/*.sh /sdv/scripts/
+
+# Check that UID argument is valid.
+RUN /sdv/scripts/argument_sanitizer.sh \
+ --arg-value "${UID}" \
+ --regex "^[0-9]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'UID'"; exit 1 )
# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user
-ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
@@ -82,11 +93,8 @@ ENV AGEMO_SAMPLES_HOME=/sdv/.agemo
# Copy the executable from the "build" stage.
COPY --from=build /sdv/service /sdv/
-# Copy startup script.
-COPY --from=build /sdv/container_startup.sh /sdv/container_startup.sh
-
# Copy default configs.
COPY --from=build /sdv/.agemo-samples/config/ /sdv/.agemo/config/
# What the container should run when it is started.
-CMD ["/sdv/container_startup.sh"]
+CMD ["/sdv/scripts/container_startup.sh"]
diff --git a/container/scripts/argument_sanitizer.sh b/container/scripts/argument_sanitizer.sh
new file mode 100755
index 0000000..48ace77
--- /dev/null
+++ b/container/scripts/argument_sanitizer.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT license.
+# SPDX-License-Identifier: MIT
+
+# Exits immediately on failure.
+set -e
+
+# Function to display usage information
+usage() {
+ echo "Usage: $0 [-a|--arg-value] [-r|--regex] "
+ echo "Example:"
+ echo " $0 -a \"\${APP_NAME}\" -r \"^[a-zA-Z_0-9-]+$\""
+}
+
+# Parse command line arguments
+while [[ $# -gt 0 ]]
+do
+ key="$1"
+
+ case $key in
+ -a|--arg-value)
+ arg_value="$2"
+ shift # past argument
+ shift # past value
+ ;;
+ -r|--regex)
+ regex="$2"
+ shift # past argument
+ shift # past value
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ *)
+ echo "Unknown argument: $key"
+ usage
+ exit 1
+ esac
+done
+
+# Check if all required arguments have been set
+if [[ -z "${arg_value}" || -z "${regex}" ]]; then
+ echo "Error: Missing required arguments:"
+ [[ -z "${arg_value}" ]] && echo " -a|--arg-value"
+ [[ -z "${regex}" ]] && echo " -r|--regex"
+ echo -e "\n"
+ usage
+ exit 1
+fi
+
+sanitized=$(echo "${arg_value}" | tr -dc "${regex}");
+[ "$sanitized" = "${arg_value}" ] || {
+ echo "ARG is invalid. ARG='${arg_value}' sanitized='${sanitized}'";
+ exit 1
+}
+
+echo -e "\nARG with value '${arg_value}' is sanitized"
+exit 0
diff --git a/container_startup.sh b/container/scripts/container_startup.sh
similarity index 88%
rename from container_startup.sh
rename to container/scripts/container_startup.sh
index 73be244..48d508e 100755
--- a/container_startup.sh
+++ b/container/scripts/container_startup.sh
@@ -8,6 +8,6 @@
set -e
# Copy any configuration files present to service configuration.
-cp -rn /mnt/config /sdv/.agemo
+cp -rf /mnt/config /sdv/.agemo
/sdv/service
diff --git a/docs/containers.md b/docs/containers.md
index 8f7c231..8c5139e 100644
--- a/docs/containers.md
+++ b/docs/containers.md
@@ -1,12 +1,16 @@
## Containers
-### Dockerfiles
+This repository provides several Dockerfiles to enable building of OCI container images. This
+document has instructions for building and running the provided Dockerfiles in
+[Docker](#docker-containers) and [Podman](#podman-containers). Refer to the
+[Dockerfiles](#dockerfiles) section to select the appropriate Dockerfile.
-This repository currently provides the following Dockerfiles:
+### Dockerfiles
#### Pub Sub Service
-- [Dockerfile](../Dockerfile) - Dockerfile used to build the `Pub Sub Service`.
+- [Dockerfile.amd64](../Dockerfile.amd64) - Dockerfile used to build the `Pub Sub Service` for the
+x86-64 architecture.
- [Dockerfile.arm64](../Dockerfile.arm64) - Dockerfile used to build the `Pub Sub Service` for the
aarch64 architecture.
@@ -15,15 +19,15 @@ in the project's root.
#### Mosquitto MQTT Broker
-- [Dockerfile.mosquitto](../Dockerfile.mosquitto) - Dockerfile used to build the
-`Mosquitto MQTT Broker` with the appropriate configuration.
+- [Dockerfile.mosquitto.amd64](../Dockerfile.mosquitto.amd64) - Dockerfile used to build the
+`Mosquitto MQTT Broker` with the appropriate configuration for the x86-64 architecture.
- [Dockerfile.mosquitto.arm64](../Dockerfile.mosquitto.arm64) - Dockerfile used to build the
`Mosquitto MQTT Broker` with the appropriate configuration for the aarch64 architecture.
#### Sample Applications
-- [Dockerfile.samples](../Dockerfile.samples) - Dockerfile used to build one of the sample
-applications.
+- [Dockerfile.samples.amd64](../Dockerfile.samples.amd64) - Dockerfile used to build one of the
+sample applications for the x86-64 architecture.
- [Dockerfile.samples.arm64](../Dockerfile.samples.arm64) - Dockerfile used to build one of the
sample applications for the aarch64 architecture.
@@ -50,7 +54,7 @@ Dockerfile:
For example, to build an image for the `pub-sub-service` project:
```shell
- docker build -t pub_sub_service -f Dockerfile .
+ docker build -t pub_sub_service -f Dockerfile.amd64 .
```
Or to build an image for the `chariott-publisher` sample for aarch64:
@@ -136,7 +140,7 @@ Dockerfile:
For example, to build an image for the `pub-sub-service` project:
```shell
- podman build -t pub_sub_service -f Dockerfile .
+ podman build -t pub_sub_service -f Dockerfile.amd64 .
```
Or to build an image for the `chariott-publisher` sample for aarch64:
From 272611d0ba2e77c8bf36a63ddc2396af8e59589a Mon Sep 17 00:00:00 2001
From: Devin Kelley <105753233+devkelley@users.noreply.github.com>
Date: Thu, 30 Nov 2023 12:25:34 -0800
Subject: [PATCH 3/7] rearranged sanitizer args
---
Dockerfile.arm64 | 12 ++++++------
Dockerfile.mosquitto.amd64 | 1 +
Dockerfile.samples.amd64 | 12 ++++++------
Dockerfile.samples.arm64 | 12 ++++++------
4 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/Dockerfile.arm64 b/Dockerfile.arm64
index 8843814..b28e72a 100644
--- a/Dockerfile.arm64
+++ b/Dockerfile.arm64
@@ -21,6 +21,12 @@ WORKDIR /sdv
COPY ./ .
+# Check that APP_NAME argument is valid.
+RUN /sdv/container/scripts/argument_sanitizer.sh \
+ --arg-value "${APP_NAME}" \
+ --regex "^[a-zA-Z_0-9-]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
+
# Add Build dependencies.
RUN apt update && apt upgrade -y && apt install -y \
cmake \
@@ -29,12 +35,6 @@ RUN apt update && apt upgrade -y && apt install -y \
protobuf-compiler \
gcc-aarch64-linux-gnu
-# Check that APP_NAME argument is valid.
-RUN /sdv/container/scripts/argument_sanitizer.sh \
- --arg-value "${APP_NAME}" \
- --regex "^[a-zA-Z_0-9-]+$" || \
- ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
-
RUN rustup target add aarch64-unknown-linux-gnu
# Build the application.
diff --git a/Dockerfile.mosquitto.amd64 b/Dockerfile.mosquitto.amd64
index 199d9a0..4eeddea 100644
--- a/Dockerfile.mosquitto.amd64
+++ b/Dockerfile.mosquitto.amd64
@@ -16,4 +16,5 @@ WORKDIR /mosquitto/config
COPY ./pub-sub-service/src/connectors/mosquitto.conf ./mosquitto.conf
+# Expose the port that the mqtt broker listens on.
EXPOSE 1883
diff --git a/Dockerfile.samples.amd64 b/Dockerfile.samples.amd64
index 23b6749..b625b54 100644
--- a/Dockerfile.samples.amd64
+++ b/Dockerfile.samples.amd64
@@ -21,6 +21,12 @@ WORKDIR /sdv
COPY ./ .
+# Check that APP_NAME argument is valid.
+RUN /sdv/container/scripts/argument_sanitizer.sh \
+ --arg-value "${APP_NAME}" \
+ --regex "^[a-zA-Z_0-9-]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
+
# Add Build dependencies.
RUN apt update && apt upgrade -y && apt install -y \
cmake \
@@ -28,12 +34,6 @@ RUN apt update && apt upgrade -y && apt install -y \
pkg-config \
protobuf-compiler
-# Check that APP_NAME argument is valid.
-RUN /sdv/container/scripts/argument_sanitizer.sh \
- --arg-value "${APP_NAME}" \
- --regex "^[a-zA-Z_0-9-]+$" || \
- ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
-
# Build the application.
RUN cargo build --release -p "${APP_NAME}"
diff --git a/Dockerfile.samples.arm64 b/Dockerfile.samples.arm64
index 2d7544a..c2e7637 100644
--- a/Dockerfile.samples.arm64
+++ b/Dockerfile.samples.arm64
@@ -21,6 +21,12 @@ WORKDIR /sdv
COPY ./ .
+# Check that APP_NAME argument is valid.
+RUN /sdv/container/scripts/argument_sanitizer.sh \
+ --arg-value "${APP_NAME}" \
+ --regex "^[a-zA-Z_0-9-]+$" || \
+ ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
+
# Add Build dependencies.
RUN apt update && apt upgrade -y && apt install -y \
cmake \
@@ -29,12 +35,6 @@ RUN apt update && apt upgrade -y && apt install -y \
protobuf-compiler \
gcc-aarch64-linux-gnu
-# Check that APP_NAME argument is valid.
-RUN /sdv/container/scripts/argument_sanitizer.sh \
- --arg-value "${APP_NAME}" \
- --regex "^[a-zA-Z_0-9-]+$" || \
- ( echo "Argument sanitizer failed for ARG 'APP_NAME'"; exit 1 )
-
RUN rustup target add aarch64-unknown-linux-gnu
# Build the application.
From ffa04f09edac15ad935cd58bdfc9ac9c0f1e614d Mon Sep 17 00:00:00 2001
From: Devin Kelley <105753233+devkelley@users.noreply.github.com>
Date: Fri, 1 Dec 2023 14:35:53 -0800
Subject: [PATCH 4/7] Add -u to scripts
---
container/scripts/argument_sanitizer.sh | 2 +-
container/scripts/container_startup.sh | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/container/scripts/argument_sanitizer.sh b/container/scripts/argument_sanitizer.sh
index 48ace77..d6ed4da 100755
--- a/container/scripts/argument_sanitizer.sh
+++ b/container/scripts/argument_sanitizer.sh
@@ -5,7 +5,7 @@
# SPDX-License-Identifier: MIT
# Exits immediately on failure.
-set -e
+set -eu
# Function to display usage information
usage() {
diff --git a/container/scripts/container_startup.sh b/container/scripts/container_startup.sh
index 48d508e..0005e4d 100755
--- a/container/scripts/container_startup.sh
+++ b/container/scripts/container_startup.sh
@@ -5,7 +5,7 @@
# SPDX-License-Identifier: MIT
# Exits immediately on failure.
-set -e
+set -eu
# Copy any configuration files present to service configuration.
cp -rf /mnt/config /sdv/.agemo
From b36a32cfb762667b3c9fe797151335482b76d193 Mon Sep 17 00:00:00 2001
From: Devin Kelley <105753233+devkelley@users.noreply.github.com>
Date: Fri, 1 Dec 2023 15:43:31 -0800
Subject: [PATCH 5/7] Add comment to cp command
---
container/scripts/container_startup.sh | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/container/scripts/container_startup.sh b/container/scripts/container_startup.sh
index 0005e4d..03cfaa4 100755
--- a/container/scripts/container_startup.sh
+++ b/container/scripts/container_startup.sh
@@ -7,7 +7,9 @@
# Exits immediately on failure.
set -eu
-# Copy any configuration files present to service configuration.
+# Copy any mounted configuration files present to service configuration at runtime.
+# If there is a configuration file with the same name at `/sdv/.agemo/config` this will overwrite
+# the file with the mounted configuration file.
cp -rf /mnt/config /sdv/.agemo
/sdv/service
From a4def3924a7a4d57ea7477a8c0138f39e157b887 Mon Sep 17 00:00:00 2001
From: Devin Kelley <105753233+devkelley@users.noreply.github.com>
Date: Fri, 1 Dec 2023 15:44:11 -0800
Subject: [PATCH 6/7] reword
---
container/scripts/container_startup.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/container/scripts/container_startup.sh b/container/scripts/container_startup.sh
index 03cfaa4..517f3e9 100755
--- a/container/scripts/container_startup.sh
+++ b/container/scripts/container_startup.sh
@@ -9,7 +9,7 @@ set -eu
# Copy any mounted configuration files present to service configuration at runtime.
# If there is a configuration file with the same name at `/sdv/.agemo/config` this will overwrite
-# the file with the mounted configuration file.
+# that file with the mounted configuration file.
cp -rf /mnt/config /sdv/.agemo
/sdv/service
From 2f4d9e5a2e10ca5183081c1210a321a05b38d56c Mon Sep 17 00:00:00 2001
From: Devin Kelley <105753233+devkelley@users.noreply.github.com>
Date: Fri, 1 Dec 2023 15:49:17 -0800
Subject: [PATCH 7/7] fix whitespace
---
container/scripts/container_startup.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/container/scripts/container_startup.sh b/container/scripts/container_startup.sh
index 517f3e9..e3abc43 100755
--- a/container/scripts/container_startup.sh
+++ b/container/scripts/container_startup.sh
@@ -9,7 +9,7 @@ set -eu
# Copy any mounted configuration files present to service configuration at runtime.
# If there is a configuration file with the same name at `/sdv/.agemo/config` this will overwrite
-# that file with the mounted configuration file.
+# that file with the mounted configuration file.
cp -rf /mnt/config /sdv/.agemo
/sdv/service