diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..c3b54de --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" +rustflags = [ "-C", "target-feature=+crt-static", "-C", "link-arg=-lgcc" ] diff --git a/.github/workflows/dotnet-ci.yml b/.github/workflows/dotnet-ci.yml index 9fe1dbf..fb99c57 100644 --- a/.github/workflows/dotnet-ci.yml +++ b/.github/workflows/dotnet-ci.yml @@ -9,7 +9,7 @@ on: - main env: - DOTNET_VERSION: 6.0.119 + DOTNET_VERSION: 6.0.x jobs: static_code_analysis: @@ -21,7 +21,6 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ env.DOTNET_VERSION }} - global-json-file: cloud_connectors/azure/digital_twins_connector/global.json - name: Cache NuGet dependencies uses: actions/cache@v3 with: diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 6a2e59e..3b4866e 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -38,11 +38,10 @@ jobs: uses: actions/checkout@v3 with: submodules: recursive - - name: Install .NET 6.0.119 + - name: Install .NET 6.0.x uses: actions/setup-dotnet@v3 with: - dotnet-version: 6.0.119 - global-json-file: cloud_connectors/azure/digital_twins_connector/global.json + dotnet-version: '6.0.x' - name: Cache NuGet dependencies uses: actions/cache@v3 with: diff --git a/Cargo.lock b/Cargo.lock index 3e68b81..d2b5ab4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -607,6 +607,7 @@ dependencies = [ "freyja", "ibeji-adapter", "in-memory-mock-mapping-client", + "paho-mqtt", "tokio", ] @@ -618,6 +619,7 @@ dependencies = [ "ibeji-adapter", "in-memory-mock-cloud-adapter", "in-memory-mock-mapping-client", + "paho-mqtt", "tokio", ] @@ -1305,6 +1307,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[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" @@ -1313,6 +1324,7 @@ checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] diff --git a/Dockerfile.freyja_apps b/Dockerfile.freyja_apps.amd64 similarity index 73% rename from Dockerfile.freyja_apps rename to Dockerfile.freyja_apps.amd64 index e70c8c8..290964a 100644 --- a/Dockerfile.freyja_apps +++ b/Dockerfile.freyja_apps.amd64 @@ -10,27 +10,30 @@ # 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=freyja-in-memory-app +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 \ 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}" --features containerize +# Build the application. +RUN cargo build --release -p "${APP_NAME}" # Copy the built application to working directory. RUN cp ./target/release/"${APP_NAME}" /sdv/service @@ -47,10 +50,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 "" \ @@ -59,6 +71,14 @@ RUN adduser \ --no-create-home \ --uid "${UID}" \ appuser + +# Create and add user ownership to config directory. +RUN mkdir -p /sdv/.freyja/config +RUN chown appuser /sdv/.freyja/config + +# Create mnt directory to copy override configs into. +RUN mkdir -p /mnt/config + USER appuser WORKDIR /sdv @@ -70,4 +90,4 @@ COPY --from=build /sdv/target/release/build/ /sdv/target/release/build/ ENV FREYJA_HOME=/sdv/.freyja # What the container should run when it is started. -CMD ["/sdv/service"] +CMD ["/sdv/scripts/container_startup.sh"] diff --git a/Dockerfile.freyja_apps.arm64 b/Dockerfile.freyja_apps.arm64 new file mode 100644 index 0000000..0aea351 --- /dev/null +++ b/Dockerfile.freyja_apps.arm64 @@ -0,0 +1,96 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. +# SPDX-License-Identifier: MIT + +# 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 +ARG APP_NAME=freyja-in-memory-app +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 \ + libssl-dev \ + pkg-config \ + protobuf-compiler \ + gcc-aarch64-linux-gnu + +RUN rustup target add aarch64-unknown-linux-gnu + +# Build the application. +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 +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 +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/.freyja/config +RUN chown appuser /sdv/.freyja/config + +# Create mnt directory to copy override configs into. +RUN mkdir -p /mnt/config + +USER appuser + +WORKDIR /sdv + +# Copy the executable from the "build" stage. +COPY --from=build /sdv/service /sdv/ +COPY --from=build /sdv/target/aarch64-unknown-linux-gnu/release/build/ /sdv/target/aarch64-unknown-linux-gnu/release/build/ + +ENV FREYJA_HOME=/sdv/.freyja + +# What the container should run when it is started. +CMD ["/sdv/scripts/container_startup.sh"] diff --git a/README.md b/README.md index 30996df..64d5b8f 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,11 @@ The Freyja examples include: - [Example Freyja Apps](./freyja_apps/): These are examples of how to write a Freyja application using its plugin model. Each example has a README describing its usage, and the `template` app can be used to get started with your own adapters. - [Example Freyja Adapters](./freyja_adapters/): These are examples of adapters that can be used with Freyja. Each adapter has a README describing its usage. - [Example Cloud Connectors](./cloud_connectors/): These are examples of cloud connectors that Freyja can interface with through the `CloudAdapter` trait. These serve as examples of how to integrate with specific cloud solutions. + +### Supported Ibeji Samples + +This repository provides freyja configuration overrides in the [`.freyja`](.freyja/) directory that support the following Ibeji samples: + +- [managed subscribe](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/managed_subscribe) +- [mixed](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/mixed) +- [property](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/property) diff --git a/cloud_connectors/azure/Dockerfile.dt_connector.amd64 b/cloud_connectors/azure/Dockerfile.dt_connector.amd64 new file mode 100644 index 0000000..3d79278 --- /dev/null +++ b/cloud_connectors/azure/Dockerfile.dt_connector.amd64 @@ -0,0 +1,27 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env +WORKDIR /App + +# Copy everything +COPY ./ . +WORKDIR /App/digital_twins_connector/src/core/ +# Restore as distinct layers +RUN dotnet restore +# Build and publish a release +RUN dotnet publish -c Release -o out +RUN cp -rn ./out /App/out + +# Build runtime image +FROM docker.io/library/ubuntu:22.04 AS final + +# Install dotnet and az cli +RUN apt update -y && apt install -y dotnet-sdk-6.0 curl +RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash + +WORKDIR /sdv + +COPY --from=build-env /App/out . +COPY --from=build-env /App/container/scripts/container_startup.sh /sdv/scripts/container_startup.sh + +ENV ASPNETCORE_URLS "http://0.0.0.0:5176" + +CMD ["/sdv/scripts/container_startup.sh"] diff --git a/cloud_connectors/azure/Dockerfile.dt_connector.arm64 b/cloud_connectors/azure/Dockerfile.dt_connector.arm64 new file mode 100644 index 0000000..9257d45 --- /dev/null +++ b/cloud_connectors/azure/Dockerfile.dt_connector.arm64 @@ -0,0 +1,27 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build-env +WORKDIR /App + +# Copy everything +COPY ./ . +WORKDIR /App/digital_twins_connector/src/core/ +# Restore as distinct layers +RUN dotnet restore +# Build and publish a release +RUN dotnet publish -c Release -o out +RUN cp -rn ./out /App/out + +# Build runtime image +FROM docker.io/arm64v8/ubuntu:22.04 AS final + +# Install dotnet and az cli +RUN apt update -y && apt install -y dotnet-sdk-6.0 curl +RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash + +WORKDIR /sdv + +COPY --from=build-env /App/out . +COPY --from=build-env /App/container/scripts/container_startup.sh /sdv/scripts/container_startup.sh + +ENV ASPNETCORE_URLS "http://0.0.0.0:5176" + +CMD ["/sdv/scripts/container_startup.sh"] diff --git a/cloud_connectors/azure/container/scripts/container_startup.sh b/cloud_connectors/azure/container/scripts/container_startup.sh new file mode 100755 index 0000000..c39a7b8 --- /dev/null +++ b/cloud_connectors/azure/container/scripts/container_startup.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. +# SPDX-License-Identifier: MIT + +# Exits immediately on failure. +set -eu + +# Copy any configuration files present to service configuration. +cp -rf /mnt/config /sdv/ + +# Acquire access token scoped to the Azure Digital Twin Service. +az login --use-device-code --scope https://digitaltwins.azure.net/.default + +# Set azure subscription only if SUBSCRIPTION_ID is set. +if [ -n "$SUBSCRIPTION_ID" ]; then + az account set --subscription "$SUBSCRIPTION_ID" +fi + +# Start the Digital Twin Connector service. +dotnet ./DigitalTwinsConnector.dll \ No newline at end of file diff --git a/cloud_connectors/azure/digital_twins_connector/README.md b/cloud_connectors/azure/digital_twins_connector/README.md index 08479f5..12ca0bc 100644 --- a/cloud_connectors/azure/digital_twins_connector/README.md +++ b/cloud_connectors/azure/digital_twins_connector/README.md @@ -114,3 +114,12 @@ The first gRPC client call to the Digital Twins Connector's gRPC server could be ```shell dotnet run --project src/core/ ``` + +## Containerize the Azure Digital Twins Cloud Connector Application + +To build and run the application in a container, follow the steps under +[Docker Containers](../../../container/README.md#docker-containers) or +[Podman Containers](../../../container/README.md#podman-containers). + +Set `CONFIG_HOME` to point to the directory containing the `adt_instance_config.json` file modified +in step 4 of [Manual Azure Digital Twins Setup](#manual-azure-digital-twins-setup). diff --git a/cloud_connectors/azure/digital_twins_connector/global.json b/cloud_connectors/azure/digital_twins_connector/global.json deleted file mode 100644 index 08c8396..0000000 --- a/cloud_connectors/azure/digital_twins_connector/global.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sdk": { - "version": "6.0.119" - } -} \ No newline at end of file diff --git a/cloud_connectors/azure/digital_twins_connector/src/core/Program.cs b/cloud_connectors/azure/digital_twins_connector/src/core/Program.cs index aabd46e..f01e15c 100644 --- a/cloud_connectors/azure/digital_twins_connector/src/core/Program.cs +++ b/cloud_connectors/azure/digital_twins_connector/src/core/Program.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. // SPDX-License-Identifier: MIT +using System.Reflection; using System.Text.Json; using Azure.DigitalTwins.Core; @@ -20,8 +21,8 @@ class Program { static void Main(string[] args) { - const string AZURE_DIGITAL_TWINS_INSTANCE_CONFIG_PATH = @"bin/Debug/net6.0/config/adt_instance_config.json"; - string contents = File.ReadAllText(AZURE_DIGITAL_TWINS_INSTANCE_CONFIG_PATH); + string azure_digital_twins_config_path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"config/adt_instance_config.json"); + string contents = File.ReadAllText(azure_digital_twins_config_path); AzureDigitalTwinsInstanceConfig adtInstanceConfig = JsonSerializer.Deserialize(contents); // Configure the builder diff --git a/container/README.md b/container/README.md index 4c42e89..5eec059 100644 --- a/container/README.md +++ b/container/README.md @@ -1,4 +1,4 @@ -# Container Examples +# Containers This document describes how to utilize the provided Dockerfiles for containerization. @@ -6,25 +6,236 @@ This document describes how to utilize the provided Dockerfiles for containeriza ### Freyja Apps -To containerize the [Example Freyja Apps](../freyja_apps/), use -[Dockerfile.freyja_apps](../Dockerfile.freyja_apps). This dockerfile defaults to the +To containerize the [Example Freyja Apps](../freyja_apps/) use one of the following dockerfiles: + +- [Dockerfile.freyja_apps.amd64](../Dockerfile.freyja_apps.amd64) - For x86-64 architecture. +- [Dockerfile.freyja_apps.arm64](../Dockerfile.freyja_apps.arm64) - For aarch64 architecture. + +These dockerfiles default to the [In Memory Example Application](../freyja_apps/in_memory/). -Currently the following example applications can be containerized: +Currently the following example applications are supported: -- [In Memory Example Application](../freyja_apps/in_memory/) -- [Ibeji Adapter Example Application](../freyja_apps/ibeji_adapter) +- [In Memory Example Application](../freyja_apps/in_memory/README.md) +- [Ibeji Adapter Example Application](../freyja_apps/ibeji_adapter/README.md) +- [End to End Example Application](../freyja_apps/e2e/README.md) -Each supported application has a README describing the steps to containerize the application. +See [Docker Containers](#docker-containers) or [Podman Containers](#podman-containers) for +information on how to build and run supported applications in a container. ### Freyja Cloud Connectors -Coming soon! +To containerize the +[Azure Digitals Twin Cloud Connector](../cloud_connectors/azure/digital_twins_connector/README.md) +use one of the following dockerfiles: + +- [cloud_connectors/azure/Dockerfile.dt_connector.amd64](../cloud_connectors/azure/Dockerfile.dt_connector.amd64) - +For x86-64 architecture. +- [cloud_connectors/azure/Dockerfile.dt_connector.arm64](../cloud_connectors/azure/Dockerfile.dt_connector.arm64) - +For aarch64 architecture. + +See [Docker Containers](#docker-containers) or [Podman Containers](#podman-containers) for +information on how to build and run supported applications in a container. + +## Configuration Overrides + +This repository provides overrides for the samples listed under +[Supported Ibeji Samples](../README.md#supported-ibeji-samples). Configuration is provided in the +[`.freyja`](../.freyja/) directory, with each sample having its own directory. For example, the +configuration for the +[Ibeji mixed sample](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/mixed) is provided +under the [.freyja/mixed_sample](../.freyja/mixed_sample/) directory. + +## Docker Containers + +### Prequisites + +[Install Docker](https://docs.docker.com/engine/install/) + +### Running in Docker + +To run the service in a Docker container: + +>Note: Before running any of the following commands, replace all placeholders (wrapped with `<>`). + +1. Run the following command in the project root directory to build the docker container from the +Dockerfile: + + ```shell + docker build -t -f [--build-arg=APP_NAME=] . + ``` + + For example, to build an image for the `ibeji-adapter` project: + + ```shell + docker build -t ibeji_adapter -f Dockerfile.freyja_apps.amd64 --build-arg APP_NAME=freyja-ibeji-adapter-app . + ``` + + Or to build an image for the `azure digital twins cloud connector` example for aarch64: + + ```shell + docker build -t azure_dt_connector -f ./cloud_connectors/azure/Dockerfile.dt_connector.arm64 . + ``` + + >Note: The build arg `APP_NAME` needs to be passed in for all example freyja applications to + build the correct example. + +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 `ibeji_adapter` image built in step 1: + + ```shell + docker run --name ibeji_adapter --network=host -it --rm ibeji_adapter + ``` + + >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 `ibeji_adapter` container started in step 2: + + ```shell + docker stop ibeji_adapter + ``` + +### 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} + ``` + + For example, to set the configuration for the + [Ibeji mixed sample](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/mixed), run: + + ```shell + export CONFIG_HOME={path-to-repo-root}/.freyja/mixed_sample/config/ + ``` + + >Note: See [Configuration Overrides](#configuration-overrides) for information on how to find + the provided configuration for the + [Supported Ibeji Samples](../README.md#supported-ibeji-samples). + +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 `ibeji_adapter` image with overridden configuration: + + ```shell + docker run -v ${CONFIG_HOME}:/mnt/config --name ibeji_adapter --network=host -it --rm ibeji_adapter + ``` + +## Podman Containers + +### Prequisites + +[Install Podman](https://podman.io/docs/installation) + +### Running in Podman + +To run the service in a Podman container: + +>Note: Before running any of the following commands, replace all placeholders (wrapped with `<>`). + +1. Run the following command in the project root directory to build the podman container from the +Dockerfile: + + ```shell + podman build -t -f [--build-arg=APP_NAME=] . + ``` + + For example, to build an image for the `ibeji-adapter` project: + + ```shell + podman build -t ibeji_adapter -f Dockerfile.freyja_apps.amd64 --build-arg APP_NAME=freyja-ibeji-adapter-app . + ``` + + Or to build an image for the `azure digital twins cloud connector` example for aarch64: + + ```shell + podman build -t azure_dt_connector -f ./cloud_connectors/azure/Dockerfile.dt_connector.arm64 . + ``` + + >Note: The build arg `APP_NAME` needs to be passed in for all example freyja applications to + build the correct example. + +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 `ibeji_adapter` image built in step 1: + + ```shell + podman run --network=host ibeji_adapter + ``` + + >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 `ibeji_adapter` container started in step 2: + + ```shell + podman ps -f ancestor=localhost/ibeji_adapter: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} + ``` + + For example, to set the configuration for the + [Ibeji mixed sample](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/mixed), run: + + ```shell + export CONFIG_HOME={path-to-repo-root}/.freyja/mixed_sample/config/ + ``` + + >Note: See [Configuration Overrides](#configuration-overrides) for information on how to find + the provided configuration for the + [Supported Ibeji Samples](../README.md#supported-ibeji-samples). + +1. Then run the container with the following command: -### Env Files + ```shell + podman run --mount=type=bind,src=${CONFIG_HOME},dst=/mnt/config,ro=true --network=host + ``` -To run an application in Docker, ensure that the [docker.env](./config/docker.env) is passed in -when running the container. + For example, to run the `ibeji_adapter` image with overridden configuration: -To run an application in Podman, ensure that the [podman.env](./config/podman.env) is passed in -when running the container. + ```shell + podman run --mount=type=bind,src=${CONFIG_HOME},dst=/mnt/config,ro=true --network=host ibeji_adapter + ``` diff --git a/container/config/docker.env b/container/config/docker.env deleted file mode 100644 index 56bafc6..0000000 --- a/container/config/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/config/podman.env b/container/config/podman.env deleted file mode 100644 index 1abc4a3..0000000 --- a/container/config/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/container/scripts/argument_sanitizer.sh b/container/scripts/argument_sanitizer.sh new file mode 100755 index 0000000..d31613d --- /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 -eu + +# 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 \ No newline at end of file diff --git a/container/scripts/container_startup.sh b/container/scripts/container_startup.sh new file mode 100755 index 0000000..034dc93 --- /dev/null +++ b/container/scripts/container_startup.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT license. +# SPDX-License-Identifier: MIT + +# Exits immediately on failure. +set -eu + +# Copy any configuration files present to service configuration. +# If there is a configuration file with the same name at `/sdv/.freyja/config` this will overwrite +# that file with the mounted configuration file. +cp -rf /mnt/config /sdv/.freyja + +# Start the Freyja service. +/sdv/service \ No newline at end of file diff --git a/freyja_adapters/cloud/azure_cloud_connector_adapter/res/azure_cloud_connector_adapter_config.default.json b/freyja_adapters/cloud/azure_cloud_connector_adapter/res/azure_cloud_connector_adapter_config.default.json index f56dc84..381a41d 100644 --- a/freyja_adapters/cloud/azure_cloud_connector_adapter/res/azure_cloud_connector_adapter_config.default.json +++ b/freyja_adapters/cloud/azure_cloud_connector_adapter/res/azure_cloud_connector_adapter_config.default.json @@ -1,5 +1,5 @@ { - "cloud_connector_uri": "http://[::1]:8890", - "max_retries": 5, - "retry_interval_ms": 1000 + "cloud_connector_uri": "http://0.0.0.0:5176", + "max_retries": 20, + "retry_interval_ms": 10000 } \ No newline at end of file diff --git a/freyja_adapters/digital_twin/ibeji_adapter/Cargo.toml b/freyja_adapters/digital_twin/ibeji_adapter/Cargo.toml index 8878c9b..34daeed 100644 --- a/freyja_adapters/digital_twin/ibeji_adapter/Cargo.toml +++ b/freyja_adapters/digital_twin/ibeji_adapter/Cargo.toml @@ -30,6 +30,3 @@ tower = { workspace = true } [build-dependencies] freyja-build-common = { workspace = true } - -[features] -containerize = [] diff --git a/freyja_adapters/digital_twin/ibeji_adapter/src/config.rs b/freyja_adapters/digital_twin/ibeji_adapter/src/config.rs index b6613e3..0c6ceaf 100644 --- a/freyja_adapters/digital_twin/ibeji_adapter/src/config.rs +++ b/freyja_adapters/digital_twin/ibeji_adapter/src/config.rs @@ -7,28 +7,6 @@ use serde::{Deserialize, Serialize}; use std::env; -/// If feature 'containerize' is set, it 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. - let host_gateway_env_var: &str = "HOST_GATEWAY"; - let host_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 host_alias = env::var(host_alias_env_var)?; - - uri.replace(&host_alias, &host_gateway) - }; - - Ok(uri.to_string()) -} - /// Configuration for the Ibeji Adapter. /// Supports two different schemas based on the service discovery method. #[derive(Clone, Serialize, Deserialize)] diff --git a/freyja_adapters/digital_twin/ibeji_adapter/src/ibeji_adapter.rs b/freyja_adapters/digital_twin/ibeji_adapter/src/ibeji_adapter.rs index 65f5844..9f1734f 100644 --- a/freyja_adapters/digital_twin/ibeji_adapter/src/ibeji_adapter.rs +++ b/freyja_adapters/digital_twin/ibeji_adapter/src/ibeji_adapter.rs @@ -14,7 +14,7 @@ use service_discovery_proto::service_registry::v1::service_registry_client::Serv use service_discovery_proto::service_registry::v1::DiscoverRequest; use tonic::{transport::Channel, Request}; -use crate::config::{self, ChariottDiscoverRequest, Config}; +use crate::config::{ChariottDiscoverRequest, Config}; use freyja_build_common::config_file_stem; use freyja_common::{config_utils, out_dir, retry_utils::execute_with_retry}; use freyja_contracts::{ @@ -39,12 +39,10 @@ impl IbejiAdapter { chariott_service_discovery_uri: &str, chariott_discovery_request: ChariottDiscoverRequest, ) -> Result { - let chariott_uri = - config::get_uri(chariott_service_discovery_uri).map_err(DigitalTwinAdapterError::io)?; - - let mut service_registry_client = ServiceRegistryClient::connect(chariott_uri) - .await - .map_err(DigitalTwinAdapterError::communication)?; + let mut service_registry_client = + ServiceRegistryClient::connect(chariott_service_discovery_uri.to_owned()) + .await + .map_err(DigitalTwinAdapterError::communication)?; let discover_request = Request::new(DiscoverRequest { namespace: chariott_discovery_request.namespace, @@ -118,14 +116,11 @@ impl DigitalTwinAdapter for IbejiAdapter { } }; - let invehicle_digital_twin_uri = config::get_uri(&invehicle_digital_twin_service_uri) - .map_err(DigitalTwinAdapterError::io)?; - let client = futures::executor::block_on(async { execute_with_retry( max_retries, Duration::from_millis(retry_interval_ms), - || InvehicleDigitalTwinClient::connect(invehicle_digital_twin_uri.clone()), + || InvehicleDigitalTwinClient::connect(invehicle_digital_twin_service_uri.clone()), Some(String::from("Connection retry for connecting to Ibeji")), ) .await diff --git a/freyja_apps/e2e/Cargo.toml b/freyja_apps/e2e/Cargo.toml index d5302ae..999c13e 100644 --- a/freyja_apps/e2e/Cargo.toml +++ b/freyja_apps/e2e/Cargo.toml @@ -17,4 +17,8 @@ tokio = { workspace = true, features = ["macros"] } # This samples utilizes the in-memory mock adapters. azure-cloud-connector-adapter = { workspace = true } ibeji-adapter = { workspace = true } -in-memory-mock-mapping-client = { workspace = true } \ No newline at end of file +in-memory-mock-mapping-client = { workspace = true } + +# If built for aarch64, enable the 'vendored-ssl' feature. +[target.'cfg(target_arch = "aarch64")'.dependencies] +paho-mqtt = { workspace = true, features = ["vendored-ssl"] } diff --git a/freyja_apps/e2e/README.md b/freyja_apps/e2e/README.md index 1f5397f..c10b777 100644 --- a/freyja_apps/e2e/README.md +++ b/freyja_apps/e2e/README.md @@ -6,7 +6,7 @@ This Freyja Example Application utilizes the [Ibeji Digital Twin Adapter](../../ To build and run the application, follow these steps: -1. (Optional) If necessary, author configuration overrides for the [`InMemoryMockMappingClient`](https://github.com/eclipse-ibeji/freyja/tree/main/mapping_clients/in_memory_mock_mapping_client). Refer to the adapter README files for instructions on how to do this. This repository provides overrides for the samples listed under [Supported Samples](../ibeji_adapter/README.md#supported-samples). +1. (Optional) If necessary, author configuration overrides for the [`InMemoryMockMappingClient`](https://github.com/eclipse-ibeji/freyja/tree/main/mapping_clients/in_memory_mock_mapping_client). Refer to the adapter README files for instructions on how to do this. This repository provides overrides for the samples listed under [Supported Samples](../../README.md#supported-ibeji-samples). 1. Set the `$FREYJA_HOME` environment variable. For example, to use the provided overrides for the [Ibeji mixed sample](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/mixed), you can run the command below. @@ -19,3 +19,11 @@ To build and run the application, follow these steps: cargo run -p freyja-e2e-app This will rebuild the `freyja-e2e-app` application as necessary and then run it. + +## Containerize the End-To-End Freyja Example Application + +To build and run the application in a container, follow the steps under +[Docker Containers](../../container/README.md#docker-containers) or +[Podman Containers](../../container/README.md#podman-containers). + +Use `freyja-e2e-app` for the `APP_NAME` build arg when building the container. diff --git a/freyja_apps/ibeji_adapter/Cargo.toml b/freyja_apps/ibeji_adapter/Cargo.toml index 79d25df..c509db0 100644 --- a/freyja_apps/ibeji_adapter/Cargo.toml +++ b/freyja_apps/ibeji_adapter/Cargo.toml @@ -19,5 +19,6 @@ in-memory-mock-cloud-adapter = { workspace = true } ibeji-adapter = { workspace = true } in-memory-mock-mapping-client = { workspace = true } -[features] -containerize = ["ibeji-adapter/containerize"] +# If built for aarch64, enable the 'vendored-ssl' feature. +[target.'cfg(target_arch = "aarch64")'.dependencies] +paho-mqtt = { workspace = true, features = ["vendored-ssl"] } diff --git a/freyja_apps/ibeji_adapter/README.md b/freyja_apps/ibeji_adapter/README.md index b058eef..59cbac6 100644 --- a/freyja_apps/ibeji_adapter/README.md +++ b/freyja_apps/ibeji_adapter/README.md @@ -6,7 +6,7 @@ This Freyja Example Application utilizes the [Ibeji Digital Twin Adapter](../../ To build and run the application, follow these steps: -1. (Optional) If necessary, author configuration overrides for the [`InMemoryMockMappingClient`](https://github.com/eclipse-ibeji/freyja/tree/main/mapping_clients/in_memory_mock_mapping_client). Refer to the adapter README files for instructions on how to do this. This repository provides overrides for the samples listed under [Supported Samples](#supported-samples). +1. (Optional) If necessary, author configuration overrides for the [`InMemoryMockMappingClient`](https://github.com/eclipse-ibeji/freyja/tree/main/mapping_clients/in_memory_mock_mapping_client). Refer to the adapter README files for instructions on how to do this. This repository provides overrides for the samples listed under [Supported Ibeji Samples](../../README.md#supported-ibeji-samples). 1. Set the `$FREYJA_HOME` environment variable. For example, to use the provided overrides for the [Ibeji mixed sample](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/mixed), you can run the command below. @@ -20,91 +20,10 @@ To build and run the application, follow these steps: This will rebuild the `freyja-ibeji-adapter-app` application as necessary and then run it. -## Supported Samples - -This repository provides overrides in the [`.freyja`](../../.freyja/) directory that support the following Ibeji samples: - -- [managed subscribe](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/managed_subscribe) -- [mixed](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/mixed) -- [property](https://github.com/eclipse-ibeji/ibeji/tree/main/samples/property) - ## Containerize the Ibeji Adapter Freyja Example Application -To build and run the application in a container, follow the steps under [Docker](#docker) or -[Podman](#podman). Ensure that the `$FREYJA_HOME` environment variable is set. - -### Docker - -#### Prerequisites - -[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's root directory to build the docker container from the -Dockerfile: - - ```shell - docker build -t freyja_ibeji_adapter --build-arg APP_NAME=freyja-ibeji-adapter-app -f Dockerfile.freyja_apps . - ``` - - The `APP_NAME` build arg needs to be set as `Dockerfile.freyja_apps` defaults to the - [In Memory Example Application](../in_memory/). - -1. Once the container has been built, start the container in interactive mode with the following -command in the project's root directory: - - ```shell - docker run -v ${FREYJA_HOME}:/sdv/.freyja --name freyja_ibeji_adapter -p 60010:60010 --env-file=./container/config/docker.env --add-host=host.docker.internal:host-gateway -it --rm freyja_ibeji_adapter - ``` - - `-v` mounts the `$FREYJA_HOME` path set above in the container allowing the application to use - the provided overrides for the mixed sample in Ibeji. - -1. To detach from the container, enter: - - Ctrl + p, Ctrl + q - -1. To stop the container, enter: - - ```shell - docker stop freyja_ibeji_adapter - ``` - -### Podman - -#### Prerequisites - -[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's root directory to build the podman container from the -Dockerfile: - - ```shell - podman build -t freyja_ibeji_adapter --build-arg=APP_NAME=freyja-ibeji-adapter-app -f Dockerfile.freyja_apps . - ``` - - The `APP_NAME` build arg needs to be set as `Dockerfile.freyja_apps` defaults to the - [In Memory Example Application](../in_memory/). - -1. Once the container has been built, start the container with the following command in the -project's root directory: - - ```shell - podman run --mount=type=bind,src=${FREYJA_HOME},dst=/sdv/.freyja,ro=true -p 60010:60010 --env-file=./container/config/podman.env --network=slirp4netns:allow_host_loopback=true localhost/freyja_ibeji_adapter - ``` - - `-v` mounts the `$FREYJA_HOME` path set above in the container allowing the application to use - the provided overrides for the mixed sample in Ibeji. - -1. To stop the container, run: +To build and run the application in a container, follow the steps under +[Docker Containers](../../container/README.md#docker-containers) or +[Podman Containers](../../container/README.md#podman-containers). - ```shell - podman ps -f ancestor=localhost/freyja_ibeji_adapter:latest --format="{{.Names}}" | xargs podman stop - ``` +Use `freyja-ibeji-adapter-app` for the `APP_NAME` build arg when building the container. diff --git a/freyja_apps/in_memory/README.md b/freyja_apps/in_memory/README.md index 9162fb5..e2607db 100644 --- a/freyja_apps/in_memory/README.md +++ b/freyja_apps/in_memory/README.md @@ -18,70 +18,10 @@ This template is integrated with [revision `a07b033`](https://github.com/eclipse ## Containerize the In Memory Freyja Example Application -To build and run the application in a container, follow the steps under [Docker](#docker) or -[Podman](#podman). This is not a very useful example but shows how the application can be -containerized. +To build and run the application in a container, follow the steps under +[Docker Containers](../../container/README.md#docker-containers) or +[Podman Containers](../../container/README.md#podman-containers). -### Docker +Use `freyja-in-memory-app` for the `APP_NAME` build arg when building the container. -#### Prerequisites - -[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's root directory to build the docker container from the -Dockerfile: - - ```shell - docker build -t freyja_in_memory -f Dockerfile.freyja_apps . - ``` - -1. Once the container has been built, start the container in interactive mode with the following -command in the project's root directory: - - ```shell - docker run --name freyja_in_memory --env-file=./container/config/docker.env -it --rm freyja_in_memory - ``` - -1. To detach from the container, enter: - - Ctrl + p, Ctrl + q - -1. To stop the container, enter: - - ```shell - docker stop freyja_in_memory - ``` - -### Podman - -#### Prerequisites - -[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's root directory to build the podman container from the -Dockerfile: - - ```shell - podman build -t freyja_in_memory -f Dockerfile.freyja_apps . - ``` - -1. Once the container has been built, start the container with the following command in the -project's root directory: - - ```shell - podman run --env-file=./container/config/podman.env localhost/freyja_in_memory - ``` - -1. To stop the container, run: - - ```shell - podman ps -f ancestor=localhost/freyja_in_memory:latest --format="{{.Names}}" | xargs podman stop - ``` +>Note: This is not a very useful example but shows how the application can be containerized.