├── .clang-format
├── .devcontainer
├── Dockerfile
├── devcontainer.json
└── reinstall-cmake.sh
├── .github
├── actions
│ ├── build-container-image
│ │ └── action.yaml
│ └── build-native-binary
│ │ └── action.yaml
└── workflows
│ ├── main.yaml
│ ├── main_developer.yaml
│ └── ocaas.yaml
├── .gitignore
├── .gitmodules
├── .ort.yml
├── .vscode
├── c_cpp_properties.json
├── launch.json
└── settings.json
├── 3rdparty
├── CMakeLists.txt
└── meson-cross-file-aarch64.txt
├── CMakeLists.txt
├── Dockerfile.amd64
├── Dockerfile.arm64
├── LICENSE
├── README.md
├── clang-format.sh
├── cmake
├── dependencies.cmake
└── linux
│ ├── amd64
│ └── toolchain.cmake
│ └── arm64
│ └── toolchain.cmake
├── docs
├── bfb.md
├── building
│ └── README.md
├── data-privacy-notice.md
├── deploying
│ ├── README.md
│ └── sua-service.yaml
├── migration_guide.md
└── testing
│ ├── README.md
│ ├── fileserver
│ ├── Dockerfile
│ └── bundle
│ │ └── bundle
│ └── mqtt
│ ├── command-activate.json
│ ├── command-cleanup.json
│ ├── command-download.json
│ ├── command-rollback.json
│ ├── command-update.json
│ ├── current-state-get.json
│ ├── mosquitto.conf
│ └── start.json
├── project.spdx.yml
├── scripts
├── build.sh
├── build_glib_amd64.sh
├── build_glib_arm64.sh
├── build_openssl_amd64.sh
└── build_openssl_arm64.sh
├── src
├── CMakeLists.txt
├── Context.h
├── Defaults.cpp
├── Defaults.h
├── Download
│ ├── Downloader.cpp
│ ├── Downloader.h
│ └── IDownloader.h
├── FSM
│ ├── FSM.cpp
│ ├── FSM.h
│ ├── State.cpp
│ ├── State.h
│ ├── StateFactory.cpp
│ ├── StateFactory.h
│ └── States
│ │ ├── Activating.cpp
│ │ ├── Activating.h
│ │ ├── Cleaning.cpp
│ │ ├── Cleaning.h
│ │ ├── Connected.cpp
│ │ ├── Connected.h
│ │ ├── Downloading.cpp
│ │ ├── Downloading.h
│ │ ├── Failed.cpp
│ │ ├── Failed.h
│ │ ├── Idle.cpp
│ │ ├── Idle.h
│ │ ├── Installed.cpp
│ │ ├── Installed.h
│ │ ├── Installing.cpp
│ │ ├── Installing.h
│ │ ├── SendCurrentState.cpp
│ │ ├── SendCurrentState.h
│ │ ├── Uninitialized.cpp
│ │ └── Uninitialized.h
├── FotaEvent.cpp
├── FotaEvent.h
├── Install
│ ├── DBusRaucInstaller.cpp
│ ├── DBusRaucInstaller.h
│ ├── DummyRaucInstaller.cpp
│ ├── DummyRaucInstaller.h
│ ├── IRaucInstaller.h
│ ├── Installer.cpp
│ └── Installer.h
├── Logger.cpp
├── Logger.h
├── Mqtt
│ ├── IMqttMessagingProtocol.h
│ ├── IMqttProcessor.h
│ ├── MqttConfiguration.h
│ ├── MqttListener.h
│ ├── MqttMessage.cpp
│ ├── MqttMessage.h
│ ├── MqttMessagingProtocolJSON.cpp
│ ├── MqttMessagingProtocolJSON.h
│ ├── MqttProcessor.cpp
│ └── MqttProcessor.h
├── Patterns
│ ├── Dispatcher.cpp
│ └── Dispatcher.h
├── SelfUpdateAgent.cpp
├── SelfUpdateAgent.h
├── TechCodes.h
├── Utils
│ ├── BundleChecker.cpp
│ ├── BundleChecker.h
│ ├── IBundleChecker.h
│ ├── JsonUtils.cpp
│ ├── JsonUtils.h
│ ├── ServerAddressParser.cpp
│ └── ServerAddressParser.h
├── main.cpp
├── version.cpp.in
└── version.h
└── utest
├── CMakeLists.txt
├── MockBundleChecker.h
├── MockDownloader.h
├── MockFSM.h
├── MockMqttMessagingProtocol.h
├── MockMqttProcessor.h
├── TestDispatcher.cpp
├── TestDownloader.cpp
├── TestFSM.cpp
├── TestLogger.cpp
├── TestMqttMessagingProtocolJSON.cpp
├── TestSelfUpdateScenarios.cpp
├── TestServerAddressParser.cpp
├── TestStateFactory.cpp
├── Utils.cpp
├── Utils.h
├── sua-apache2.conf
└── sua-certificate.config
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: WebKit
2 | TabWidth: 4
3 | IndentWidth: 4
4 | UseTab: Never
5 | ColumnLimit: 100
6 |
7 | ---
8 | Language: Cpp
9 |
10 | DisableFormat: false
11 | Standard: Cpp11
12 |
13 | AccessModifierOffset: -4
14 | AlignAfterOpenBracket: true
15 | AlignConsecutiveAssignments: true
16 | AlignConsecutiveDeclarations: true
17 | AlignEscapedNewlinesLeft: false
18 | AlignOperands: true
19 | AlignTrailingComments: false
20 | AllowAllParametersOfDeclarationOnNextLine: true
21 | AllowShortBlocksOnASingleLine: false
22 | AllowShortCaseLabelsOnASingleLine: false
23 | AllowShortFunctionsOnASingleLine: Empty
24 | AllowShortIfStatementsOnASingleLine: false
25 | AllowShortLoopsOnASingleLine: false
26 | AlwaysBreakAfterDefinitionReturnType: false
27 | AlwaysBreakAfterReturnType: None
28 | AlwaysBreakBeforeMultilineStrings: false
29 | AlwaysBreakTemplateDeclarations: true
30 | BinPackArguments: false
31 | BinPackParameters: false
32 |
33 | BreakBeforeBraces: Custom
34 | BraceWrapping: {
35 | AfterClass: 'false'
36 | AfterControlStatement: 'false'
37 | AfterEnum: 'false'
38 | AfterFunction: 'true'
39 | AfterNamespace: 'false'
40 | AfterStruct: 'false'
41 | AfterUnion: 'false'
42 | BeforeCatch: 'false'
43 | BeforeElse: 'false'
44 | IndentBraces: 'false'
45 | AfterExternBlock: 'false'
46 | SplitEmptyFunction: 'false'
47 | SplitEmptyRecord: 'false'
48 | SplitEmptyNamespace: 'true'
49 | }
50 |
51 | BreakAfterJavaFieldAnnotations: true
52 | BreakBeforeInheritanceComma: true
53 | BreakBeforeBinaryOperators: None
54 | BreakBeforeTernaryOperators: true
55 | BreakConstructorInitializersBeforeComma: true
56 | BreakInheritanceList: BeforeColon
57 | BreakStringLiterals: true
58 |
59 | CommentPragmas: '^ IWYU pragma:'
60 | CompactNamespaces: false
61 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
62 | ConstructorInitializerIndentWidth: 4
63 | ContinuationIndentWidth: 4
64 | Cpp11BracedListStyle: true
65 | SpaceBeforeCpp11BracedList: false
66 | DerivePointerAlignment: false
67 | ExperimentalAutoDetectBinPacking: false
68 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
69 | IndentCaseLabels: false
70 | FixNamespaceComments: true
71 | IndentWrappedFunctionNames: false
72 | KeepEmptyLinesAtTheStartOfBlocks: true
73 | MacroBlockBegin: ''
74 | MacroBlockEnd: ''
75 | JavaScriptQuotes: Double
76 | MaxEmptyLinesToKeep: 1
77 | NamespaceIndentation: All
78 | ObjCBlockIndentWidth: 4
79 | ObjCSpaceAfterProperty: true
80 | ObjCSpaceBeforeProtocolList: true
81 | PenaltyBreakBeforeFirstCallParameter: 19
82 | PenaltyBreakComment: 300
83 | PenaltyBreakFirstLessLess: 120
84 | PenaltyBreakString: 1000
85 |
86 | PenaltyExcessCharacter: 1000000
87 | PenaltyReturnTypeOnItsOwnLine: 60
88 | PointerAlignment: Left
89 | SpaceAfterCStyleCast: false
90 | SpaceBeforeAssignmentOperators: true
91 | SpaceBeforeParens: Never
92 | SpaceInEmptyParentheses: false
93 | SpacesBeforeTrailingComments: 1
94 | SpacesInAngles: false
95 | SpacesInContainerLiterals: true
96 | SpacesInCStyleCastParentheses: false
97 | SpacesInParentheses: false
98 | SpacesInSquareBrackets: false
99 | SpaceAfterTemplateKeyword: true
100 | SpaceBeforeInheritanceColon: true
101 |
102 | SortUsingDeclarations: true
103 | SortIncludes: true
104 |
105 | ReflowComments: false
106 |
107 | UseCRLF: false
108 |
109 | IncludeBlocks: Preserve
110 | IndentPPDirectives: AfterHash
111 |
--------------------------------------------------------------------------------
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp/.devcontainer/base.Dockerfile
2 | # [Choice] Debian / Ubuntu version (use Debian 11/9, Ubuntu 18.04/21.04 on local arm64/Apple Silicon): debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
3 | ARG VARIANT="bullseye"
4 | FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-${VARIANT}
5 |
6 | # ENV http_proxy "http://172.17.0.1:3128"
7 | # ENV https_proxy "http://172.17.0.1:3128"
8 |
9 | # Required packages.
10 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
11 | && apt-get -y install python3-pip python3-setuptools python3-wheel ninja-build \
12 | libblkid-dev libselinux-dev gcc-9-aarch64-linux-gnu g++-9-aarch64-linux-gnu \
13 | mosquitto mosquitto-clients \
14 | && pip3 install meson
15 |
16 | # Optional packages.
17 | RUN apt-get -y install vim file iputils-ping
18 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at:
2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.195.0/containers/cpp
3 | {
4 | "name": "SDV Self Update DevContainer",
5 | "build": {
6 | "dockerfile": "Dockerfile",
7 | // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-11, debian-10, debian-9, ubuntu-21.04, ubuntu-20.04, ubuntu-18.04
8 | // Use Debian 11, Debian 9, Ubuntu 18.04 or Ubuntu 21.04 on local arm64/Apple Silicon
9 | "args": { "VARIANT": "bullseye" }
10 | },
11 | "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"],
12 |
13 | // Configure tool-specific properties.
14 | "customizations": {
15 | // Configure properties specific to VS Code.
16 | "vscode": {
17 | // Set *default* container specific settings.json values on container create.
18 | "settings": {},
19 |
20 | // Add the IDs of extensions you want installed when the container is created.
21 | "extensions": [
22 | "ms-vscode.cpptools",
23 | "ms-vscode.cmake-tools",
24 | "GitHub.copilot",
25 | "bierner.markdown-mermaid"
26 | ]
27 | }
28 | },
29 |
30 | // Use 'forwardPorts' to make a list of ports inside the container available locally.
31 | // "forwardPorts": [],
32 |
33 | // Use 'postCreateCommand' to run commands after the container is created.
34 | // "postCreateCommand": "gcc -v",
35 |
36 | // Comment out this line to run as root instead.
37 | "remoteUser": "vscode",
38 | "features": {
39 | "docker-in-docker": "latest"
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/.devcontainer/reinstall-cmake.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #-------------------------------------------------------------------------------------------------------------
3 | # Copyright (c) Microsoft Corporation. All rights reserved.
4 | # Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
5 | #-------------------------------------------------------------------------------------------------------------
6 | #
7 | set -e
8 |
9 | CMAKE_VERSION=${1:-"none"}
10 |
11 | if [ "${CMAKE_VERSION}" = "none" ]; then
12 | echo "No CMake version specified, skipping CMake reinstallation"
13 | exit 0
14 | fi
15 |
16 | # Cleanup temporary directory and associated files when exiting the script.
17 | cleanup() {
18 | EXIT_CODE=$?
19 | set +e
20 | if [[ -n "${TMP_DIR}" ]]; then
21 | echo "Executing cleanup of tmp files"
22 | rm -Rf "${TMP_DIR}"
23 | fi
24 | exit $EXIT_CODE
25 | }
26 | trap cleanup EXIT
27 |
28 |
29 | echo "Installing CMake..."
30 | apt-get -y purge --auto-remove cmake
31 | mkdir -p /opt/cmake
32 |
33 | architecture=$(dpkg --print-architecture)
34 | case "${architecture}" in
35 | arm64)
36 | ARCH=aarch64 ;;
37 | amd64)
38 | ARCH=x86_64 ;;
39 | *)
40 | echo "Unsupported architecture ${architecture}."
41 | exit 1
42 | ;;
43 | esac
44 |
45 | CMAKE_BINARY_NAME="cmake-${CMAKE_VERSION}-linux-${ARCH}.sh"
46 | CMAKE_CHECKSUM_NAME="cmake-${CMAKE_VERSION}-SHA-256.txt"
47 | TMP_DIR=$(mktemp -d -t cmake-XXXXXXXXXX)
48 |
49 | echo "${TMP_DIR}"
50 | cd "${TMP_DIR}"
51 |
52 | curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_BINARY_NAME}" -O
53 | curl -sSL "https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/${CMAKE_CHECKSUM_NAME}" -O
54 |
55 | sha256sum -c --ignore-missing "${CMAKE_CHECKSUM_NAME}"
56 | sh "${TMP_DIR}/${CMAKE_BINARY_NAME}" --prefix=/opt/cmake --skip-license
57 |
58 | ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake
59 |
--------------------------------------------------------------------------------
/.github/actions/build-container-image/action.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Contributors to the Eclipse Foundation
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 | # SPDX-License-Identifier: Apache-2.0
16 |
17 | name: Build and push container image
18 |
19 | inputs:
20 | arch:
21 | required: true
22 | description: "Architecture amd64/arm64"
23 | run_number:
24 | required: true
25 | description: "Workflow run number"
26 | commit_hash:
27 | required: true
28 | description: "Git commit hash"
29 | username:
30 | required: true
31 | description: "User name"
32 | token:
33 | required: true
34 | description: "Auth token"
35 | suffix:
36 | required: true
37 | description: "Optional suffix for -developer build of container image"
38 |
39 | runs:
40 | using: "composite"
41 | steps:
42 | - id: repo_name
43 | uses: ASzc/change-string-case-action@v5
44 | with:
45 | string: ${{ github.repository }}
46 |
47 | - name: Checkout repository
48 | uses: actions/checkout@v3
49 | with:
50 | submodules: recursive
51 |
52 | # Workaround: https://github.com/docker/build-push-action/issues/461
53 | - name: Setup Docker buildx
54 | uses: docker/setup-buildx-action@v2
55 |
56 | # Login against a Docker registry except on PR
57 | - name: Log into registry ghcr.io
58 | uses: docker/login-action@v2
59 | with:
60 | registry: ghcr.io
61 | username: ${{ inputs.username }}
62 | password: ${{ inputs.token }}
63 |
64 | # https://github.com/docker/build-push-action
65 | - name: Build and push docker image to ghcr.io
66 | id: build-and-push
67 | uses: docker/build-push-action@v4
68 | with:
69 | push: ${{ (github.event_name == 'push') || (inputs.suffix == '-developer') }}
70 | context: .
71 | platforms: linux/${{ inputs.arch }}
72 | file: Dockerfile.${{ inputs.arch }}
73 | labels: ${{ steps.meta.outputs.labels }}
74 | build-args: |
75 | GITHUB_RUN_NUMBER=${{ inputs.run_number }}
76 | GITHUB_COMMIT_HASH=${{ inputs.commit_hash }}
77 | tags: |
78 | ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent${{ inputs.suffix }}:latest_${{ inputs.arch }}
79 | ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent${{ inputs.suffix }}:build-${{ inputs.run_number }}_${{ inputs.arch }}
80 |
--------------------------------------------------------------------------------
/.github/workflows/main.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Contributors to the Eclipse Foundation
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 | # SPDX-License-Identifier: Apache-2.0
16 |
17 | name: Build All
18 |
19 | on:
20 | push:
21 | branches: [ main ]
22 | pull_request:
23 | branches: [ main ]
24 |
25 | jobs:
26 | build-container-image:
27 | runs-on: ubuntu-latest
28 | permissions:
29 | contents: read
30 | packages: write
31 | id-token: write
32 | pull-requests: write
33 | strategy:
34 | matrix:
35 | arch: [ amd64, arm64 ]
36 | steps:
37 | - uses: actions/checkout@v3
38 | with:
39 | submodules: recursive
40 |
41 | - name: Build Docker image
42 | uses: ./.github/actions/build-container-image
43 | with:
44 | arch: ${{ matrix.arch }}
45 | run_number: ${{ github.run_number }}
46 | commit_hash: ${{ github.sha }}
47 | username: ${{ github.actor }}
48 | token: ${{ secrets.GITHUB_TOKEN }}
49 | suffix: ""
50 |
51 | push-container-image:
52 | if: github.event_name == 'push'
53 | runs-on: ubuntu-latest
54 | needs: build-container-image
55 | steps:
56 | - uses: actions/checkout@v3
57 | with:
58 | submodules: recursive
59 |
60 | - id: repo_name
61 | uses: ASzc/change-string-case-action@v5
62 | with:
63 | string: ${{ github.repository }}
64 |
65 | - name: Log into registry ghcr.io
66 | uses: docker/login-action@v2
67 | with:
68 | registry: ghcr.io
69 | username: ${{ github.actor }}
70 | password: ${{ secrets.GITHUB_TOKEN }}
71 |
72 | - name: Create merged manifest and push
73 | env:
74 | REPO: ghcr.io/${{ steps.repo_name.outputs.lowercase }}
75 | run: |
76 | docker buildx imagetools create -t ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent:build-${{ github.run_number }} ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent:build-${{ github.run_number }}_arm64 ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent:build-${{ github.run_number }}_amd64
77 | docker buildx imagetools create -t ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent:latest ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent:latest_arm64 ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent:latest_amd64
78 |
79 | build-native-binary:
80 | runs-on: ubuntu-latest
81 | strategy:
82 | matrix:
83 | arch: [ amd64, arm64 ]
84 | steps:
85 | - uses: actions/checkout@v3
86 | with:
87 | submodules: recursive
88 |
89 | - name: Build native binary
90 | id: build-native-binary
91 | uses: ./.github/actions/build-native-binary
92 | with:
93 | arch: ${{ matrix.arch }}
94 | run_number: ${{ github.run_number }}
95 |
96 | - name: Upload ${{ matrix.arch }} artifacts to workspace
97 | uses: actions/upload-artifact@v3
98 | with:
99 | path: self-update-agent-${{ matrix.arch }}-build-${{ github.run_number }}.tar.gz
100 |
101 | - name: Upload code-coverage results to workspace
102 | if: ${{ matrix.arch == 'amd64' }}
103 | uses: actions/upload-artifact@v3
104 | with:
105 | path: code-coverage.tar.gz
106 |
107 | - name: Upload unit tests results to workspace
108 | uses: actions/upload-artifact@v3
109 | with:
110 | path: unit_tests_report_${{ matrix.arch }}.*
111 |
112 | upload-native-binary:
113 | runs-on: ubuntu-latest
114 | needs: build-native-binary
115 | steps:
116 | - uses: actions/checkout@v3
117 | with:
118 | submodules: recursive
119 |
120 | - name: Download artifacts
121 | uses: actions/download-artifact@v3
122 |
123 | - name: Upload artifacts to build results
124 | if: github.event_name == 'push'
125 | uses: marvinpinto/action-automatic-releases@latest
126 | with:
127 | repo_token: ${{ secrets.GITHUB_TOKEN }}
128 | draft: false
129 | prerelease: true
130 | automatic_release_tag: build_${{ github.run_number }}
131 | title: "Build ${{ github.run_number }}"
132 | files: |
133 | ./artifact/unit_tests_report_amd64.*
134 | ./artifact/unit_tests_report_arm64.*
135 | ./artifact/code-coverage.tar.gz
136 | ./artifact/self-update-agent-amd64-build-${{ github.run_number }}.tar.gz
137 | ./artifact/self-update-agent-arm64-build-${{ github.run_number }}.tar.gz
138 |
139 | - name: Upload artifacts to build results (make latest tag)
140 | if: github.event_name == 'push'
141 | uses: marvinpinto/action-automatic-releases@latest
142 | with:
143 | repo_token: ${{ secrets.GITHUB_TOKEN }}
144 | draft: false
145 | prerelease: true
146 | automatic_release_tag: latest
147 | title: "Latest build (${{ github.run_number }})"
148 | files: |
149 | ./artifact/unit_tests_report_amd64.*
150 | ./artifact/unit_tests_report_arm64.*
151 | ./artifact/code-coverage.tar.gz
152 | ./artifact/self-update-agent-amd64-build-${{ github.run_number }}.tar.gz
153 | ./artifact/self-update-agent-arm64-build-${{ github.run_number }}.tar.gz
154 |
155 |
--------------------------------------------------------------------------------
/.github/workflows/main_developer.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Contributors to the Eclipse Foundation
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 | # SPDX-License-Identifier: Apache-2.0
16 |
17 | name: Build developer container
18 |
19 | on:
20 | workflow_dispatch:
21 |
22 | jobs:
23 | build-container-image:
24 | runs-on: ubuntu-latest
25 | permissions:
26 | contents: read
27 | packages: write
28 | id-token: write
29 | strategy:
30 | matrix:
31 | arch: [ amd64, arm64 ]
32 | steps:
33 | - uses: actions/checkout@v3
34 | with:
35 | submodules: recursive
36 |
37 | - name: Build Docker image
38 | uses: ./.github/actions/build-container-image
39 | with:
40 | arch: ${{ matrix.arch }}
41 | run_number: ${{ github.run_number }}
42 | commit_hash: ${{ github.sha }}
43 | username: ${{ github.actor }}
44 | token: ${{ secrets.GITHUB_TOKEN }}
45 | suffix: "-developer"
46 |
47 | push-container-image:
48 | runs-on: ubuntu-latest
49 | needs: build-container-image
50 | steps:
51 | - uses: actions/checkout@v3
52 | with:
53 | submodules: recursive
54 |
55 | - id: repo_name
56 | uses: ASzc/change-string-case-action@v1
57 | with:
58 | string: ${{ github.repository }}
59 |
60 | - name: Log into registry ghcr.io
61 | uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
62 | with:
63 | registry: ghcr.io
64 | username: ${{ github.actor }}
65 | password: ${{ secrets.GITHUB_TOKEN }}
66 |
67 | - name: Create merged manifest and push
68 | env:
69 | REPO: ghcr.io/${{ steps.repo_name.outputs.lowercase }}
70 | run: |
71 | docker buildx imagetools create -t ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent-developer:build-${{ github.run_number }} ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent-developer:build-${{ github.run_number }}_arm64 ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent-developer:build-${{ github.run_number }}_amd64
72 | docker buildx imagetools create -t ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent-developer:latest ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent-developer:latest_arm64 ghcr.io/${{ steps.repo_name.outputs.lowercase }}/self-update-agent-developer:latest_amd64
73 |
74 |
--------------------------------------------------------------------------------
/.github/workflows/ocaas.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2023 Contributors to the Eclipse Foundation
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 | #
15 | # SPDX-License-Identifier: Apache-2.0
16 |
17 | name: OCaaS Compliance checks
18 |
19 | on:
20 | workflow_dispatch:
21 | push:
22 | pull_request:
23 |
24 | jobs:
25 | ocaas-scan:
26 | runs-on: ubuntu-latest
27 | if: github.repository_owner == 'SoftwareDefinedVehicle'
28 | steps:
29 | - name: setup env variables for OCaaS
30 | run: |
31 | echo "VCS_REVISION=${{ github.ref_name }}" >> $GITHUB_ENV
32 | - name: use different VCS_REVISION for pull requests
33 | if: github.event_name == 'pull_request'
34 | run: |
35 | echo "Workflow triggered by pull request. Scanning source branch only as merge revisions are not supported."
36 | echo "VCS_REVISION=${{ github.head_ref }}" >> $GITHUB_ENV
37 | - name: OCaaS Scans
38 | id: ocaas
39 | uses: docker://osmipublic.azurecr.io/ocaas-ci:latest
40 | continue-on-error: true # Built artifacts also should also be uploaded if the scan finds violations.
41 | with:
42 | args: auth generate-token run start download
43 | env:
44 | OCAAS_USERNAME: ${{ secrets.OCAAS_USERNAME }}
45 | OCAAS_PASSWORD: ${{ secrets.OCAAS_PASSWORD }}
46 | PROJECT_NAME: "Project LEDA - sdv-self-update-agent"
47 | PIPELINE_ID: 377 # Your pipeline ID. Provided by the OSMI team.
48 | VCS_URL: ${{ github.server_url }}/${{ github.repository }}.git
49 | # VCS_REVISION: is defined before
50 | APPLICATION_CATEGORY: "BT11"
51 | BLOCKING: true
52 | REPORT_FILES: DISCLOSURE_DOCUMENT_PDF,VULNERABILITY_REPORT_PDF,SCAN_REPORT_WEB_APP_HTML
53 | OUTPUT_DIR: reports/
54 | - name: Upload reports
55 | id: upload
56 | uses: actions/upload-artifact@v3
57 | with:
58 | name: reports
59 | path: reports/
60 | - name: Check for violations
61 | if: steps.ocaas.outcome != 'success' || steps.upload.outcome != 'success'
62 | run: exit 1
63 |
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | CMakeLists.txt.user
2 | CMakeCache.txt
3 | CMakeFiles
4 | CMakeScripts
5 | Testing
6 | Makefile
7 | cmake_install.cmake
8 | install_manifest.txt
9 | compile_commands.json
10 | CTestTestfile.cmake
11 | _deps
12 | build_amd64
13 | build_arm64
14 | dist_amd64
15 | dist_arm64
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "3rdparty/paho.mqtt.c"]
2 | path = 3rdparty/paho.mqtt.c
3 | url = https://github.com/eclipse/paho.mqtt.c.git
4 | [submodule "3rdparty/paho.mqtt.cpp"]
5 | path = 3rdparty/paho.mqtt.cpp
6 | url = https://github.com/eclipse/paho.mqtt.cpp.git
7 | [submodule "3rdparty/curl"]
8 | path = 3rdparty/curl
9 | url = https://github.com/curl/curl.git
10 | [submodule "3rdparty/googletest"]
11 | path = 3rdparty/googletest
12 | url = https://github.com/google/googletest.git
13 | [submodule "3rdparty/glib"]
14 | path = 3rdparty/glib
15 | url = https://github.com/GNOME/glib.git
16 | [submodule "3rdparty/spdlog"]
17 | path = 3rdparty/spdlog
18 | url = https://github.com/gabime/spdlog.git
19 | [submodule "3rdparty/openssl"]
20 | path = 3rdparty/openssl
21 | url = https://github.com/openssl/openssl.git
22 | [submodule "3rdparty/nlohmann-json"]
23 | path = 3rdparty/nlohmann-json
24 | url = https://github.com/nlohmann/json
25 |
--------------------------------------------------------------------------------
/.vscode/c_cpp_properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "name": "Linux",
5 | "includePath": [
6 | "${workspaceFolder}/**",
7 | "${workspaceFolder}/3rdparty"
8 | ],
9 | "defines": [],
10 | "compilerPath": "/usr/bin/gcc",
11 | "cStandard": "gnu17",
12 | "cppStandard": "gnu++17",
13 | "intelliSenseMode": "linux-gcc-x64",
14 | "configurationProvider": "ms-vscode.cmake-tools"
15 | }
16 | ],
17 | "version": 4
18 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Launch SDV update agent",
6 | "type": "cppdbg",
7 | "request": "launch",
8 | "program": "${workspaceFolder}/build_amd64/src/sdv-self-update-agent",
9 | "args": [],
10 | "stopAtEntry": false,
11 | "cwd": "${workspaceFolder}",
12 | "environment": [
13 | {
14 | "name": "LD_LIBRARY_PATH",
15 | "value": "${workspaceFolder}/dist_amd64/lib"
16 | }
17 | ],
18 | "externalConsole": false,
19 | "MIMode": "gdb",
20 | "setupCommands": [
21 | {
22 | "description": "Enable pretty-printing for gdb",
23 | "text": "-enable-pretty-printing",
24 | "ignoreFailures": true
25 | }
26 | ]
27 | }
28 | ]
29 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "string": "cpp",
4 | "cstdlib": "cpp",
5 | "list": "cpp",
6 | "*.tcc": "cpp",
7 | "array": "cpp",
8 | "atomic": "cpp",
9 | "bit": "cpp",
10 | "cctype": "cpp",
11 | "chrono": "cpp",
12 | "clocale": "cpp",
13 | "cmath": "cpp",
14 | "condition_variable": "cpp",
15 | "cstdarg": "cpp",
16 | "cstddef": "cpp",
17 | "cstdint": "cpp",
18 | "cstdio": "cpp",
19 | "cstring": "cpp",
20 | "ctime": "cpp",
21 | "cwchar": "cpp",
22 | "cwctype": "cpp",
23 | "deque": "cpp",
24 | "map": "cpp",
25 | "unordered_map": "cpp",
26 | "vector": "cpp",
27 | "exception": "cpp",
28 | "algorithm": "cpp",
29 | "functional": "cpp",
30 | "iterator": "cpp",
31 | "memory": "cpp",
32 | "memory_resource": "cpp",
33 | "numeric": "cpp",
34 | "optional": "cpp",
35 | "random": "cpp",
36 | "ratio": "cpp",
37 | "string_view": "cpp",
38 | "system_error": "cpp",
39 | "tuple": "cpp",
40 | "type_traits": "cpp",
41 | "utility": "cpp",
42 | "fstream": "cpp",
43 | "future": "cpp",
44 | "initializer_list": "cpp",
45 | "iosfwd": "cpp",
46 | "iostream": "cpp",
47 | "istream": "cpp",
48 | "limits": "cpp",
49 | "mutex": "cpp",
50 | "new": "cpp",
51 | "ostream": "cpp",
52 | "sstream": "cpp",
53 | "stdexcept": "cpp",
54 | "streambuf": "cpp",
55 | "thread": "cpp",
56 | "cinttypes": "cpp",
57 | "typeinfo": "cpp",
58 | "any": "cpp",
59 | "forward_list": "cpp",
60 | "set": "cpp",
61 | "unordered_set": "cpp",
62 | "iomanip": "cpp",
63 | "variant": "cpp"
64 | }
65 | }
--------------------------------------------------------------------------------
/3rdparty/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(PAHO_ENABLE_TESTING FALSE CACHE BOOL "")
2 | set(PAHO_BUILD_STATIC FALSE CACHE BOOL "")
3 | set(PAHO_BUILD_SHARED TRUE CACHE BOOL "")
4 | set(PAHO_BUILD_WITH_SSL FALSE CACHE BOOL "")
5 | add_subdirectory(./paho.mqtt.c)
6 |
7 | set(PAHO_MQTT_C_LIBRARIES ${CMAKE_BINARY_DIR}/3rdparty/paho.mqtt.c/src/libpaho-mqtt3c.so)
8 | set(PAHO_MQTT_C_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/3rdparty/paho.mqtt.c/src)
9 |
10 | add_subdirectory(./paho.mqtt.cpp)
11 |
12 | add_dependencies(paho-mqttpp3 paho-mqtt3a)
13 | add_dependencies(paho-mqttpp3 paho-mqtt3c)
14 |
15 | set(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/lib/pkgconfig)
16 | find_package(OpenSSL REQUIRED)
17 | set(CURL_USE_OPENSSL ON)
18 | set(BUILD_SHARED_LIBS ON)
19 | set(BUILD_CURL_EXE OFF)
20 | add_subdirectory(curl)
21 |
22 | if(SUA_BUILD_TESTS)
23 | add_subdirectory(googletest)
24 | endif()
25 |
26 | install(
27 | FILES
28 | ${CMAKE_BINARY_DIR}/lib/libssl.so.3
29 | ${CMAKE_BINARY_DIR}/lib/libcrypto.so.3
30 | ${CMAKE_BINARY_DIR}/3rdparty/curl/lib/libcurl.so
31 | ${CMAKE_BINARY_DIR}/glib/subprojects/zlib-1.2.11/libz.so
32 | DESTINATION ${CMAKE_INSTALL_PREFIX}/lib
33 | )
34 |
35 | install(FILES ${CMAKE_BINARY_DIR}/glib/gio/libgio-2.0.so.0.7800.0 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib RENAME libgio-2.0.so.0)
36 | install(FILES ${CMAKE_BINARY_DIR}/glib/glib/libglib-2.0.so.0.7800.0 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib RENAME libglib-2.0.so.0)
37 | install(FILES ${CMAKE_BINARY_DIR}/glib/gmodule/libgmodule-2.0.so.0.7800.0 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib RENAME libgmodule-2.0.so.0)
38 | install(FILES ${CMAKE_BINARY_DIR}/glib/gobject/libgobject-2.0.so.0.7800.0 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib RENAME libgobject-2.0.so.0)
39 | install(FILES ${CMAKE_BINARY_DIR}/glib/subprojects/libffi/src/libffi.so.7.1.0 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib RENAME libffi.so.7)
40 | install(FILES ${CMAKE_BINARY_DIR}/glib/subprojects/proxy-libintl/libintl.so.8 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib RENAME libintl.so.8)
41 |
--------------------------------------------------------------------------------
/3rdparty/meson-cross-file-aarch64.txt:
--------------------------------------------------------------------------------
1 | [host_machine]
2 | system = 'linux'
3 | cpu_family = 'aarch64'
4 | cpu = 'aarch64'
5 | endian = 'little'
6 |
7 | [properties]
8 | c_args = []
9 | c_link_args = []
10 |
11 | [binaries]
12 | c = 'aarch64-linux-gnu-gcc-9'
13 | cpp = 'aarch64-linux-gnu-g++-9'
14 | ar = 'aarch64-linux-gnu-ar'
15 | ld = 'aarch64-linux-gnu-ld'
16 | objcopy = 'aarch64-linux-gnu-objcopy'
17 | strip = 'aarch64-linux-gnu-strip'
18 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.10)
2 | project(sdv-self-update-agent)
3 |
4 | set(CMAKE_CXX_STANDARD 14)
5 |
6 | set(CMAKE_SKIP_BUILD_RPATH TRUE)
7 | set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
8 | set(CMAKE_INSTALL_RPATH ../lib)
9 |
10 | option(SUA_BUILD_TESTS "Build unit tests with code-coverage report enabled" OFF)
11 | option(SUA_MEASURE_CODE_COVERAGE "Measure code-coverage" OFF)
12 |
13 | include(cmake/dependencies.cmake)
14 |
15 | add_subdirectory(3rdparty)
16 | add_subdirectory(src)
17 |
18 | if(SUA_BUILD_TESTS)
19 | add_subdirectory(utest)
20 | endif()
21 |
22 | unset(SUA_BUILD_TESTS CACHE)
23 |
--------------------------------------------------------------------------------
/Dockerfile.amd64:
--------------------------------------------------------------------------------
1 | # Dockerfile for building multi-arch images and for runtime of the SDV Self Update Agent
2 |
3 | FROM --platform=${BUILDPLATFORM} ubuntu AS build
4 |
5 | ARG TARGETPLATFORM
6 | ARG GITHUB_RUN_NUMBER
7 | ARG GITHUB_COMMIT_HASH
8 |
9 | RUN apt-get update && apt-get -y install \
10 | autoconf binutils cmake file \
11 | gcc g++ git libtool make \
12 | build-essential libcurl4-openssl-dev \
13 | binutils-aarch64-linux-gnu gcc-9-aarch64-linux-gnu g++-9-aarch64-linux-gnu \
14 | python3 python3-pip python3-setuptools python3-wheel ninja-build meson \
15 | libselinux1-dev libmount-dev libmount1 libblkid-dev \
16 | ca-certificates
17 |
18 | # Copy the sources to the build container
19 | COPY .git /work/.git
20 | COPY src /work/src
21 | COPY cmake /work/cmake
22 | COPY 3rdparty /work/3rdparty
23 | COPY utest /work/utest
24 | COPY scripts /work/scripts
25 | COPY CMakeLists.txt /work/CMakeLists.txt
26 |
27 | # Build the Self Update Agent binaries and dependencies
28 | RUN cd /work \
29 | && mkdir -p build_amd64/3rdparty/openssl \
30 | && mkdir -p dist_amd64 \
31 | && ./scripts/build_openssl_amd64.sh > /dev/null
32 |
33 | RUN cd /work \
34 | && ./scripts/build_glib_amd64.sh > /dev/null
35 |
36 | RUN cd /work \
37 | && cd build_amd64 \
38 | && cmake \
39 | -DCMAKE_INSTALL_PREFIX=../dist_amd64 \
40 | -DCMAKE_TOOLCHAIN_FILE=../cmake/linux/amd64/toolchain.cmake \
41 | -DOPENSSL_ROOT_DIR=../build_amd64 \
42 | -DOPENSSL_CRYPTO_LIBRARY=../build_amd64/lib/libcrypto.so \
43 | -DCMAKE_BUILD_TYPE="Release" \
44 | -DSUA_BUILD_NUMBER=$GITHUB_RUN_NUMBER \
45 | -DSUA_COMMIT_HASH=$GITHUB_COMMIT_HASH \
46 | ..
47 |
48 | RUN cd /work \
49 | && cd build_amd64 \
50 | && make -j
51 |
52 | RUN cd /work \
53 | && cd build_amd64 \
54 | && make install/strip
55 |
56 | RUN cd /work \
57 | && strip dist_amd64/lib/lib* \
58 | && strip /work/build_amd64/glib/gio/libgio-2.0.so.0 \
59 | && strip /work/build_amd64/glib/gobject/libgobject-2.0.so.0 \
60 | && strip /work/build_amd64/glib/glib/libglib-2.0.so.0 \
61 | && strip /work/build_amd64/glib/gmodule/libgmodule-2.0.so.0 \
62 | && strip /work/build_amd64/glib/subprojects/libffi/src/libffi.so.7 \
63 | && strip /work/build_amd64/glib/subprojects/zlib-1.2.11/libz.so
64 |
65 | #Define RUNTIME environment, the final image
66 | FROM --platform=${TARGETPLATFORM} scratch as runtime
67 | ARG TARGETPLATFORM
68 | COPY --from=build /work/dist_amd64/bin/sdv-self-update-agent /sua/bin/sdv-self-update-agent
69 | COPY --from=build /work/dist_amd64/lib/libpaho-mqttpp3.so.1 /sua/lib/
70 | COPY --from=build /work/dist_amd64/lib/libpaho-mqtt3a.so.1 /sua/lib/
71 | COPY --from=build /work/dist_amd64/lib/libpaho-mqtt3c.so.1 /sua/lib/
72 | COPY --from=build /work/dist_amd64/lib/libcurl.so.4.8.0 /sua/lib/libcurl.so.4
73 | COPY --from=build /work/dist_amd64/lib/libcrypto.so.3 /sua/lib/
74 | COPY --from=build /work/dist_amd64/lib/libssl.so.3 /sua/lib/
75 | COPY --from=build /work/dist_amd64/lib/libsua.so /sua/lib/
76 | COPY --from=build /work/build_amd64/glib/gio/libgio-2.0.so.0 /sua/lib/
77 | COPY --from=build /work/build_amd64/glib/gobject/libgobject-2.0.so.0 /sua/lib/
78 | COPY --from=build /work/build_amd64/glib/glib/libglib-2.0.so.0 /sua/lib/
79 | COPY --from=build /work/build_amd64/glib/gmodule/libgmodule-2.0.so.0 /sua/lib/
80 | COPY --from=build /work/build_amd64/glib/subprojects/libffi/src/libffi.so.7 /sua/lib/
81 | COPY --from=build /work/build_amd64/glib/subprojects/zlib-1.2.11/libz.so /sua/lib/
82 | COPY --from=build /work/build_amd64/glib/subprojects/proxy-libintl/libintl.so.8 /sua/lib/
83 | COPY --from=build /etc/ssl/certs /etc/ssl/certs/
84 | COPY --from=build /usr/share/ca-certificates /usr/share/ca-certificates
85 | COPY --from=build /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
86 | COPY --from=build /lib/x86_64-linux-gnu/libgcc_s.so.1 /lib/libgcc_s.so.1
87 | COPY --from=build /lib/x86_64-linux-gnu/libstdc++.so.6 /lib/libstdc++.so.6
88 | COPY --from=build /lib/x86_64-linux-gnu/libc.so.6 /lib/libc.so.6
89 | COPY --from=build /lib/x86_64-linux-gnu/libz.so.1 /lib/libz.so.1
90 | COPY --from=build /lib/x86_64-linux-gnu/libm.so.6 /lib/libm.so.6
91 |
92 | WORKDIR /sua/bin
93 | ENV LD_LIBRARY_PATH ../lib
94 | CMD ["./sdv-self-update-agent"]
95 |
--------------------------------------------------------------------------------
/Dockerfile.arm64:
--------------------------------------------------------------------------------
1 | # Dockerfile for building multi-arch images and for runtime of the SDV Self Update Agent
2 |
3 | FROM --platform=${BUILDPLATFORM} ubuntu AS build
4 |
5 | ARG TARGETPLATFORM
6 | ARG GITHUB_RUN_NUMBER
7 | ARG GITHUB_COMMIT_HASH
8 |
9 | RUN apt-get update && apt-get -y install \
10 | autoconf binutils cmake file \
11 | gcc g++ git libtool make \
12 | build-essential libcurl4-openssl-dev \
13 | binutils-aarch64-linux-gnu gcc-9-aarch64-linux-gnu g++-9-aarch64-linux-gnu \
14 | python3 python3-pip python3-setuptools python3-wheel ninja-build meson \
15 | libselinux1-dev libmount-dev libmount1 libblkid-dev \
16 | ca-certificates
17 |
18 | # Copy the sources to the build container
19 | COPY .git /work/.git
20 | COPY src /work/src
21 | COPY cmake /work/cmake
22 | COPY 3rdparty /work/3rdparty
23 | COPY utest /work/utest
24 | COPY scripts /work/scripts
25 | COPY CMakeLists.txt /work/CMakeLists.txt
26 |
27 | # Build the Self Update Agent binaries and dependencies
28 | RUN cd /work \
29 | && mkdir -p build_arm64/3rdparty/openssl \
30 | && mkdir -p dist_arm64 \
31 | && ./scripts/build_openssl_arm64.sh > /dev/null
32 |
33 | RUN cd /work \
34 | && ./scripts/build_glib_arm64.sh > /dev/null
35 |
36 | RUN cd /work \
37 | && cd build_arm64 \
38 | && cmake \
39 | -DCMAKE_INSTALL_PREFIX=../dist_arm64 \
40 | -DCMAKE_TOOLCHAIN_FILE=../cmake/linux/arm64/toolchain.cmake \
41 | -DOPENSSL_ROOT_DIR=../build_arm64 \
42 | -DOPENSSL_CRYPTO_LIBRARY=../build_arm64/lib/libcrypto.so \
43 | -DCMAKE_BUILD_TYPE="Release" \
44 | -DSUA_BUILD_NUMBER=$GITHUB_RUN_NUMBER \
45 | -DSUA_COMMIT_HASH=$GITHUB_COMMIT_HASH \
46 | ..
47 |
48 | RUN cd /work \
49 | && cd build_arm64 \
50 | && make -j
51 |
52 | RUN cd /work \
53 | && cd build_arm64 \
54 | && make install/strip
55 |
56 | RUN cd /work \
57 | && aarch64-linux-gnu-strip dist_arm64/lib/lib* \
58 | && aarch64-linux-gnu-strip /work/build_arm64/glib/gio/libgio-2.0.so.0 \
59 | && aarch64-linux-gnu-strip /work/build_arm64/glib/gobject/libgobject-2.0.so.0 \
60 | && aarch64-linux-gnu-strip /work/build_arm64/glib/glib/libglib-2.0.so.0 \
61 | && aarch64-linux-gnu-strip /work/build_arm64/glib/gmodule/libgmodule-2.0.so.0 \
62 | && aarch64-linux-gnu-strip /work/build_arm64/glib/subprojects/libffi/src/libffi.so.7 \
63 | && aarch64-linux-gnu-strip /work/build_arm64/glib/subprojects/zlib-1.2.11/libz.so
64 |
65 | #Define RUNTIME environment, the final image
66 | FROM --platform=${TARGETPLATFORM} scratch as runtime
67 | ARG TARGETPLATFORM
68 | COPY --from=build /work/dist_arm64/bin/sdv-self-update-agent /sua/bin/sdv-self-update-agent
69 | COPY --from=build /work/dist_arm64/lib/libpaho-mqttpp3.so.1 /sua/lib/
70 | COPY --from=build /work/dist_arm64/lib/libpaho-mqtt3a.so.1 /sua/lib/
71 | COPY --from=build /work/dist_arm64/lib/libpaho-mqtt3c.so.1 /sua/lib/
72 | COPY --from=build /work/dist_arm64/lib/libcurl.so.4.8.0 /sua/lib/libcurl.so.4
73 | COPY --from=build /work/dist_arm64/lib/libcrypto.so.3 /sua/lib/
74 | COPY --from=build /work/dist_arm64/lib/libssl.so.3 /sua/lib/
75 | COPY --from=build /work/dist_arm64/lib/libsua.so /sua/lib/
76 | COPY --from=build /work/build_arm64/glib/gio/libgio-2.0.so.0 /sua/lib/
77 | COPY --from=build /work/build_arm64/glib/gobject/libgobject-2.0.so.0 /sua/lib/
78 | COPY --from=build /work/build_arm64/glib/glib/libglib-2.0.so.0 /sua/lib/
79 | COPY --from=build /work/build_arm64/glib/gmodule/libgmodule-2.0.so.0 /sua/lib/
80 | COPY --from=build /work/build_arm64/glib/subprojects/libffi/src/libffi.so.7 /sua/lib/
81 | COPY --from=build /work/build_arm64/glib/subprojects/zlib-1.2.11/libz.so /sua/lib/
82 | COPY --from=build /work/build_arm64/glib/subprojects/proxy-libintl/libintl.so.8 /sua/lib/
83 | COPY --from=build /etc/ssl/certs /etc/ssl/certs/
84 | COPY --from=build /usr/share/ca-certificates /usr/share/ca-certificates
85 | COPY --from=build /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 /lib/ld-linux-aarch64.so.1
86 | COPY --from=build /usr/aarch64-linux-gnu/lib/libstdc++.so.6 /lib/
87 | COPY --from=build /usr/aarch64-linux-gnu/lib/libgcc_s.so.1 /lib/
88 | COPY --from=build /usr/aarch64-linux-gnu/lib/libc.so.6 /lib/
89 | COPY --from=build /usr/aarch64-linux-gnu/lib/libm.so.6 /lib/
90 |
91 | WORKDIR /sua/bin
92 | ENV LD_LIBRARY_PATH ../lib
93 | CMD ["./sdv-self-update-agent"]
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # License
2 | Apache 2.0
3 |
4 | # Contribution
5 | Follow guidelines from Eclipse Leda: https://eclipse-leda.github.io/leda/docs/project-info/contribution-guidelines
6 |
7 | # Security Policy
8 | This project implements the Eclipse Foundation Security Policy: https://www.eclipse.org/security
9 |
10 | # Reporting a Vulnerability
11 | Please report vulnerabilities to the Eclipse Foundation Security Team at security@eclipse.org
12 |
13 | # Data privacy notice:
14 | Data privacy notice is here: [link](docs/data-privacy-notice.md)
15 |
16 | # SDV Self Update Agent
17 | The self update agent (SUA) is a component responsible for the OS Update process.
18 | SUA is communicating on MQTT interface via usage of defined messages. Internally, SUA uses [RAUC](https://rauc.io/) to perform the update.
19 |
20 | Following sequence diagram shows the happy path example of communication between components.
21 |
22 | ```mermaid
23 | sequenceDiagram
24 | participant m as MQTT Broker
25 | participant s as SUA
26 | participant r as RAUC
27 |
28 | s -->> m: connect
29 |
30 | loop Wait for OTA trigger
31 |
32 | Note left of s: Initial start
33 | s ->> m: Current state (installed version from booted partition)
34 |
35 | Note left of s: Trigger for OTA
36 | m ->> s: Desired state request (new version and url to bundle)
37 | s ->> m: Feedback (update actions are identified)
38 |
39 | Note left of s: Command for Download
40 | m ->> s: Download command
41 | s ->> s: Download bundle
42 | s ->> m: Feedback (downloading/downloaded/failed)
43 |
44 | Note left of s: Command for Update
45 | m ->> s: Update command
46 | s ->> r: Flash image to partition
47 | r ->> r: Flashing...
48 | s ->> m: Feedback (updating with percentage)
49 | r ->> s: Flash completed/failed
50 | s ->> m: Feedback (updated/failed)
51 |
52 | Note left of s: Command for Activate
53 | m ->> s: Activate command
54 | s ->> r: Switch partitions (booted <-> other)
55 | r ->> s: Switch completed/failed
56 | s ->> m: Feedback (activated/failed)
57 |
58 | Note left of s: Command for Cleanup
59 | m ->> s: Cleanup command
60 | s ->> s: Remove temporary files
61 | s ->> m: Cleanup completed + status from previously failed state
(completed/failed)
62 |
63 | end
64 | ```
65 |
66 | ```mermaid
67 | stateDiagram
68 | Uninitialized --> Connected: Connected
69 | Connected --> Identified: Start (OTA trigger)
70 | Identified --> Downloading: Command download
71 | Identified --> Failed: If OTA trigger is invalid
72 | Downloading --> Updating: Command update
73 | Downloading --> Failed: If download has failed
74 | Updating --> Activate: Command activate
75 | Updating --> Failed: If update has failed
76 | Activate --> Cleanup: Command cleanup
77 | Activate --> Failed: If activate has failed
78 | Failed --> Cleanup: Command cleanup
79 | Cleanup --> Idle
80 | ```
81 | Important: Uninitialized state is the default entry state or state in case connection is lost. To simplify reading of the diagram arrows from other states to Unitialized have been removed.
82 |
83 | MQTT communication is done over 5 MQTT topics:
84 |
85 | ## Trigger OTA
86 | | Topic | Direction | Description |
87 | |-------|-----------|-------------|
88 | | selfupdate/desiredstate | IN | This message triggers the update process. The payload shall contain all data necessary to obtain the update bundle and to install it. |
89 |
90 | ## Trigger self-update step/action
91 | | Topic | Direction | Description |
92 | |-------|-----------|-------------|
93 | | selfupdate/desiredstate/command | IN | This message triggers the single step in update process (download/flash/activate/cleanup). |
94 |
95 | ## Report current state
96 | | Topic | Direction | Description |
97 | |-------|-----------|-------------|
98 | | selfupdate/currentstate | OUT | This message is being sent either once on SUA start or as an answer to response received by selfupdate/currentstate/get. It contains information about the currently installed OS version. |
99 |
100 | ## Get current state
101 | | Topic | Direction | Description |
102 | |-------|-----------|-------------|
103 | | selfupdate/currentstate/get | IN | This message can be received at any point of time. Indicates that SUA should send back the version of the installed OS as current state. |
104 |
105 | ## Report status of self-update process
106 | | Topic | Direction | Description |
107 | |-------|-----------|-------------|
108 | | selfupdate/desiredstatefeedback | OUT | This message is being sent by SUA to share the current progress of the triggered update process. This is the *OUT* counterpart of *selfupdate/desiredstate* input message. |
109 |
110 | Detailed description of Update Agent API can be found here: [link](docs/bfb.md).
111 | Migration guide for users from old YAML payloads to new JSON format can be found here: [link](docs/migration_guide.md).
112 |
113 | # Checkout
114 | SUA links to some 3rd party libraries, which are fetched as submodules, therefore the cloning shall be performed with recursive option:
115 |
116 | ```
117 | git clone --recursive https://github.com/eclipse-leda/leda-contrib-self-update-agent.git
118 | ```
119 | or if was cloned non recursively
120 | ```
121 | git submodule init
122 | git submodule update
123 | ```
124 |
125 | # HowTo Build
126 | Instructions for building are available on: [link](docs/building/README.md)
127 |
128 | # HowTo Deploy
129 | Instructions for deploying are available on: [link](docs/deploying/README.md)
130 |
131 | # HowTo Test
132 | Instructions for testing are available on: [link](docs/testing/README.md)
133 |
--------------------------------------------------------------------------------
/clang-format.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | find src -iname *.h -o -iname *.cpp | xargs clang-format -i
4 |
--------------------------------------------------------------------------------
/cmake/dependencies.cmake:
--------------------------------------------------------------------------------
1 | add_library(curl_lib SHARED IMPORTED)
2 |
3 | if (CMAKE_BUILD_TYPE STREQUAL "Debug")
4 | set_property(
5 | TARGET curl_lib
6 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/3rdparty/curl/lib/libcurl-d.so
7 | )
8 | else ()
9 | set_property(
10 | TARGET curl_lib
11 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/3rdparty/curl/lib/libcurl.so
12 | )
13 | endif()
14 |
15 | add_library(ssl_lib SHARED IMPORTED)
16 | set_property(
17 | TARGET ssl_lib
18 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libssl.so.3
19 | )
20 |
21 | add_library(crypto_lib SHARED IMPORTED)
22 | set_property(
23 | TARGET crypto_lib
24 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/lib/libcrypto.so.3
25 | )
26 |
27 | add_library(gio_lib SHARED IMPORTED)
28 | set_property(
29 | TARGET gio_lib
30 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/glib/gio/libgio-2.0.so
31 | )
32 |
33 | add_library(glib_lib SHARED IMPORTED)
34 | set_property(
35 | TARGET glib_lib
36 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/glib/glib/libglib-2.0.so
37 | )
38 |
39 | add_library(gmodule_lib SHARED IMPORTED)
40 | set_property(
41 | TARGET gmodule_lib
42 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/glib/gmodule/libgmodule-2.0.so
43 | )
44 |
45 | add_library(gobject_lib SHARED IMPORTED)
46 | set_property(
47 | TARGET gobject_lib
48 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/glib/gobject/libgobject-2.0.so
49 | )
50 |
51 | add_library(ffi_lib SHARED IMPORTED)
52 | set_property(
53 | TARGET ffi_lib
54 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/glib/subprojects/libffi/src/libffi.so
55 | )
56 |
57 | add_library(z_lib SHARED IMPORTED)
58 | set_property(
59 | TARGET z_lib
60 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/glib/subprojects/zlib-1.2.11/libz.so
61 | )
62 |
63 | add_library(intl_lib SHARED IMPORTED)
64 | set_property(
65 | TARGET intl_lib
66 | PROPERTY IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/glib/subprojects/proxy-libintl/libintl.so
67 | )
68 |
--------------------------------------------------------------------------------
/cmake/linux/amd64/toolchain.cmake:
--------------------------------------------------------------------------------
1 | set(CMAKE_SYSTEM_NAME Linux)
2 | set(CMAKE_SYSTEM_VERSION 1)
3 |
4 | set(CMAKE_C_COMPILER gcc)
5 | set(CMAKE_CXX_COMPILER g++)
6 |
7 | set(SUA_PLATFORM_LIBS resolv blkid selinux)
8 |
--------------------------------------------------------------------------------
/cmake/linux/arm64/toolchain.cmake:
--------------------------------------------------------------------------------
1 | set(CMAKE_SYSTEM_NAME Linux)
2 | set(CMAKE_SYSTEM_VERSION 1)
3 |
4 | set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc-9)
5 | set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++-9)
6 |
7 | set(SUA_PLATFORM_LIBS resolv)
8 |
--------------------------------------------------------------------------------
/docs/bfb.md:
--------------------------------------------------------------------------------
1 | # Detailed description of bfb (binding-for-backend) communication protocol
2 |
3 | ## Current state message
4 | This is retained message sent by SUA on start-up or as an answer to response for current state (then it is supplied with activityId field).
5 | MQTT Topic: selfupdate/currentstate
6 | ```
7 | {
8 | "activityId": "random-uuid",
9 | "timestamp": 123456789,
10 | "payload": {
11 | "softwareNodes": [
12 | {
13 | "id": "self-update-agent",
14 | "version": "build-42,
15 | "name": "OTA NG Self Update Agent",
16 | "type": "APPLICATION"
17 | },
18 | {
19 | "id": "self-update:leda-deviceimage",
20 | "version": "1.0",
21 | "name": "Official Leda device image",
22 | "type": "IMAGE"
23 | }
24 | ],
25 | "hardwareNodes": [],
26 | "associations": [
27 | {
28 | "sourceId": "self-update-agent",
29 | "targetId": "self-update:leda-deviceimage"
30 | }
31 | ]
32 | }
33 | }
34 | ```
35 |
36 | ## Current state request
37 | This message is a trigger to send back version of installed OS. Can be received at any point of time.
38 | MQTT Topic: selfupdate/currentstate/get
39 | ```
40 | {
41 | "activityId": "random-uuid",
42 | "timestamp": 123456789
43 | }
44 | ```
45 |
46 | ## Desired state
47 | This message indicates that SUA needs to perform an update operation.
48 | MQTT Topic: selfupdate/desiredstate
49 | ```
50 | {
51 | "activityId": "random-uuid",
52 | "timestamp": 123456789,
53 | "payload": {
54 | "domains": [
55 | {
56 | "id": "self-update",
57 | "components": [
58 | {
59 | "id": "os-image",
60 | "version": "1.0",
61 | "config": [
62 | {
63 | "key": "image",
64 | "value": "http://example.com/downloads/os-image-1.1.bin"
65 | }
66 | ]
67 | }
68 | ]
69 | }
70 | ]
71 | }
72 | }
73 | ```
74 |
75 | ## Desired state feedback
76 | This message contains information about SUA state - what agent is doing - installing, downloading or idle.
77 | MQTT Topic: selfupdate/desiredstatefeedback
78 | ```
79 | {
80 | "activityId": "random-uuid",
81 | "timestamp": 123456789,
82 | "payload": {
83 | "status": "payload_status",
84 | "message": "status message as a string",
85 | "actions": [
86 | {
87 | "component": {
88 | "id": "self-update:os-image",
89 | "version": "1.0"
90 | },
91 | "status": "action_status",
92 | "progress": 42,
93 | "message": "action message as a string"
94 | }
95 | ]
96 | }
97 | }
98 | ```
99 |
100 | ## Command for single self-update action/step
101 | This message contains information about SUA action - what must be done as a single step - download, update, activate, cleanup.
102 | MQTT Topic: selfupdate/desiredstate/command
103 | ```
104 | {
105 | "activityId": "random-uuid-as-string",
106 | "timestamp": 123456789,
107 | "payload": {
108 | "baseline": "BASELINE NAME",
109 | "command": "command_type"
110 | }
111 | }
112 | ```
113 |
114 | ## Description of statuses
115 | Following combinations of payload_status and action_status are possible:
116 | | payload_status | action_status | Description |
117 | |-----------------------|------------------|-------------|
118 | | IDENTIFYING | | SUA has received request for update and evaluating it |
119 | | IDENTIFICATION_FAILED | | SUA has received request for update and is unable to perform self-update |
120 | | IDENTIFIED | IDENTIFIED | SUA has received request for update and will try to perform an update |
121 | | DOWNLOADING | DOWNLOADING | Downloading an image |
122 | | DOWNLOAD_SUCCESS | DOWNLOAD_SUCCESS | Image is downloaded without errors |
123 | | DOWNLOAD_FAILURE | DOWNLOAD_FAILURE | Image was not downloaded |
124 | | UPDATING | UPDATING | Installing the downloaded image |
125 | | UPDATE_SUCCESS | UPDATING | Image installed |
126 | | UPDATE_FAILURE | UPDATE_FAILURE | Image was not installed due to error |
127 | | ACTIVATING | UPDATING | SUA is activating the partition with new image |
128 | | ACTIVATION_SUCCESS | UPDATED | SUA has activated the partition with new image |
129 | | ACTIVATION_FAILURE | UPDATE_FAILURE | SUA has failed to activate the partition with new image |
130 | | COMPLETE | UPDATE_SUCCESS | Self-update finished without errors |
131 | | INCOMPLETE | UPDATE_FAILURE
DOWNLOAD_FAILURE | Self-update is incomplete. Action status and action
message will preserve error from one of the previous steps: download/flash/activate.|
132 |
133 | ## Description of command types
134 | | Command | Description |
135 | |----------|-------------|
136 | | DOWNLOAD | Start download of bundle |
137 | | UPDATE | Flash image to partition |
138 | | ACTIVATE | Make 'other' partition bootable |
139 | | CLEANUP | Remove temporary files |
140 |
141 | ## Description of other fields
142 | | Name | Description |
143 | |------------|-------------|
144 | | activityId | Random UUID as string (needs to be taken from desiredstate message and passed back in all feedback messages) |
145 | | timestamp | Epoch time (in seconds since January 1, 1970) |
146 | | version | Reflects version of SUA running on the device, OS version or bundle version |
147 | | progress | Percentage value of download/install progress |
148 |
149 |
--------------------------------------------------------------------------------
/docs/building/README.md:
--------------------------------------------------------------------------------
1 | # Building
2 |
3 | The SUA can be used in both forms:
4 |
5 | - as a native application,
6 | - as an image running inside of a container.
7 |
8 | This section describes the building steps for both variants.
9 |
10 | If the SUA is to be used on the board with a different architecture than the host machine on which it is being built, the cross compilation is necessary.
11 |
12 | # Native
13 |
14 | ## Install prerequisites
15 |
16 | To be able to compile, following libraries and tools have to be installed:
17 |
18 | ### Toolchain
19 |
20 | ```
21 | sudo apt install binutils cmake make autoconf file libtool git build-essential libcurl4-openssl-dev libselinux1-dev libmount-dev libmount1 libblkid-dev
22 | ```
23 |
24 | ### Compilers (for x86_64)
25 |
26 | ```
27 | sudo apt install gcc g++
28 | ```
29 |
30 | ### Compilers (for Raspberry Pi board)
31 |
32 | ```
33 | sudo apt install gcc-9-aarch64-linux-gnu g++-9-aarch64-linux-gnu
34 | ```
35 |
36 | ### Build tool Meson for glib
37 |
38 | ```
39 | sudo apt-get install python3 python3-pip python3-setuptools python3-wheel ninja-build meson
40 | pip3 install meson
41 | ```
42 |
43 | ## Build for amd64 or for arm64
44 |
45 | ```
46 | ./scripts/build.sh amd64
47 | ```
48 | or
49 | ```
50 | ./scripts/build.sh arm64
51 | ```
52 |
53 | ## Run
54 |
55 | The SUA binary will be placed under `dist_amd64/bin` / `dist_arm64/bin`. There is an optional parameter that can be specified: `-p path` location where the the downloaded bundles shall be stored:
56 |
57 | ```
58 | cd dist_amd64/bin
59 | LD_LIBRARY_PATH=../lib ./sdv-self-update-agent
60 | ```
61 |
62 | ```
63 | cd dist_amd64/bin
64 | LD_LIBRARY_PATH=../lib ./sdv-self-update-agent -p /data/download
65 | ```
66 |
67 | ## Hint about usage of devcontainer
68 |
69 | This project provides the `.devcontainer`, which some of required for building tools. You can select the *open in the container* option in VS and this way use predefined development environment, instead of installing all the tools natively. The `.devcontainer` will be also used when you develop in *Codespaces*.
70 |
71 | ### Windows
72 |
73 | If the docker and VS proxy settings are correctly set, the .devcontainer environment shall work on windows out of the box.
74 |
75 | # Containerized
76 |
77 | SUA can be built as multi-arch image, and run inside of the container. This is preferred way of deployment, as it provides a necessary sandbox runtime environment and also allows to easily adjust the configuration settings (ports, ENV variables) via yaml.
78 |
79 | Also the building process is easier, as all necessary tools are provided by the build platform - as also the build itself is being performed inside of the container.
80 |
81 | ## Build multi-arch image
82 |
83 | ### Build and load to local docker registry
84 |
85 | Useful for testing on host machine: (specify only the host's architecture):
86 |
87 | ```
88 | docker buildx build -f Dockerfile.arm64 --progress plain --platform "linux/arm64" -t sua:arm64 --load .
89 | docker buildx build -f Dockerfile.amd64 --progress plain --platform "linux/amd64" -t sua:amd64 --load .
90 | ```
91 |
92 | ### Build and push to remote container registry (ghrc)
93 |
94 | ```
95 | docker buildx build -f Dockerfile.arm64 --progress plain --platform "linux/arm64" -t ghcr.io/softwaredefinedvehicle/sdv-self-update-agent/sua:testing_arm64 --push .
96 | docker buildx build -f Dockerfile.amd64 --progress plain --platform "linux/amd64" -t ghcr.io/softwaredefinedvehicle/sdv-self-update-agent/sua:testing_amd64 --push .
97 | ```
98 |
99 | ### Create multiarch image using remote container registry (ghrc)
100 |
101 | ```
102 | docker buildx imagetools create -t ghcr.io/softwaredefinedvehicle/sdv-self-update-agent/sua:testing ghcr.io/softwaredefinedvehicle/sdv-self-update-agent/sua:testing_arm64 ghcr.io/softwaredefinedvehicle/sdv-self-update-agent/sua:testing_amd64
103 | ```
104 |
105 | ## Run
106 |
107 | ```
108 | docker run -it sua:latest
109 | ```
110 |
--------------------------------------------------------------------------------
/docs/data-privacy-notice.md:
--------------------------------------------------------------------------------
1 | ### Privacy Customer Information
2 |
3 | Your privacy is important to us. The following information is to provide you with all information relevant to data protection in order to be able to use the software, in a data protection compliant manner. It is provided as an information source for your solution-specific data protection and data privacy topics. This is not intended to provide and should not be relied on for legal advice.
4 |
5 | ### Your Role
6 |
7 | First things first: when you choose and use our software, you are most likely acting in the role of data controller, if personal related data is being processed. Therefore, you must ensure that the processing of personal data complies with the respective local legal requirements, e.g. when processing data within the scope of General Data Protection Regulation (GDPR) the legal requirements for a controller from the GDPR.
8 |
9 | ### Where may the processing of personal related data be relevant?
10 |
11 | When using our software in combination with other software components, personal data or data categories may be collected for the purpose of developing, testing and running (in-)Vehicle Applications. Possible examples are the vehicle identification number (VIN), the number plate, GPS data, applications metrics, or other measurement data. You can determine which data or data categories are collected when configuring the software. These data are stored in volatile memory and are deleted by shutting down the system.
12 |
13 | However, you are responsible for the compliant handling of the data in accordance with the applicable local law.
14 |
15 | ### What have we done to make the software data protection friendly?
16 |
17 | This section describes the measures taken to integrate the requirements of the GDPR directly into product development. The technical measures described below follow a "privacy by design" approach.
18 |
19 | ## Authentication
20 | SharedAccessKey as part of the connection string or
21 | Device key and certificated. Depends how the device was registered in Azure IoT Hub
22 | Password control
23 | Customer can configure the local MQTT broker to require user/password authentication. The configuration is preinstalled on the device.
24 | Encryption
25 | Device-to-Cloud and Cloud-to-Device communication is done using MQTT over TLS.
26 | ## Deletion possibility
27 | Local data: The software may save data permanently in local virtual storage (eg when run in QEMU Emulator) or on local physical storage (SD-Card on Raspberry PI). All collected or processed data can be deleted by either deleting the virtual storage file (\*.qcow2), or by erasing the SD-Card.
28 |
29 | ## Cloud storage: The software may send data to cloud endpoints controlled by you or your organization. Examples include connectivity data, device identification, device health, device telemetry, application metrics and application logs. Collection and processing of example data on the device is enabled by default. Sending of device data to cloud endpoints must be explicitly enabled by performing the device provisioning process. The actual cloud endpoints are determined and configured during the device provisioning process. All collected or processed data can be deleted on the cloud side in the respective cloud endpoints.
30 |
31 | ## Vulnerabilities: The release process for this software is set up to always update to the newest package updates. The project will continuously release new versions of the software. To protect personal data, it is advisable to always use the latest version of the software.
32 |
33 | ### Important: When you use the self-update-agent within Eclipse Leda quickstart images for non-volatile setups, it is essential to reconfigure the system and harden it, this includes but is not limited to the following configuration items:
34 |
35 | Disable system user (root) password and login
36 | Disable SSH login with password
37 | Adding a new Linux user with restricted permissions
38 | Adding SSH key based authentication
39 | Kubernetes Resources: Secrets
40 | Device Identity Certificates for Cloud Connection
41 | Access credentials for private Container Registries
42 |
--------------------------------------------------------------------------------
/docs/deploying/README.md:
--------------------------------------------------------------------------------
1 | # Deployment
2 |
3 | # Native
4 |
5 | For the native usage, no special deployment is needed. You can run and test the app as specified in [link](../building/README.md) (native part).
6 |
7 | # Container
8 |
9 | If you want to run the SUA as a service which can receive update requests any time the following [yaml](sua-service.yaml) is available.
10 |
11 | Apply the yaml config with...
12 |
13 | ```
14 | kubectl apply -f sua-service.yaml
15 | ```
16 |
17 | The yaml mounts system_bus_socket to allow access to the host dbus and a shared volume for holding the downloaded update bundle.
18 |
19 | By default the path for holding the downloaded update bundles is assumed to be /data/selfupdates. If you wish to choose another download location then update the yaml file (lines 21 & 40) with your desired path.
20 |
21 | There are also various port settings. You may need to adjust these values to match the setup that you are using.
22 |
--------------------------------------------------------------------------------
/docs/deploying/sua-service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: suaservice
5 | labels:
6 | app: suaservice
7 | spec:
8 | replicas: 1
9 | selector:
10 | matchLabels:
11 | app: suaservice
12 | template:
13 | metadata:
14 | labels:
15 | app: suaservice
16 | spec:
17 | containers:
18 | - name: suaservice
19 | image: ghcr.io/eclipse-leda/leda-contrib-self-update-agent/self-update-agent:latest
20 | command: ["/app/sdv-self-update-agent"]
21 | args: ["-p", "/data/selfupdates"]
22 | imagePullPolicy: IfNotPresent
23 | volumeMounts:
24 | - mountPath: /var/run/dbus/system_bus_socket
25 | name: system-dbus-socket
26 | readOnly: true
27 | - mountPath: /RaucUpdate
28 | name: shared-rauc-vol
29 | ports:
30 | - name: default
31 | containerPort: 50052
32 | protocol: TCP
33 | imagePullSecrets:
34 | - name: ghcr-user
35 | volumes:
36 | - hostPath:
37 | path: /var/run/dbus/system_bus_socket
38 | name: system-dbus-socket
39 | - hostPath:
40 | path: /data/selfupdates
41 | name: shared-rauc-vol
42 | ---
43 | apiVersion: v1
44 | kind: Service
45 | metadata:
46 | name: suaservice-nodeport
47 | spec:
48 | type: NodePort
49 | selector:
50 | app: suaservice
51 | ports:
52 | - port: 50052
53 | targetPort: 50052
54 | nodePort: 30052
55 |
--------------------------------------------------------------------------------
/docs/migration_guide.md:
--------------------------------------------------------------------------------
1 | # Migration guide from YAML payloads to JSON (bfb) protocol
2 |
3 | ## Background
4 | The communication protocol between SUA and backend was extended to support vehicle orchestration for large quantities of devices. Key differences are:
5 | * Transition from YAML to JSON
6 | * Fine-grained API (command-based approach instead of single-shot self-update)
7 | * Extension of statuses (for detailed reflection of success, progress or failure)
8 | Some fields are not relevant anymore meanwhile new were introduced. Below is a brief comparison between messages in YAML and in JSON format.
9 |
10 | ### Transition guide for current state message
11 | From the current state message in YAML payload there is only one field 'bundleVersion' which is relevant. The corresponding field in JSON variant is 'version' in 'softwareNodes' for the device image. *NOTE*: The actual name could differ depending on the distro configuration.
12 | ```
13 | apiVersion: sdv.eclipse.org/v1
14 | kind: SelfUpdateBundle
15 | metadata:
16 | name: "self-update-bundle-example"
17 | spec:
18 | bundleVersion: 1.0
19 | ```
20 |
21 | ```
22 | {
23 | "timestamp": 42,
24 | "payload": {
25 | "softwareNodes": [
26 | {
27 | "id": "self-update-agent",
28 | "version": "build-42",
29 | "name": "OTA NG Self Update Agent",
30 | "type": "APPLICATION"
31 | },
32 | {
33 | "id": "self-update:leda-deviceimage",
34 | "version": "1.0",
35 | "name": "Official Leda device image",
36 | "type": "IMAGE"
37 | }
38 | ],
39 | "hardwareNodes": [],
40 | "associations": [
41 | {
42 | "sourceId": "self-update-agent",
43 | "targetId": "self-update:leda-deviceimage"
44 | }
45 | ]
46 | }
47 | }
48 | ```
49 |
50 | ### Transition guide for desired state message
51 | For the desired state message there are two relevant fields 'bundleDownloadUrl' and 'bundleVersion' for take-over. The corresponding values are 'version' under the 'components' and 'value' inside the object with 'key'='image'. *NOTE*: There could be multiple entries inside 'components' array and 'config' section. Your implementation has to search for 'os-image' and 'image' values respectively.
52 | ```
53 | apiVersion: "sdv.eclipse.org/v1"
54 | kind: SelfUpdateBundle
55 | metadata:
56 | name: self-update-bundle-example
57 | spec:
58 | bundleDownloadUrl: http://url
59 | bundleName: arm64-bundle
60 | bundleTarget: base
61 | bundleVersion: 1.0
62 | ```
63 | ```
64 | {
65 | "activityId": "random-uuid-as-string",
66 | "timestamp": 123456789,
67 | "payload": {
68 | "domains": [
69 | {
70 | "id": "self-update",
71 | "components": [
72 | {
73 | "id": "os-image",
74 | "version": "1.1",
75 | "config": [
76 | {
77 | "key": "image",
78 | "value": "http://example.com/downloads/os-image-1.1.bin"
79 | }
80 | ]
81 | }
82 | ]
83 | }
84 | ]
85 | }
86 | }
87 | ```
88 |
89 | ### Transition guide for state feedback
90 | Below there is an example for state feedback ('techCode' is optional and available only in case of failure). For transition to JSON format all three fields from 'state' section are important (except 'techCode') and their corresponding places in JSON are 'status' and 'message' in sections 'payload' and 'actions', and 'progress' in section 'actions'. The detailed list of the available payload status and action status can be found in [link](docs/bfb.md) because for vehicle orchestration more sub-states were introduced for a fine-grained report of the self-update progress.
91 | ```
92 | apiVersion: sdv.eclipse.org/v1
93 | kind: SelfUpdateBundle
94 | metadata:
95 | name: "self-update-bundle-example"
96 | spec:
97 | bundleDownloadUrl: "http://url"
98 | bundleName: "arm64-bundle"
99 | bundleTarget: base
100 | bundleVersion: 1.0
101 | state:
102 | message: Downloaded 10.0 MiB...
103 | name: downloading
104 | progress: 100
105 | techCode: 42
106 | ```
107 | ```
108 | {
109 | "activityId": "id",
110 | "timestamp": 42,
111 | "payload": {
112 | "status": "ACTIVATION_SUCCESS",
113 | "message": "Self-update agent has activated the new OS image.",
114 | "actions": [
115 | {
116 | "component": {
117 | "id": "self-update:os-image",
118 | "version": "1.0"
119 | },
120 | "status": "UPDATED",
121 | "progress": 0,
122 | "message": "Self-update agent has activated the new OS image."
123 | }
124 | ]
125 | }
126 | }
127 | ```
128 |
--------------------------------------------------------------------------------
/docs/testing/README.md:
--------------------------------------------------------------------------------
1 | # Testing
2 |
3 | In order to be able to test SUA, the proper test environment must be prepared, which would simulate/mock the components with which the SUA is interacting. Depending if the test is being done for the native version od containerized variant, the preparation steps will differ:
4 |
5 | # Native
6 |
7 | For the native variant all tools have to be installed on the host machine:
8 |
9 | ## Preconditions
10 |
11 | 1. Install the mosquitto server and client
12 |
13 | ```
14 | sudo apt-get update
15 | sudo apt-get install mosquitto
16 | sudo apt-get install mosquitto-clients
17 | ```
18 |
19 | 2. Ensure the python3 is installed.
20 |
21 | ## Start MQTT broker
22 |
23 | ```
24 | mosquitto
25 | ```
26 |
27 | ## Adjust the host ip in code
28 |
29 | Set the IP of the machine where the mosquitto broker is running, for the simplest case it would be the `localhost`:
30 |
31 | ```
32 | SoftwareUpdateAgent::SoftwareUpdateAgent()
33 | {
34 | sua::MqttConfiguration conf;
35 | conf.brokerHost = "localhost"
36 | ```
37 |
38 | ## Run native application
39 |
40 | ```
41 | ./sdv-self-update-agent
42 | ```
43 |
44 | ## Host test bundle file
45 |
46 | Ensure that the proper test bundle is put into hosted directory. Adjust the IP and Port as needed.
47 |
48 | ```
49 | cd docs/testing/fileserver/bundle
50 | python3 -m http.server --bind 127.0.0.1 5555
51 | ```
52 |
53 | ## Simulate sending the MQTT Start messages
54 |
55 | The content of the json file shall be adjusted, so that url of hosted bundle is valid.
56 |
57 | ```
58 | mosquitto_pub -t "selfupdate/desiredstate" -f docs/testing/mqtt/start.json
59 | mosquitto_pub -t "selfupdate/desiredstate/command" -f docs/testing/mqtt/command-download.json
60 | ```
61 |
62 | ## Subscribe to MQTT feedback messages
63 |
64 | To test if the SUA is behaving correctly and sending proper mqtt messages, subscribe to the topics:
65 |
66 | ```
67 | mosquitto_sub -t "selfupdate/currentstate"
68 | mosquitto_sub -t "selfupdate/desiredstatefeedback"
69 | ```
70 |
71 | ## Trigger current state request
72 | ```
73 | mosquitto_pub -t "selfupdate/currentstate/get" -f docs/testing/mqtt/current-state-get.json
74 | ```
75 |
76 | # Container
77 |
78 | For testing the container variant, it shall be ensured that all the components are connected to the same network and using proper ports mapping, so that they would be able to communicate with each other.
79 |
80 | ## Create the network
81 |
82 | ```
83 | docker network create -d bridge my-network
84 | ```
85 |
86 | ## Deploy Mosquitto broker
87 |
88 | ```
89 | docker run -it --network=my-network -p 1883:1883 -v /absolute/path/sdv-self-update-agent/docs/testing/mqtt/mosquitto.conf:/mosquitto/config/mosquitto.conf -v /mosquitto/data -v /mosquitto/log --name mosquitto eclipse-mosquitto
90 | ```
91 |
92 | Hint: it is required to use the absolute path to the mosquitto configuration file.
93 |
94 | ## Deploy python http server
95 |
96 | ```
97 | cd docs/testing/fileserver
98 | docker build -t host .
99 | docker run -it --network=my-network -p 5555:5555 --name fileserver host
100 | ```
101 |
102 | The bundle file will be available under: `fileserver:5555/bundle` url, so the value in `start.json` shall be adjusted.
103 |
104 | ## Deploy SUA
105 |
106 | ```
107 | docker run -it --network=my-network sua:latest
108 | ```
109 |
110 | Hint: before building and running sua, ensure that the broker host ia having the same value as the name parameter, specified for mosquitto broker:
111 |
112 | ```
113 | SoftwareUpdateAgent::SoftwareUpdateAgent()
114 | {
115 | sua::MqttConfiguration conf;
116 | conf.brokerHost = "mosquitto"
117 | ...
118 | ```
119 |
120 | # HowTo subscribe to relevant messages
121 |
122 | ```
123 | mosquitto_sub -t "selfupdate/selfupdate/desiredstatefeedback" -h ipAddress_of_mosquitto_container
124 | mosquitto_sub -t "selfupdate/currentstate" -h ipAddress_of_mosquitto_container
125 | ```
126 |
127 | From this tab console we can observe if the SUA is sending proper messages.
128 |
129 | Hint: to figure out the the ip address of mosquitto container, run following command:
130 |
131 | ```
132 | docker container ls // copy the containerID of mosquitto container
133 | docker container inspect containerID
134 | ```
135 |
136 | and locate the `IPAddress` value.
137 |
138 | # HowTo send the Start signal to trigger the process
139 |
140 | ```
141 | mosquitto_pub -t "selfupdate/desiredstate" -f docs/testing/mqtt/start.json -h ipAddress_of_mosquitto_container
142 | ```
143 |
144 | After sending this signal, you should be able to observe the SUA behavior on the console.
145 |
--------------------------------------------------------------------------------
/docs/testing/fileserver/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:latest
2 | COPY bundle/ /
3 | EXPOSE 5555
4 | CMD python3 -m http.server 5555
5 |
--------------------------------------------------------------------------------
/docs/testing/mqtt/command-activate.json:
--------------------------------------------------------------------------------
1 | {
2 | "activityId": "random-uuid-as-string",
3 | "timestamp": 123456789,
4 | "payload": {
5 | "baseline": "BASELINE NAME",
6 | "command": "ACTIVATE"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/testing/mqtt/command-cleanup.json:
--------------------------------------------------------------------------------
1 | {
2 | "activityId": "random-uuid-as-string",
3 | "timestamp": 123456789,
4 | "payload": {
5 | "baseline": "BASELINE NAME",
6 | "command": "CLEANUP"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/testing/mqtt/command-download.json:
--------------------------------------------------------------------------------
1 | {
2 | "activityId": "random-uuid-as-string",
3 | "timestamp": 123456789,
4 | "payload": {
5 | "baseline": "BASELINE NAME",
6 | "command": "DOWNLOAD"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/testing/mqtt/command-rollback.json:
--------------------------------------------------------------------------------
1 | {
2 | "activityId": "random-uuid-as-string",
3 | "timestamp": 123456789,
4 | "payload": {
5 | "baseline": "BASELINE NAME",
6 | "command": "ROLLBACK"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/testing/mqtt/command-update.json:
--------------------------------------------------------------------------------
1 | {
2 | "activityId": "random-uuid-as-string",
3 | "timestamp": 123456789,
4 | "payload": {
5 | "baseline": "BASELINE NAME",
6 | "command": "UPDATE"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/docs/testing/mqtt/current-state-get.json:
--------------------------------------------------------------------------------
1 | {
2 | "activityId": "random-uuid-as-string",
3 | "timestamp": 123456789
4 | }
5 |
--------------------------------------------------------------------------------
/docs/testing/mqtt/mosquitto.conf:
--------------------------------------------------------------------------------
1 | persistence true
2 | persistence_location /mosquitto/data/
3 | log_dest file /mosquitto/log/mosquitto.log
4 | allow_anonymous true
5 | listener 1883 0.0.0.0
--------------------------------------------------------------------------------
/docs/testing/mqtt/start.json:
--------------------------------------------------------------------------------
1 | {
2 | "activityId": "random-uuid-as-string",
3 | "timestamp": 123456789,
4 | "payload": {
5 | "domains": [
6 | {
7 | "id": "self-update",
8 | "components": [
9 | {
10 | "id": "os-image",
11 | "version": "v1beta3",
12 | "config": [
13 | {
14 | "key": "image",
15 | "value": "http://127.0.0.1:5555/bundle"
16 | }
17 | ]
18 | }
19 | ]
20 | }
21 | ]
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/scripts/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | if [ "$1" = "amd64" ]; then
4 | ./scripts/build_openssl_amd64.sh
5 | ./scripts/build_glib_amd64.sh
6 | cd build_amd64
7 | cmake -DCMAKE_INSTALL_PREFIX=../dist_amd64 -DCMAKE_TOOLCHAIN_FILE=../cmake/linux/amd64/toolchain.cmake -DOPENSSL_ROOT_DIR=../build_amd64 -DOPENSSL_CRYPTO_LIBRARY=../build_amd64/lib/libcrypto.so ..
8 | make install
9 | exit 0
10 | fi
11 |
12 | if [ "$1" = "arm64" ]; then
13 | ./scripts/build_openssl_arm64.sh
14 | ./scripts/build_glib_arm64.sh
15 | cd build_arm64
16 | cmake -DCMAKE_INSTALL_PREFIX=../dist_arm64 -DCMAKE_TOOLCHAIN_FILE=../cmake/linux/arm64/toolchain.cmake -DOPENSSL_ROOT_DIR=../build_arm64 -DOPENSSL_CRYPTO_LIBRARY=../build_arm64/lib/libcrypto.so ..
17 | make install
18 | exit 0
19 | fi
20 |
21 | echo "Unknown architecture '$1'"
22 |
23 |
--------------------------------------------------------------------------------
/scripts/build_glib_amd64.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | cd 3rdparty/glib
4 | meson subprojects download > /dev/null
5 | meson setup -Dwrap_mode=forcefallback ../../build_amd64/glib -Druntime_dir=/var/run > /dev/null
6 | meson compile -j `nproc` -C ../../build_amd64/glib > /dev/null
7 |
--------------------------------------------------------------------------------
/scripts/build_glib_arm64.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | cd 3rdparty/glib
4 | meson subprojects download > /dev/null
5 | meson setup -Dwrap_mode=forcefallback -Druntime_dir=/var/run --cross-file=../meson-cross-file-aarch64.txt ../../build_arm64/glib > /dev/null
6 | meson compile -j `nproc` -C ../../build_arm64/glib > /dev/null
7 |
--------------------------------------------------------------------------------
/scripts/build_openssl_amd64.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rootdir=`pwd`
4 | mkdir -p build_amd64/3rdparty/openssl
5 | cd build_amd64/3rdparty/openssl
6 | ./../../../3rdparty/openssl/Configure \
7 | --prefix=$rootdir/build_amd64 \
8 | --openssldir=$rootdir/build_amd64 \
9 | --libdir=lib \
10 | shared \
11 | -Wl,-rpath=$rootdir/build_amd64/lib \
12 | -Wl,--enable-new-dtags > /dev/null
13 | make -j > /dev/null
14 | make install_sw > /dev/null
15 |
--------------------------------------------------------------------------------
/scripts/build_openssl_arm64.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rootdir=`pwd`
4 | mkdir -p build_arm64/3rdparty/openssl
5 | cd build_arm64/3rdparty/openssl
6 | CC=aarch64-linux-gnu-gcc-9 \
7 | CXX=aarch64-linux-gnu-g++-9 \
8 | LD=aarch64-linux-gnu-ld \
9 | AR=aarch64-linux-gnu-ar \
10 | RANLIB=aarch64-linux-gnu-ranlib \
11 | ./../../../3rdparty/openssl/Configure linux-aarch64 \
12 | --prefix=$rootdir/build_arm64 \
13 | --openssldir=$rootdir/build_arm64 \
14 | --libdir=lib \
15 | shared \
16 | -Wl,-rpath=$rootdir/build_arm64/lib \
17 | -Wl,--enable-new-dtags > /dev/null
18 | make -j > /dev/null
19 | make install_sw > /dev/null
20 |
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if(NOT DEFINED SUA_COMMIT_HASH)
2 | execute_process(
3 | COMMAND git describe --always --abbrev=40 --dirty
4 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE SUA_COMMIT_HASH
5 | ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE
6 | )
7 | endif()
8 |
9 | if(NOT DEFINED SUA_BUILD_NUMBER)
10 | set(SUA_BUILD_NUMBER "local")
11 | endif()
12 |
13 | if(SUA_MEASURE_CODE_COVERAGE)
14 | add_compile_options(
15 | -fprofile-arcs
16 | -ftest-coverage
17 | -fPIC
18 | )
19 | endif()
20 |
21 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/version.cpp @ONLY)
22 |
23 | include_directories(
24 | ${CMAKE_SOURCE_DIR}/src
25 | ${CMAKE_SOURCE_DIR}/3rdparty/spdlog/include
26 | ${CMAKE_SOURCE_DIR}/3rdparty/paho.mqtt.c/src
27 | ${CMAKE_SOURCE_DIR}/3rdparty/paho.mqtt.cpp/src
28 | ${CMAKE_SOURCE_DIR}/3rdparty/glib
29 | ${CMAKE_SOURCE_DIR}/3rdparty/glib/glib
30 | ${CMAKE_SOURCE_DIR}/3rdparty/glib/gmodule
31 | ${CMAKE_SOURCE_DIR}/3rdparty/glib/builddir/
32 | ${CMAKE_SOURCE_DIR}/3rdparty/nlohmann-json/include
33 | ${CMAKE_SOURCE_DIR}/3rdparty/curl/include
34 | ${CMAKE_BINARY_DIR}/3rdparty/curl/lib
35 | ${CMAKE_BINARY_DIR}/glib
36 | ${CMAKE_BINARY_DIR}/glib/glib
37 | )
38 |
39 | file(GLOB_RECURSE SRCS *.cpp *.h)
40 | list(FILTER SRCS EXCLUDE REGEX "main.cpp" )
41 | list(APPEND SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.cpp)
42 |
43 | add_library(sua SHARED ${SRCS})
44 | set_target_properties(sua PROPERTIES LINK_FLAGS -s)
45 |
46 | add_executable(${PROJECT_NAME} ${SRCS} main.cpp)
47 | set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS -s)
48 |
49 | link_directories(${CMAKE_BINARY_DIR}/3rdparty/curl/lib)
50 |
51 | target_link_libraries(${PROJECT_NAME}
52 | curl_lib
53 | paho-mqttpp3
54 | paho-mqtt3a
55 | gio_lib
56 | gobject_lib
57 | gmodule_lib
58 | glib_lib
59 | ffi_lib
60 | z_lib
61 | intl_lib
62 | ${SUA_PLATFORM_LIBS}
63 | ssl_lib
64 | crypto_lib
65 | sua
66 | )
67 |
68 | if(SUA_MEASURE_CODE_COVERAGE)
69 | target_link_libraries(sua gcov)
70 | endif()
71 |
72 | install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
73 | install(TARGETS sua LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
74 |
75 |
--------------------------------------------------------------------------------
/src/Context.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #ifndef SDV_SUA_CONTEXT_H
18 | #define SDV_SUA_CONTEXT_H
19 |
20 | #include "FSM/FSM.h"
21 | #include "Download/IDownloader.h"
22 | #include "Install/IRaucInstaller.h"
23 | #include "Mqtt/IMqttMessagingProtocol.h"
24 | #include "Mqtt/IMqttProcessor.h"
25 | #include "Utils/IBundleChecker.h"
26 | #include "Defaults.h"
27 |
28 | #include
29 |
30 | namespace sua {
31 |
32 | struct DesiredState {
33 | std::string activityId;
34 | std::string bundleVersion;
35 | std::string bundleDownloadUrl;
36 |
37 | std::map metadata;
38 |
39 | uint64_t downloadBytesTotal = 0;
40 | uint64_t downloadBytesDownloaded = 0;
41 | int downloadProgressPercentage = 0;
42 | int installProgressPercentage = 0;
43 |
44 | std::string actionStatus = "";
45 | std::string actionMessage = "";
46 | };
47 |
48 | struct CurrentState {
49 | std::string version;
50 | };
51 |
52 | struct Context {
53 | std::shared_ptr stateMachine;
54 | std::shared_ptr downloaderAgent;
55 | std::shared_ptr installerAgent;
56 | std::shared_ptr messagingProtocol;
57 | std::shared_ptr mqttProcessor;
58 | std::shared_ptr bundleChecker;
59 | std::string updatesDirectory = SUA_DEFAULT_TEMP_DIRECTORY;
60 | std::string tempFileName = "/temp_file";
61 | std::string caDirectory = SUA_DEFAULT_CA_DIRECTORY;
62 | std::string caFilepath = SUA_DEFAULT_CA_FILEPATH;
63 | bool downloadMode = true;
64 | bool fallbackMode = false;
65 | int feedbackInterval = SUA_DEFAULT_FEEDBACK_INTERVAL; // seconds
66 |
67 | DesiredState desiredState;
68 | CurrentState currentState;
69 | };
70 |
71 | struct Command {
72 | std::string activityId;
73 | FotaEvent event;
74 | };
75 |
76 | } // namespace sua
77 |
78 | #endif
79 |
--------------------------------------------------------------------------------
/src/Defaults.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #include "Defaults.h"
18 |
19 | const std::string SUA_DEFAULT_MQTT_PROTOCOL = "tcp";
20 | const std::string SUA_DEFAULT_MQTT_HOST = "mosquitto";
21 | const int SUA_DEFAULT_MQTT_PORT = 1883;
22 | const std::string SUA_DEFAULT_MQTT_SERVER = "tcp://mosquitto:1883";
23 | const std::string SUA_DEFAULT_MODE = "download";
24 | const std::string SUA_DEFAULT_TEMP_DIRECTORY = "/data/selfupdates";
25 | const std::string SUA_DEFAULT_CA_DIRECTORY = "/etc/ssl/certs";
26 | const std::string SUA_DEFAULT_CA_FILEPATH = "";
27 | const int SUA_DEFAULT_FEEDBACK_INTERVAL = 5;
28 |
--------------------------------------------------------------------------------
/src/Defaults.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #ifndef SDV_SUA_DEFAULTS_H
18 | #define SDV_SUA_DEFAULTS_H
19 |
20 | #include
21 |
22 | extern const std::string SUA_DEFAULT_MQTT_PROTOCOL;
23 | extern const std::string SUA_DEFAULT_MQTT_HOST;
24 | extern const int SUA_DEFAULT_MQTT_PORT;
25 | extern const std::string SUA_DEFAULT_MQTT_SERVER;
26 | extern const std::string SUA_DEFAULT_MODE;
27 | extern const std::string SUA_DEFAULT_TEMP_DIRECTORY;
28 | extern const std::string SUA_DEFAULT_CA_DIRECTORY;
29 | extern const std::string SUA_DEFAULT_CA_FILEPATH;
30 | extern const int SUA_DEFAULT_FEEDBACK_INTERVAL; // seconds
31 |
32 | #endif
33 |
--------------------------------------------------------------------------------
/src/Download/Downloader.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #ifndef SDV_SUA_DOWNLOADER_H
18 | #define SDV_SUA_DOWNLOADER_H
19 |
20 | #include "IDownloader.h"
21 |
22 | namespace sua {
23 |
24 | class Downloader : public IDownloader
25 | {
26 | public:
27 | Downloader(class Context & context);
28 |
29 | static const std::string EVENT_DOWNLOADING;
30 |
31 | DownloadResult start(const std::string & input) override;
32 |
33 | private:
34 | class Context & _context;
35 | };
36 |
37 | } // namespace sua
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/src/Download/IDownloader.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #ifndef SDV_SUA_IDOWNLOADER_H
18 | #define SDV_SUA_IDOWNLOADER_H
19 |
20 | #include "TechCodes.h"
21 |
22 | #include
23 | #include
24 |
25 | namespace sua {
26 |
27 | using DownloadResult = std::tuple;
28 |
29 | class IDownloader {
30 | public:
31 | virtual ~IDownloader() = default;
32 |
33 | virtual DownloadResult start(const std::string & input) = 0;
34 | };
35 |
36 | } // namespace sua
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/src/FSM/FSM.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #include "FSM/FSM.h"
18 | #include "FSM/States/Uninitialized.h"
19 | #include "Logger.h"
20 |
21 | namespace sua {
22 |
23 | FSM::FSM(Context & context)
24 | : _context(context)
25 | { }
26 |
27 | void FSM::transitTo(const std::string& name)
28 | {
29 | assert(_factory != nullptr);
30 |
31 | if(_currentState) {
32 | Logger::trace("Leave state '{}'", _currentState->name());
33 | _currentState->onLeave(_context);
34 | }
35 |
36 | _currentState = _factory->createState(name);
37 |
38 | Logger::trace("Enter state '{}'", _currentState->name());
39 | _currentState->onEnter(_context);
40 | }
41 |
42 | std::string FSM::activeState() const
43 | {
44 | assert(_currentState != nullptr);
45 |
46 | return _currentState->name();
47 | }
48 |
49 | void FSM::setFactory(std::shared_ptr factory)
50 | {
51 | _factory = factory;
52 | }
53 |
54 | void FSM::setTransitions(std::initializer_list table)
55 | {
56 | _transitions = table;
57 | }
58 |
59 | void FSM::handleEvent(const FotaEvent e)
60 | {
61 | Logger::trace("Received event '{}'", toString(e));
62 |
63 | FotaEvent output = FotaEvent::NotUsed;
64 | bool output_set = false;
65 |
66 | for(const auto& t : _transitions) {
67 | if(t.from != activeState()) {
68 | continue;
69 | }
70 |
71 | if(t.when != e) {
72 | continue;
73 | }
74 |
75 | if(t.output == FotaEvent::NotUsed) {
76 | if(activeState() != t.to) {
77 | transitTo(t.to);
78 | }
79 | break;
80 | }
81 |
82 | if(!output_set) {
83 | output = _currentState->body(_context);
84 | output_set = true;
85 | }
86 |
87 | if(t.output == output) {
88 | if(activeState() != t.to) {
89 | transitTo(t.to);
90 | }
91 | break;
92 | }
93 | }
94 | }
95 |
96 | } // namespace sua
97 |
--------------------------------------------------------------------------------
/src/FSM/FSM.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #ifndef SDV_SUA_FSM_H
18 | #define SDV_SUA_FSM_H
19 |
20 | #include "StateFactory.h"
21 | #include "FotaEvent.h"
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | namespace sua {
29 |
30 | struct FSMTransition {
31 | FotaEvent when;
32 | std::string from;
33 | std::string to;
34 | FotaEvent output = FotaEvent::NotUsed;
35 | };
36 |
37 | class FSM {
38 | public:
39 | FSM(class Context & context);
40 |
41 | void handleEvent(FotaEvent e);
42 |
43 | virtual void transitTo(const std::string& name);
44 | std::string activeState() const;
45 |
46 | void setFactory(std::shared_ptr factory);
47 | void setTransitions(std::initializer_list table);
48 |
49 | private:
50 | Context & _context;
51 |
52 | std::shared_ptr _currentState;
53 | std::shared_ptr _factory;
54 | std::vector _transitions;
55 | };
56 | } // namespace sua
57 |
58 | #endif
59 |
--------------------------------------------------------------------------------
/src/FSM/State.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #include "FSM/State.h"
18 | #include "Context.h"
19 |
20 | namespace sua {
21 |
22 | State::State(const std::string& name)
23 | : _name(name)
24 | { }
25 |
26 | const std::string& State::name() const
27 | {
28 | return _name;
29 | }
30 |
31 | FotaEvent State::body(Context& /*ctx*/)
32 | {
33 | return FotaEvent::NotUsed;
34 | }
35 |
36 | void State::send(Context& ctx, const std::string& topic, MqttMessage message_type, bool retained)
37 | {
38 | ctx.mqttProcessor->send(topic, message_type, "", retained);
39 | }
40 |
41 | void State::send(Context& ctx, const std::string& topic, MqttMessage message_type, const std::string& message, bool retained)
42 | {
43 | ctx.mqttProcessor->send(topic, message_type, message, retained);
44 | }
45 |
46 | } // namespace sua
47 |
--------------------------------------------------------------------------------
/src/FSM/State.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #ifndef SDV_SUA_STATE_H
18 | #define SDV_SUA_STATE_H
19 |
20 | #include "FotaEvent.h"
21 | #include "Mqtt/MqttMessage.h"
22 |
23 | namespace sua {
24 |
25 | class Context;
26 |
27 | class State {
28 | public:
29 | State(const std::string& name = "");
30 |
31 | virtual ~State() = default;
32 |
33 | const std::string& name() const;
34 |
35 | virtual void onEnter(Context& ctx) {}
36 | virtual void onLeave(Context& ctx) {}
37 |
38 | virtual FotaEvent body(Context& ctx);
39 |
40 | void send(Context& ctx, const std::string& topic, MqttMessage message_type, bool retained = false);
41 | void send(Context& ctx, const std::string& topic, MqttMessage message_type, const std::string& message, bool retained = false);
42 |
43 | private:
44 | std::string _name;
45 | };
46 |
47 | } // namespace sua
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/FSM/StateFactory.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #include "StateFactory.h"
18 | #include "State.h"
19 |
20 | #include
21 |
22 | namespace sua {
23 |
24 | std::shared_ptr StateFactory::createState(const std::string& name)
25 | {
26 | auto it = _states.find(name);
27 |
28 | if(it == _states.end()) {
29 | throw std::logic_error("Unknown state '" + name + "'");
30 | }
31 |
32 | return it->second();
33 | }
34 |
35 | } // namespace sua
36 |
--------------------------------------------------------------------------------
/src/FSM/StateFactory.h:
--------------------------------------------------------------------------------
1 | // Copyright 2023 Contributors to the Eclipse Foundation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | // SPDX-License-Identifier: Apache-2.0
16 |
17 | #ifndef SDV_SUA_STATEFACTORY_H
18 | #define SDV_SUA_STATEFACTORY_H
19 |
20 | #include
21 | #include