Co-authored-by: Pierrick Arsenault <pierrick.arsenault@stello.ca>
Co-authored-by: Nox-MSFT <55153324+Nox-MSFT@users.noreply.github.com>
Co-authored-by: Jeff Miller <jeffmill@microsoft.com>
Co-authored-by: Esha Shah <92388818+eshashah-msft@users.noreply.github.com>
Co-authored-by: Takashi Matsuoka <matsujirushi@live.jp>
Co-authored-by: jw-msft <84477130+jw-msft@users.noreply.github.com>
Co-authored-by: Andrew Brown <59940770+andrewbrownmsft@users.noreply.github.com>
Co-authored-by: Shiyi Peng <shiyipeng@microsoft.com>
Co-authored-by: shiyi-peng <71347127+shiyi-peng@users.noreply.github.com>
Co-authored-by: Nicholas Hemstreet <62158276+nihemstr@users.noreply.github.com>
Co-authored-by: JoergZeidler <62105035+JoergZeidler@users.noreply.github.com>
This commit is contained in:
shiyi-peng 2023-02-08 15:03:44 -08:00 коммит произвёл GitHub
Родитель 79ce3ba24c
Коммит 2d1f03671d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
71 изменённых файлов: 751 добавлений и 2708 удалений

Просмотреть файл

@ -47,7 +47,7 @@ set_cache_with_env_or_default (
set_cache_with_env_or_default (
ADUC_VERSION_PATCH
"1"
"2"
STRING
"The patch part of the semantic version")
@ -242,7 +242,7 @@ set (
set (
ADUC_PLATFORM_LAYER
"linux"
CACHE STRING "The platform layer to use. Options: simulator linux")
CACHE STRING "The platform layer to use. Options: linux")
# By default ADU Agent daemon runs as root.
# root user home directory should be /root.

Просмотреть файл

@ -1,71 +1,70 @@
variables:
version.major: 1
version.minor: 0
version.patch: 0
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "amd64"
version.major: 1
version.minor: 0
version.patch: 2
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "amd64"
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
name: $(version.major).$(version.minor).$(version.patch)-$(version.pre-release)+$(version.build)
resources:
- repo: self
- repo: self
trigger:
branches:
include:
- main
- release/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
branches:
include:
- main
- develop
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
pr:
branches:
include:
- main
- release/*
# - feature/*
#- dev/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
branches:
include:
- main
- develop
- feature/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
jobs:
- job: BuildAduAgent
displayName: "Build ADU Agent"
timeoutInMinutes: 360
cancelTimeoutInMinutes: 360
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: 'debian10'
targetArch: 'amd64'
- job: BuildAduAgent
displayName: "Build ADU Agent"
timeoutInMinutes: 360
cancelTimeoutInMinutes: 360
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: "debian10"
targetArch: "amd64"

Просмотреть файл

@ -1,72 +1,71 @@
variables:
version.major: 1
version.minor: 0
version.patch: 0
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
version.major: 1
version.minor: 0
version.patch: 2
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "arm32"
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "arm32"
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
name: $(version.major).$(version.minor).$(version.patch)-$(version.pre-release)+$(version.build)
resources:
- repo: self
- repo: self
trigger:
branches:
include:
- main
# - release/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
branches:
include:
- main
- develop
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
pr:
branches:
include:
- main
- release/*
# - feature/*
#- dev/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
branches:
include:
- main
- develop
- feature/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
jobs:
- job: BuildAduAgent_debian10
displayName: "Build ADU Agent - Debian 10"
timeoutInMinutes: 360
cancelTimeoutInMinutes: 360
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: 'debian10'
targetArch: 'arm32'
- job: BuildAduAgent_debian10
displayName: "Build ADU Agent - Debian 10"
timeoutInMinutes: 360
cancelTimeoutInMinutes: 360
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: "debian10"
targetArch: "arm32"

Просмотреть файл

@ -1,71 +1,70 @@
variables:
version.major: 1
version.minor: 0
version.patch: 0
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "amd64"
version.major: 1
version.minor: 0
version.patch: 2
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "amd64"
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
name: $(version.major).$(version.minor).$(version.patch)-$(version.pre-release)+$(version.build)
resources:
- repo: self
- repo: self
trigger:
branches:
include:
- main
- release/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
branches:
include:
- main
- develop
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
pr:
branches:
include:
- main
- release/*
# - feature/*
#- dev/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
branches:
include:
- main
- develop
- feature/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
jobs:
- job: BuildAduAgent
displayName: "Build ADU Agent"
timeoutInMinutes: 360
cancelTimeoutInMinutes: 360
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: 'debian10'
targetArch: 'arm64'
- job: BuildAduAgent
displayName: "Build ADU Agent"
timeoutInMinutes: 360
cancelTimeoutInMinutes: 360
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: "debian10"
targetArch: "arm64"

Просмотреть файл

@ -1,85 +1,83 @@
variables:
version.major: 1
version.minor: 0
version.patch: 0
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
version.major: 1
version.minor: 0
version.patch: 2
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "amd64"
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "amd64"
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
name: $(version.major).$(version.minor).$(version.patch)-$(version.pre-release)+$(version.build)
resources:
- repo: self
- repo: self
trigger:
branches:
include:
- main
- release/*
- feature/*
- dev/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
branches:
include:
- main
- develop
- feature/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
pr:
branches:
include:
- main
- release/*
- feature/*
- dev/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
- licenses/*
branches:
include:
- main
- develop
- feature/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
- licenses/*
jobs:
- job: BuildAduAgent_ubuntu1804
displayName: "Build ADU Agent - Ubuntu 18.04 (amd64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: 'ubuntu1804'
targetArch: 'amd64'
- job: BuildAduAgent_ubuntu1804
displayName: "Build ADU Agent - Ubuntu 18.04 (amd64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: aduc_1es_client_pool
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: "ubuntu1804"
targetArch: "amd64"
- job: BuildAduAgent_ubuntu2004
displayName: "Build ADU Agent - Ubuntu 20.04 (amd64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: 1es_hosted_pool_ubuntu2004
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: 'ubuntu2004'
targetArch: 'amd64'
- job: BuildAduAgent_ubuntu2004
displayName: "Build ADU Agent - Ubuntu 20.04 (amd64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: 1es_hosted_pool_ubuntu2004
steps:
- template: ../templates/adu-docker-build-steps.yml
parameters:
targetOs: "ubuntu2004"
targetArch: "amd64"

Просмотреть файл

@ -1,83 +1,81 @@
variables:
version.major: 1
version.minor: 0
version.patch: 0
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "arm64"
version.major: 1
version.minor: 0
version.patch: 2
version.pre-release: ""
version.build: $[format('{0:yyyyMMdd}-{0:HHmmss}', pipeline.startTime)]
# Environment variables for all client builds:
ADUC_VERSION_MAJOR: $(version.major)
ADUC_VERSION_MINOR: $(version.minor)
ADUC_VERSION_PATCH: $(version.patch)
ADUC_VERSION_PRERELEASE: $(version.pre-release)
ADUC_VERSION_BUILD: $(version.build)
ADUC_DEBIAN_PACKAGE_ARCHITECTURE: "arm64"
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
ENABLE_ADU_TELEMETRY_REPORTING: true
# ADUC_BUILDER_IDENTIFIER will be set to "DU" short for Device Update by default, for Device Update-sourced builder
ADUC_BUILDER_IDENTIFIER: DU
# DO requires gcc greater than 6 for c++17 support.
# gcc-8 matches what is built with poky warrior.
CC: gcc-8
CXX: g++-8
name: $(version.major).$(version.minor).$(version.patch)-$(version.pre-release)+$(version.build)
resources:
- repo: self
- repo: self
trigger:
branches:
include:
- main
- release/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
branches:
include:
- main
- develop
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- docker/*
pr:
branches:
include:
- main
- release/*
# - feature/*
#- dev/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
branches:
include:
- main
- develop
- feature/*
paths:
exclude:
- docs/*
- README.md
- LICENSE.md
- .clang-format
- .cmake-format.json
- tools/*
- docker/*
- scripts/*
- licenses/*
jobs:
- job: BuildAduAgent_ubuntu2004
displayName: "Build ADU Agent - Ubuntu 20.04 (arm64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: ubuntu2004_arm_pool
steps:
- template: ../templates/adu-native-build-steps.yml
parameters:
targetOs: 'ubuntu2004'
targetArch: 'arm64'
- job: BuildAduAgent_ubuntu2004
displayName: "Build ADU Agent - Ubuntu 20.04 (arm64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: ubuntu2004_arm_pool
steps:
- template: ../templates/adu-native-build-steps.yml
parameters:
targetOs: "ubuntu2004"
targetArch: "arm64"
- job: BuildAduAgent_ubuntu1804
displayName: "Build ADU Agent - Ubuntu 18.04 (arm64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: ubuntu1804_arm_pool
steps:
- template: ../templates/adu-native-build-steps.yml
parameters:
targetOs: 'ubuntu1804'
targetArch: 'arm64'
- job: BuildAduAgent_ubuntu1804
displayName: "Build ADU Agent - Ubuntu 18.04 (arm64)"
timeoutInMinutes: 60
cancelTimeoutInMinutes: 60
pool: ubuntu1804_arm_pool
steps:
- template: ../templates/adu-native-build-steps.yml
parameters:
targetOs: "ubuntu1804"
targetArch: "arm64"

Просмотреть файл

@ -2,14 +2,7 @@
## What's A Content Handler Extension
Device Update has previously supported four reference Device Update Agent binaries, each designed to work with only 1 Update Type:
- An agent that supports 'microsoft/swupdate:1' update type
- An agent that supports 'microsoft/apt:1' update type
- A simulator agent that supports 'microsoft/swupdate:1' update type
- A simulator agent that supports 'microsoft/apt:1' update type
The Public Preview refresh Agent supports an Update Content Handler extension, which enables the Agent to support multiple Update Types at the same time.
Device Update agent supports an Update Content Handler (a.k.a, Step Handler) extension, which enables the Agent to support multiple Update Types at the same time.
Device builders can define a custom Update Type, implement the associated custom Update Content Handler, and register it, if needed for their additional device updates and deployment scenarios.
@ -20,7 +13,7 @@ Device builders can define a custom Update Type, implement the associated custom
```c
/**
* @brief Instantiates an Update Content Handler simulator.
* @brief Instantiates an Update Content Handler.
* @return A pointer to an instantiated Update Content Handler object.
*/
ContentHandler* CreateUpdateContentHandlerExtension(ADUC_LOG_SEVERITY logLevel);

Просмотреть файл

@ -156,7 +156,7 @@ The following is an example of how to simulate all download succeeded:
```json
"download" : {
"*" : { // A fall back result for all unmatched file names
"resultCode" : 600, // ADUC_Result_Download_Success
"resultCode" : 500, // ADUC_Result_Download_Success
"extendedResultCode" : 0, // No extended result
"resultDetails" : ""
}

Просмотреть файл

@ -295,11 +295,7 @@ fi
# Set default log dir if not specified.
if [[ $adu_log_dir == "" ]]; then
if [[ $platform_layer == "simulator" ]]; then
adu_log_dir=/tmp/aduc-logs
else
adu_log_dir=$default_log_dir
fi
adu_log_dir=$default_log_dir
fi
runtime_dir=${output_directory}/bin

Просмотреть файл

@ -72,7 +72,7 @@ install_githooks=false
du_test_data_dir_path="/tmp/adu/"
# DO Deps
default_do_ref=v1.0.0
default_do_ref=v1.0.1
install_do=false
do_ref=$default_do_ref

Просмотреть файл

@ -9,6 +9,14 @@ if (ADUC_WARNINGS_AS_ERRORS)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
endif ()
if (NOT WIN32)
# Avoids readdir returning errno 75 EOVERFLOW when running
# 32-bit ARM docker/qemu on top of 64-bit host by using this
# glibc-specific macro. See https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FILE_OFFSET_BITS=64")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FILE_OFFSET_BITS=64")
endif ()
set (COMPILER_HARDENING_FLAGS
"-fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-strong -Wformat -Werror=format-security")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -z relro -z now")

Просмотреть файл

@ -1169,14 +1169,21 @@ static void CallDownloadHandlerOnUpdateWorkflowCompleted(const ADUC_WorkflowHand
for (size_t i = 0; i < payloadCount; ++i)
{
ADUC_Result result = {};
ADUC_FileEntity* fileEntity = NULL;
if (!workflow_get_update_file(workflowHandle, i, &fileEntity) || IsNullOrEmpty(fileEntity->DownloadHandlerId))
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
if (!workflow_get_update_file(workflowHandle, i, &fileEntity))
{
continue;
}
if (IsNullOrEmpty(fileEntity.DownloadHandlerId))
{
ADUC_FileEntity_Uninit(&fileEntity);
continue;
}
// NOTE: do not free the handle as it is owned by the DownloadHandlerFactory.
DownloadHandlerHandle* handle = ADUC_DownloadHandlerFactory_LoadDownloadHandler(fileEntity->DownloadHandlerId);
DownloadHandlerHandle* handle = ADUC_DownloadHandlerFactory_LoadDownloadHandler(fileEntity.DownloadHandlerId);
if (handle == NULL)
{
Log_Error("Failed to load download handler.");
@ -1194,6 +1201,8 @@ static void CallDownloadHandlerOnUpdateWorkflowCompleted(const ADUC_WorkflowHand
workflow_set_success_erc(workflowHandle, result.ExtendedResultCode);
}
}
ADUC_FileEntity_Uninit(&fileEntity);
}
}

Просмотреть файл

@ -143,11 +143,11 @@ target_compile_definitions (
DO_FILE_USER="${DO_FILE_USER}"
SYSLOG_FILE_GROUP="${SYSLOG_FILE_GROUP}")
if (ADUC_PLATFORM_LAYER STREQUAL "simulator")
target_compile_definitions (${target_name} PRIVATE ADUC_PLATFORM_SIMULATOR)
else ()
if (ADUC_PLATFORM_LAYER STREQUAL "linux")
find_package (deliveryoptimization_sdk CONFIG REQUIRED)
target_link_libraries (${target_name} PRIVATE Microsoft::deliveryoptimization)
else ()
message (FATAL_ERROR "Invalid platform layer specified: ${ADUC_PLATFORM_LAYER}")
endif ()
target_link_libraries (${target_name} PRIVATE aduc::platform_layer)

Просмотреть файл

@ -46,14 +46,11 @@ target_compile_definitions (
ADUC_VERSION="${ADUC_VERSION}"
ADUC_BUILDER_IDENTIFIER="${ADUC_BUILDER_IDENTIFIER}")
if (NOT
ADUC_PLATFORM_LAYER
STREQUAL
"simulator")
if (ADUC_PLATFORM_LAYER STREQUAL "linux")
find_package (deliveryoptimization_sdk CONFIG REQUIRED)
target_link_libraries (${PROJECT_NAME} PRIVATE Microsoft::deliveryoptimization)
else ()
target_compile_definitions (${PROJECT_NAME} PRIVATE ADUC_PLATFORM_SIMULATOR)
message (FATAL_ERROR "Invalid platform layer specified: ${ADUC_PLATFORM_LAYER}")
endif ()
if (ENABLE_ADU_TELEMETRY_REPORTING)

Просмотреть файл

@ -120,7 +120,7 @@ void ADUC_WorkflowData_Uninit(ADUC_WorkflowData* workflowData)
/**
* @brief Reports the client json via PnP so it ends up in the reported section of the twin.
*
* @param messageType The message type.`
* @param messageType The message type.
* @param json_value The json value to be reported.
* @param workflowData The workflow data.
* @return bool true if call succeeded.

Просмотреть файл

@ -9,10 +9,7 @@
#include "device_properties.h"
#include <aduc/logging.h>
#include <aduc/types/update_content.h>
#ifndef ADUC_PLATFORM_SIMULATOR // DO is not used in sim mode
# include <do_config.h>
#endif
#include <do_config.h>
#include <stdlib.h>
@ -180,7 +177,6 @@ bool DeviceProperties_AddVersions(JSON_Object* devicePropsObj)
goto done;
}
#ifndef ADUC_PLATFORM_SIMULATOR
do_version = deliveryoptimization_get_components_version();
if (do_version == NULL)
@ -197,7 +193,6 @@ bool DeviceProperties_AddVersions(JSON_Object* devicePropsObj)
"Could not serialize JSON field: %s value: %s", ADUCITF_FIELDNAME_DEVICEPROPERTIES_DO_VERSION, do_version);
goto done;
}
#endif
success = true;

Просмотреть файл

@ -105,16 +105,6 @@ done:
return validInfo;
}
/**
* @brief Helper function for simulating an unhealthy state.
*
* @return true if an ADU configuration file contains simulateUnhealthyState value (any value).
*/
bool IsSimulatingUnhealthyState(ADUC_ConfigInfo* config)
{
return config->simulateUnhealthyState;
}
/**
* @brief Reports which required users do not exist.
* @remark Goes through the whole list of users to trace any that are missing.
@ -600,14 +590,6 @@ bool HealthCheck(const ADUC_LaunchArguments* launchArgs)
goto done;
}
#ifdef ADUC_PLATFORM_SIMULATOR
if (IsSimulatingUnhealthyState(&config))
{
Log_Error("Simulating an unhealthy state.");
goto done;
}
#endif
isHealthy = true;
done:

Просмотреть файл

@ -28,14 +28,10 @@
#include <azure_c_shared_utility/shared_util_options.h>
#include <azure_c_shared_utility/threadapi.h> // ThreadAPI_Sleep
#include <ctype.h>
#ifndef ADUC_PLATFORM_SIMULATOR // DO is not used in sim mode
# include "aduc/connection_string_utils.h"
# include <do_config.h>
#endif
#include <do_config.h>
#include <diagnostics_devicename.h>
#include <diagnostics_interface.h>
#include <getopt.h>
#include <iothub.h>
#include <iothub_client_options.h>
#include <pnp_protocol.h>
@ -1286,7 +1282,5 @@ done:
ShutdownAgent();
IoTHub_Deinit();
return ret;
}

Просмотреть файл

@ -28,7 +28,7 @@ typedef void (*ADUC_COMMUNICATION_MANAGER_CLIENT_HANDLE_UPDATED_CALLBACK)(ADUC_C
* @param client_handle_updated_callback A pointer to a callback function to be invoked when a device client handler has changed.
* @param property_update_context An ADUC_PnPComponentClient_PropertyUpdate_Context object.
*
* @return 'true' if success, 'false' if already initialize.
* @return 'true' if success.
*/
bool IoTHub_CommunicationManager_Init(ADUC_ClientHandle* handle_address,
IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK device_twin_callback,

Просмотреть файл

@ -52,6 +52,11 @@ static ADUC_COMMUNICATION_MANAGER_CLIENT_HANDLE_UPDATED_CALLBACK g_iothub_client
*/
static IOTHUB_CLIENT_DEVICE_TWIN_CALLBACK g_device_twin_callback = NULL;
/**
* @brief A boolean indicates whether the IoT Hub client has been initialized.
*/
static bool g_iothub_client_initialized = false;
/**
* @brief An additional data context used the caller.
*/
@ -106,7 +111,7 @@ static time_t GetTimeSinceEpochInSeconds()
* @param client_handle_updated_callback A pointer to a callback function to be invoked when a device client handler has changed.
* @param property_update_context An ADUC_PnPComponentClient_PropertyUpdate_Context object.
*
* @return 'true' if success, 'false' if already initialize.
* @return 'true' if success.
*/
bool IoTHub_CommunicationManager_Init(
ADUC_ClientHandle* handle_address,
@ -114,8 +119,18 @@ bool IoTHub_CommunicationManager_Init(
ADUC_COMMUNICATION_MANAGER_CLIENT_HANDLE_UPDATED_CALLBACK client_handle_updated_callback,
ADUC_PnPComponentClient_PropertyUpdate_Context* property_update_context)
{
if (g_aduc_client_handle_address != NULL)
IOTHUB_CLIENT_RESULT iothubInitResult;
if (g_iothub_client_initialized)
{
Log_Info("Already initialized.");
return true;
}
// Before invoking ANY IoTHub Device SDK functionality, IoTHub_Init must be invoked.
if ((iothubInitResult = IoTHub_Init()) != 0)
{
Log_Error("IoTHub_Init failed. Error=%d", iothubInitResult);
return false;
}
@ -123,6 +138,7 @@ bool IoTHub_CommunicationManager_Init(
g_device_twin_callback = device_twin_callback;
g_property_update_context = property_update_context;
g_iothub_client_handle_changed_callback = client_handle_updated_callback;
g_iothub_client_initialized = true;
return true;
}
@ -148,6 +164,13 @@ void IoTHub_CommunicationManager_Deinit()
if (g_aduc_client_handle_address != NULL && *g_aduc_client_handle_address != NULL)
{
ClientHandle_Destroy(*g_aduc_client_handle_address);
g_aduc_client_handle_address = NULL;
}
if (g_iothub_client_initialized)
{
IoTHub_Deinit();
g_iothub_client_initialized = false;
}
}
@ -716,6 +739,10 @@ static void Connection_Maintenance()
case IOTHUB_CLIENT_CONNECTION_OK:
// No need to retry.
return;
default:
Log_Debug("unhandled g_connection_status_reason case: %d", g_connection_status_reason);
break;
}
// Calculate the next retry time, then continue.

Просмотреть файл

@ -4,7 +4,7 @@ include (agentRules)
compileasc99 ()
add_library (${PROJECT_NAME} SHARED contoso_component_enumerator.cpp)
add_library (${PROJECT_NAME} MODULE contoso_component_enumerator.cpp)
find_package (Parson REQUIRED)

Просмотреть файл

@ -4,7 +4,7 @@ include (agentRules)
compileasc99 ()
add_library (${PROJECT_NAME} SHARED)
add_library (${PROJECT_NAME} MODULE)
add_library (aduc::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_sources (

Просмотреть файл

@ -6,7 +6,7 @@ compileasc99 ()
find_package (deliveryoptimization_sdk CONFIG REQUIRED)
add_library (${PROJECT_NAME} SHARED)
add_library (${PROJECT_NAME} MODULE)
add_library (aduc::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_sources (

Просмотреть файл

@ -3,7 +3,7 @@ set (target_name microsoft_delta_download_handler)
include (agentRules)
compileasc99 ()
add_library (${target_name} MODULE "")
add_library (${target_name} MODULE)
target_include_directories (${target_name} PUBLIC inc ${ADUC_EXPORT_INCLUDES})

Просмотреть файл

@ -20,6 +20,7 @@ target_link_libraries (
PRIVATE aduc::c_utils
aduc::extension_manager
aduc::logging
aduc::parser_utils
aduc::shared_lib
aduc::source_update_cache
aduc::workflow_utils)

Просмотреть файл

@ -14,6 +14,7 @@ target_link_libraries (
${PROJECT_NAME}
PRIVATE aduc::adu_types
aduc::microsoft_delta_download_handler_utils
aduc::parser_utils
aduc::workflow_utils
Catch2::Catch2)

Просмотреть файл

@ -11,6 +11,7 @@
using Catch::Matchers::Equals;
#include "aduc/microsoft_delta_download_handler_utils.h"
#include <aduc/parser_utils.h>
#include <aduc/result.h> // ADUC_Result_*
#include <aduc/types/adu_core.h> // ADUC_Result_*
#include <aduc/types/update_content.h> // ADUC_RelatedFile, ADUC_FileEntity
@ -22,63 +23,61 @@ using Catch::Matchers::Equals;
#define TEST_PAYLOAD_FILE_ID "ac47d3bab772454283ae95f0bbb1a1de"
#define TEST_DELTA_FILE_ID "312d0351155037c4900d76473d371c35"
const std::string updateManifest{
R"( { )"
R"( "compatibility": [ )"
R"( { )"
R"( "deviceManufacturer": "contoso", )"
R"( "deviceModel": "toaster" )"
R"( } )"
R"( ], )"
R"( "createdDateTime": "2022-03-12T12:22:37.2627901Z", )"
R"( "files": { )"
R"( "PAYLOAD_FILE_ID": { )"
R"( "fileName": "target_update.swu", )"
R"( "hashes": { )"
R"( "sha256": "PAYLOAD_HASH" )"
R"( }, )"
R"( "sizeInBytes": 98765, )"
R"( "properties": { )"
R"( }, )"
R"( "downloadHandler": { )"
R"( "id": "microsoft/delta:1" )"
R"( }, )"
R"( "relatedFiles": { )"
R"( "DELTA_FILE_ID": { )"
R"( "fileName": "DELTA_UPDATE_FILE_NAME", )"
R"( "sizeInBytes": 1234, )"
R"( "hashes": { )"
R"( "sha256": "DELTA_UPDATE_HASH" )"
R"( }, )"
R"( "properties": { )"
R"( "microsoft.sourceFileHash": "SOURCE_UPDATE_HASH", )"
R"( "microsoft.sourceFileHashAlgorithm": "sha256" )"
R"( } )"
R"( } )"
R"( } )"
R"( } )"
R"( }, )"
R"( "instructions": { )"
R"( "steps": [ )"
R"( { )"
R"( "files": [ )"
R"( "f222b9ffefaaac577" )"
R"( ], )"
R"( "handler": "microsoft/swupdate:1", )"
R"( "handlerProperties": { )"
R"( "installedCriteria": "toaster_firmware-0.1" )"
R"( } )"
R"( } )"
R"( ] )"
R"( }, )"
R"( "manifestVersion": "5", )"
R"( "updateId": { )"
R"( "name": "toaster_firmware", )"
R"( "provider": "contoso", )"
R"( "version": "0.1" )"
R"( } )"
R"( } )"
};
const std::string updateManifest{ R"( { )"
R"( "compatibility": [ )"
R"( { )"
R"( "deviceManufacturer": "contoso", )"
R"( "deviceModel": "toaster" )"
R"( } )"
R"( ], )"
R"( "createdDateTime": "2022-03-12T12:22:37.2627901Z", )"
R"( "files": { )"
R"( "PAYLOAD_FILE_ID": { )"
R"( "fileName": "target_update.swu", )"
R"( "hashes": { )"
R"( "sha256": "PAYLOAD_HASH" )"
R"( }, )"
R"( "sizeInBytes": 98765, )"
R"( "properties": { )"
R"( }, )"
R"( "downloadHandler": { )"
R"( "id": "microsoft/delta:1" )"
R"( }, )"
R"( "relatedFiles": { )"
R"( "DELTA_FILE_ID": { )"
R"( "fileName": "DELTA_UPDATE_FILE_NAME", )"
R"( "sizeInBytes": 1234, )"
R"( "hashes": { )"
R"( "sha256": "DELTA_UPDATE_HASH" )"
R"( }, )"
R"( "properties": { )"
R"( "microsoft.sourceFileHash": "SOURCE_UPDATE_HASH", )"
R"( "microsoft.sourceFileHashAlgorithm": "sha256" )"
R"( } )"
R"( } )"
R"( } )"
R"( } )"
R"( }, )"
R"( "instructions": { )"
R"( "steps": [ )"
R"( { )"
R"( "files": [ )"
R"( "f222b9ffefaaac577" )"
R"( ], )"
R"( "handler": "microsoft/swupdate:1", )"
R"( "handlerProperties": { )"
R"( "installedCriteria": "toaster_firmware-0.1" )"
R"( } )"
R"( } )"
R"( ] )"
R"( }, )"
R"( "manifestVersion": "5", )"
R"( "updateId": { )"
R"( "name": "toaster_firmware", )"
R"( "provider": "contoso", )"
R"( "version": "0.1" )"
R"( } )"
R"( } )" };
const std::string desiredTemplate{
R"( { )"
@ -136,16 +135,17 @@ TEST_CASE("MicrosoftDeltaDownloadHandlerUtils_ProcessRelatedFile Cache Miss")
result = workflow_init(desired.c_str(), false, &handle);
REQUIRE(IsAducResultCodeSuccess(result.ResultCode));
ADUC_FileEntity* fileEntity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
REQUIRE(workflow_get_update_file(handle, 0, &fileEntity));
//
// Act
//
result = MicrosoftDeltaDownloadHandlerUtils_ProcessRelatedFile(
handle, &fileEntity->RelatedFiles[0], "/foo/", "/bar/", MockProcessDeltaUpdateFn, MockDownloadDeltaUpdateFn);
handle, &fileEntity.RelatedFiles[0], "/foo/", "/bar/", MockProcessDeltaUpdateFn, MockDownloadDeltaUpdateFn);
CHECK(result.ResultCode == ADUC_Result_Success_Cache_Miss);
workflow_free_file_entity(fileEntity);
ADUC_FileEntity_Uninit(&fileEntity);
}

Просмотреть файл

@ -19,6 +19,7 @@ target_link_libraries (
${target_name}
PUBLIC aduc::adu_types aduc::c_utils
PRIVATE aduc::file_utils
aduc::parser_utils
aduc::path_utils
aduc::permission_utils
aduc::system_utils

Просмотреть файл

@ -8,6 +8,7 @@
*/
#include "aduc/source_update_cache_utils.h"
#include <aduc/parser_utils.h> // ADUC_FileEntity_Uninit
#include <aduc/path_utils.h> // SanitizePathSegment
#include <aduc/string_c_utils.h> // IsNullOrEmpty
#include <aduc/system_utils.h> // ADUC_SystemUtils_*
@ -149,7 +150,8 @@ ADUC_Result ADUC_SourceUpdateCacheUtils_MoveToUpdateCache(
{
ADUC_Result result = { .ResultCode = ADUC_Result_Failure };
int res = -1;
ADUC_FileEntity* fileEntity = NULL;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
STRING_HANDLE sandboxUpdatePayloadFile = NULL;
ADUC_UpdateId* updateId = NULL;
STRING_HANDLE updateCacheFilePath = NULL;
@ -164,7 +166,7 @@ ADUC_Result ADUC_SourceUpdateCacheUtils_MoveToUpdateCache(
goto done;
}
workflow_get_entity_workfolder_filepath(workflowHandle, fileEntity, &sandboxUpdatePayloadFile);
workflow_get_entity_workfolder_filepath(workflowHandle, &fileEntity, &sandboxUpdatePayloadFile);
result = workflow_get_expected_update_id(workflowHandle, &updateId);
if (IsAducResultCodeFailure(result.ResultCode))
@ -183,8 +185,8 @@ ADUC_Result ADUC_SourceUpdateCacheUtils_MoveToUpdateCache(
}
const char* provider = updateId->Provider;
const char* hash = (fileEntity->Hash[0]).value;
const char* alg = (fileEntity->Hash[0]).type;
const char* hash = (fileEntity.Hash[0]).value;
const char* alg = (fileEntity.Hash[0]).type;
updateCacheFilePath =
ADUC_SourceUpdateCacheUtils_CreateSourceUpdateCachePath(provider, hash, alg, updateCacheBasePath);
@ -236,8 +238,7 @@ ADUC_Result ADUC_SourceUpdateCacheUtils_MoveToUpdateCache(
}
}
workflow_free_file_entity(fileEntity);
fileEntity = NULL;
ADUC_FileEntity_Uninit(&fileEntity);
ADUC_UpdateId_UninitAndFree(updateId);
updateId = NULL;
@ -252,7 +253,7 @@ ADUC_Result ADUC_SourceUpdateCacheUtils_MoveToUpdateCache(
result.ResultCode = ADUC_Result_Success;
done:
workflow_free_file_entity(fileEntity);
ADUC_FileEntity_Uninit(&fileEntity);
ADUC_UpdateId_UninitAndFree(updateId);
STRING_delete(sandboxUpdatePayloadFile);
STRING_delete(updateCacheFilePath);

Просмотреть файл

@ -2,12 +2,8 @@ cmake_minimum_required (VERSION 3.5)
set (target_name microsoft_apt_1)
set (SOURCE_ALL src/apt_handler.cpp src/apt_parser.cpp)
#
# Create a SHARED library.
#
add_library (${target_name} SHARED ${SOURCE_ALL})
add_library (${target_name} MODULE)
target_sources (${target_name} PRIVATE src/apt_handler.cpp src/apt_parser.cpp)
add_library (aduc::${target_name} ALIAS ${target_name})
@ -37,6 +33,7 @@ target_link_libraries (
aduc::contract_utils
aduc::extension_manager
aduc::installed_criteria_utils
aduc::parser_utils
aduc::process_utils
aduc::workflow_data_utils
aduc::workflow_utils

Просмотреть файл

@ -18,6 +18,7 @@
#include "aduc/extension_manager.hpp"
#include "aduc/installed_criteria_utils.hpp"
#include "aduc/logging.h"
#include "aduc/parser_utils.h" // ADUC_FileEntity_Uninit
#include "aduc/process_utils.hpp"
#include "aduc/string_c_utils.h"
#include "aduc/types/update_content.h"
@ -158,7 +159,9 @@ ADUC_Result AptHandlerImpl::Download(const ADUC_WorkflowData* workflowData)
}
char* workFolder = workflow_get_workfolder(handle);
ADUC_FileEntity* fileEntity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
if (!workflow_get_update_file(handle, 0, &fileEntity))
{
@ -176,14 +179,11 @@ ADUC_Result AptHandlerImpl::Download(const ADUC_WorkflowData* workflowData)
goto done;
}
aptManifestFilename << workFolder << "/" << fileEntity->TargetFilename;
aptManifestFilename << workFolder << "/" << fileEntity.TargetFilename;
// Download the APT manifest file.
result = ExtensionManager::Download(
fileEntity, workflowData->WorkflowHandle, &Default_ExtensionManager_Download_Options, nullptr);
workflow_free_file_entity(fileEntity);
fileEntity = nullptr;
&fileEntity, workflowData->WorkflowHandle, &Default_ExtensionManager_Download_Options, nullptr);
if (IsAducResultCodeFailure(result.ResultCode))
{
@ -276,7 +276,7 @@ ADUC_Result AptHandlerImpl::Download(const ADUC_WorkflowData* workflowData)
done:
workflow_free_string(installedCriteria);
workflow_free_string(workFolder);
workflow_free_file_entity(fileEntity);
ADUC_FileEntity_Uninit(&fileEntity);
return result;
}
@ -291,7 +291,8 @@ ADUC_Result AptHandlerImpl::Install(const ADUC_WorkflowData* workflowData)
std::string aptOutput;
int aptExitCode = -1;
ADUC_Result result = { .ResultCode = ADUC_Result_Download_Success, .ExtendedResultCode = 0 };
ADUC_FileEntity* fileEntity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
ADUC_WorkflowHandle handle = workflowData->WorkflowHandle;
char* workFolder = workflow_get_workfolder(handle);
std::stringstream aptManifestFilename;
@ -310,7 +311,7 @@ ADUC_Result AptHandlerImpl::Install(const ADUC_WorkflowData* workflowData)
goto done;
}
aptManifestFilename << workFolder << "/" << fileEntity->TargetFilename;
aptManifestFilename << workFolder << "/" << fileEntity.TargetFilename;
result = ParseContent(aptManifestFilename.str(), aptContent);
if (IsAducResultCodeFailure(result.ResultCode))
@ -368,7 +369,7 @@ ADUC_Result AptHandlerImpl::Install(const ADUC_WorkflowData* workflowData)
done:
workflow_free_string(workFolder);
workflow_free_file_entity(fileEntity);
ADUC_FileEntity_Uninit(&fileEntity);
return result;
}
@ -385,7 +386,8 @@ ADUC_Result AptHandlerImpl::Apply(const ADUC_WorkflowData* workflowData)
char* workFolder = workflow_get_workfolder(handle);
std::unique_ptr<AptContent> aptContent{ nullptr };
std::stringstream aptManifestFilename;
ADUC_FileEntity* entity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
if (workflow_is_cancel_requested(handle))
{
@ -400,14 +402,14 @@ ADUC_Result AptHandlerImpl::Apply(const ADUC_WorkflowData* workflowData)
goto done;
}
if (!workflow_get_update_file(handle, 0, &entity))
if (!workflow_get_update_file(handle, 0, &fileEntity))
{
result = { .ResultCode = ADUC_Result_Failure,
.ExtendedResultCode = ADUC_ERC_APT_HANDLER_GET_FILEENTITY_FAILURE };
goto done;
}
aptManifestFilename << workFolder << "/" << entity->TargetFilename;
aptManifestFilename << workFolder << "/" << fileEntity.TargetFilename;
result = ParseContent(aptManifestFilename.str(), aptContent);
if (IsAducResultCodeFailure(result.ResultCode))
@ -433,7 +435,7 @@ ADUC_Result AptHandlerImpl::Apply(const ADUC_WorkflowData* workflowData)
done:
workflow_free_string(workFolder);
workflow_free_string(installedCriteria);
workflow_free_file_entity(entity);
ADUC_FileEntity_Uninit(&fileEntity);
return result;
}

Просмотреть файл

@ -44,6 +44,7 @@ target_link_libraries (
aduc::exception_utils
aduc::extension_manager
aduc::installed_criteria_utils
aduc::parser_utils
aduc::process_utils
aduc::string_utils
aduc::system_utils

Просмотреть файл

@ -19,6 +19,7 @@ target_link_libraries (
aduc::extension_utils
aduc::extension_manager
aduc::logging
aduc::parser_utils
aduc::process_utils
aduc::string_utils
aduc::system_utils

Просмотреть файл

@ -180,7 +180,7 @@ The following options and arguments are automatically pass to the script.
|--action-cancel| none | Script Handler will append this option to the `arguments` list to indicate that the update (step) is being canceled.<br/>The Script should consider canceling any in-progress task, and restore the device or component back to the original state. |
|--action-download| none | Script Handler will append this option to the `arguments` list to indicate that the script is invoked as part of the `download` action.<br/>The Script should perform any additional content download tasks to ensure that all content required by the installation is accessible during the installation. |
|--action-install| none | Script Handler will append this option to the `arguments` list to indicate that the script is invoked as part of the `install` action.<br/>The Script should perform all tasks related to the software installation. Such as, install a software package(s) on host device, transfer firmware file to connected peripheral, remove existing file(s) that no longer needed, etc.|
|--action-is-install| none |Script Handler will append this option to the `arguments` list to indicate that the script is invoked as part of the `isInstalled` inquiry.<br/>As part of the Agent-Orchestrated workflow, sometimes, Device Update Agent will invoke the Script Handler's `IsInstalled` function to determine wither the current Step has been **installed**. <br> For Step that does not install any software, **isinstalled** is equivalent to **applied**. E.g., "Is the step has been applied on the device or components?"|
|--action-is-installed| none |Script Handler will append this option to the `arguments` list to indicate that the script is invoked as part of the `isInstalled` inquiry.<br/>As part of the Agent-Orchestrated workflow, sometimes, Device Update Agent will invoke the Script Handler's `IsInstalled` function to determine wither the current Step has been **installed**. <br> For Step that does not install any software, **is installed** is equivalent to **applied**. E.g., "Is the step has been applied on the device or components?"|
| --work-folder | <"work_folder_path">| A fully qualified path to `workfolder` (a.k.a. `sandbox folder`). This is a folder used for storing downloaded file, workflow result file, and any other temp files.<br/><br/>Script Handler will append this option to the arguments list when invoking the script. |
| --result-file | <"result_file_path"> |A fully qualified path to the workflow task result. The result file contains a ADUC_Result data in a JSON. The Script Handler will read ADUC_Result data in this file and continue or abort the update workflow based on the `resultCode`. If the result file does not exist, or can not be opened, the update workflow will be aborted.<br/><br/>Script Handler will append this option to the arguments list when invoking the script.|
| --installed-criteria | <"installed_criteria_string">| Pass-through value to the script.|

Просмотреть файл

@ -8,6 +8,7 @@
#include "aduc/script_handler.hpp"
#include "aduc/extension_manager.hpp"
#include "aduc/logging.h"
#include "aduc/parser_utils.h" // ADUC_FileEntity_Uninit
#include "aduc/process_utils.hpp" // ADUC_LaunchChildProcess
#include "aduc/string_c_utils.h" // IsNullOrEmpty
#include "aduc/string_utils.hpp" // ADUC::StringUtils::Split
@ -105,7 +106,8 @@ static ADUC_Result Script_Handler_DownloadPrimaryScriptFile(ADUC_WorkflowHandle
ADUC_Result result = { ADUC_Result_Failure };
const char* workflowId = nullptr;
char* workFolder = nullptr;
ADUC_FileEntity* entity = nullptr;
ADUC_FileEntity entity;
memset(&entity, 0, sizeof(entity));
int fileCount = workflow_get_update_files_count(handle);
int createResult = 0;
@ -148,17 +150,15 @@ static ADUC_Result Script_Handler_DownloadPrimaryScriptFile(ADUC_WorkflowHandle
.retryTimeout = DO_RETRY_TIMEOUT_DEFAULT,
};
result = ExtensionManager::Download(entity, handle, &downloadOptions, nullptr);
result = ExtensionManager::Download(&entity, handle, &downloadOptions, nullptr);
}
catch (...)
{
result.ExtendedResultCode = ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_PRIMARY_FILE_FAILURE_UNKNOWNEXCEPTION;
}
workflow_free_file_entity(entity);
entity = nullptr;
done:
ADUC_FileEntity_Uninit(&entity);
workflow_free_string(workFolder);
return result;
}
@ -187,7 +187,8 @@ ADUC_Result ScriptHandlerImpl::Download(const tagADUC_WorkflowData* workflowData
char* installedCriteria = nullptr;
const char* workflowId = workflow_peek_id(workflowHandle);
char* workFolder = workflow_get_workfolder(workflowData->WorkflowHandle);
ADUC_FileEntity* entity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
int fileCount = workflow_get_update_files_count(workflowHandle);
ADUC_Result result = Script_Handler_DownloadPrimaryScriptFile(workflowHandle);
@ -212,7 +213,7 @@ ADUC_Result ScriptHandlerImpl::Download(const tagADUC_WorkflowData* workflowData
{
Log_Info("Downloading file #%d", i);
if (!workflow_get_update_file(workflowHandle, i, &entity))
if (!workflow_get_update_file(workflowHandle, i, &fileEntity))
{
result = { .ResultCode = ADUC_Result_Failure,
.ExtendedResultCode = ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_FAILURE_GET_PAYLOAD_FILE_ENTITY };
@ -225,7 +226,8 @@ ADUC_Result ScriptHandlerImpl::Download(const tagADUC_WorkflowData* workflowData
.retryTimeout = DO_RETRY_TIMEOUT_DEFAULT,
};
result = ExtensionManager::Download(entity, workflowHandle, &downloadOptions, nullptr);
result = ExtensionManager::Download(&fileEntity, workflowHandle, &downloadOptions, nullptr);
ADUC_FileEntity_Uninit(&fileEntity);
}
catch (...)
{
@ -233,9 +235,6 @@ ADUC_Result ScriptHandlerImpl::Download(const tagADUC_WorkflowData* workflowData
.ExtendedResultCode = ADUC_ERC_SCRIPT_HANDLER_DOWNLOAD_PAYLOAD_FILE_FAILURE_UNKNOWNEXCEPTION };
}
workflow_free_file_entity(entity);
entity = nullptr;
if (IsAducResultCodeFailure(result.ResultCode))
{
Log_Error("Cannot download script payload file#%d. (0x%X)", i, result.ExtendedResultCode);
@ -248,7 +247,7 @@ ADUC_Result ScriptHandlerImpl::Download(const tagADUC_WorkflowData* workflowData
done:
workflow_free_string(workFolder);
workflow_free_file_entity(entity);
ADUC_FileEntity_Uninit(&fileEntity);
workflow_free_string(installedCriteria);
Log_Info("Script_Handler download task end.");
return result;
@ -481,16 +480,14 @@ ADUC_Result ScriptHandlerImpl::PrepareScriptArguments(
args.emplace_back("--result-file");
args.emplace_back(resultFilePath);
args.emplace_back("--installed-criteria");
if (installedCriteria != nullptr)
if (IsNullOrEmpty(installedCriteria))
{
args.emplace_back(installedCriteria);
Log_Info("Installed criteria is null.");
}
else
{
Log_Info("Installed criteria is null.");
args.emplace_back("");
args.emplace_back("--installed-criteria");
args.emplace_back(installedCriteria);
}
result = { ADUC_Result_Success };

Просмотреть файл

@ -2,12 +2,8 @@ cmake_minimum_required (VERSION 3.5)
set (target_name microsoft_simulator_1)
set (SOURCE_ALL src/simulator_handler.cpp)
#
# Create a shared library.
#
add_library (${target_name} SHARED ${SOURCE_ALL})
add_library (${target_name} MODULE)
target_sources (${target_name} PRIVATE src/simulator_handler.cpp)
add_library (aduc::${target_name} ALIAS ${target_name})
@ -38,6 +34,7 @@ target_link_libraries (
PRIVATE aduc::agent_workflow
aduc::contract_utils
aduc::logging
aduc::parser_utils
aduc::workflow_utils
Parson::parson)

Просмотреть файл

@ -7,6 +7,7 @@
*/
#include "aduc/simulator_handler.hpp"
#include "aduc/logging.h"
#include "aduc/parser_utils.h" // ADUC_FileEntity_Uninit
#include "aduc/workflow_utils.h"
#include <stdarg.h> // for va_*
#include <stdlib.h> // for getenv
@ -214,6 +215,8 @@ ADUC_Result SimulatorHandlerImpl::Download(const tagADUC_WorkflowData* workflowD
ADUC_Result result = { .ResultCode = ADUC_Result_Download_Success };
ADUC_WorkflowHandle handle = workflowData->WorkflowHandle;
ADUC_WorkflowHandle childHandle = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
auto fileCount = static_cast<unsigned int>(workflow_get_update_files_count(handle));
@ -232,33 +235,27 @@ ADUC_Result SimulatorHandlerImpl::Download(const tagADUC_WorkflowData* workflowD
for (size_t i = 0; i < fileCount; i++)
{
ADUC_FileEntity* entity = nullptr;
result = { .ResultCode = ADUC_Result_Download_Success };
bool fileEntityOk = workflow_get_update_file(handle, i, &entity);
if (!fileEntityOk || entity == nullptr)
if (!workflow_get_update_file(handle, i, &fileEntity))
{
result = { .ResultCode = ADUC_Result_Failure,
.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_GET_FILE_ENTITY_FAILURE };
goto done;
}
Log_Info("Downloading file#%d (targetFileName:%s).", i, entity->TargetFilename);
Log_Info("Downloading file#%d (targetFileName:%s).", i, fileEntity.TargetFilename);
JSON_Object* resultForFile =
json_value_get_object(json_object_get_value(downloadResult, entity->TargetFilename));
json_value_get_object(json_object_get_value(downloadResult, fileEntity.TargetFilename));
if (resultForFile == nullptr)
{
Log_Info("No matching results for file '%s', fallback to catch-all result", entity->TargetFilename);
Log_Info("No matching results for file '%s', fallback to catch-all result", fileEntity.TargetFilename);
resultForFile = json_value_get_object(json_object_get_value(downloadResult, "*"));
}
workflow_free_file_entity(entity);
entity = nullptr;
if (resultForFile != nullptr)
{
result.ResultCode = json_object_get_number(resultForFile, "resultCode");
@ -277,6 +274,7 @@ ADUC_Result SimulatorHandlerImpl::Download(const tagADUC_WorkflowData* workflowD
}
done:
ADUC_FileEntity_Uninit(&fileEntity);
if (data != nullptr)
{

Просмотреть файл

@ -39,6 +39,7 @@ target_link_libraries (
aduc::exception_utils
aduc::extension_utils
aduc::logging
aduc::parser_utils
aduc::process_utils
aduc::string_utils
aduc::system_utils

Просмотреть файл

@ -24,6 +24,7 @@ target_link_libraries (
aduc::contract_utils
aduc::extension_manager
aduc::logging
aduc::parser_utils
aduc::process_utils
aduc::string_utils
aduc::system_utils

Просмотреть файл

@ -20,6 +20,7 @@
#include "aduc/adu_core_exports.h"
#include "aduc/extension_manager.hpp"
#include "aduc/logging.h"
#include "aduc/parser_utils.h" // ADUC_FileEntity_Uninit
#include "aduc/process_utils.hpp"
#include "aduc/string_c_utils.h"
#include "aduc/string_utils.hpp"
@ -124,7 +125,8 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
{
std::stringstream updateFilename;
ADUC_Result result = { ADUC_Result_Failure };
ADUC_FileEntity* entity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
ADUC_WorkflowHandle workflowHandle = workflowData->WorkflowHandle;
char* workFolder = workflow_get_workfolder(workflowHandle);
int fileCount = 0;
@ -143,7 +145,8 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
updateTypeOk = ADUC_ParseUpdateType(updateType, &updateName, &updateTypeVersion);
if (!updateTypeOk)
{
Log_Error("SWUpdate packages download failed. Unknown Handler Version (UpdateDateType:%s)", updateType);
Log_Error(
"SWUpdate packages download failed. Unable to parse updateName and updateTypeVersion from updateType.");
result.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_UNKNOWN_UPDATE_VERSION;
goto done;
}
@ -164,25 +167,26 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
goto done;
}
if (!workflow_get_update_file(workflowHandle, 0, &entity))
if (!workflow_get_update_file(workflowHandle, 0, &fileEntity))
{
result.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_BAD_FILE_ENTITY;
goto done;
}
updateFilename << workFolder << "/" << entity->TargetFilename;
updateFilename << workFolder << "/" << fileEntity.TargetFilename;
{
ExtensionManager_Download_Options downloadOptions = {
.retryTimeout = DO_RETRY_TIMEOUT_DEFAULT,
};
result = ExtensionManager::Download(entity, workflowHandle, &downloadOptions, nullptr);
result = ExtensionManager::Download(&fileEntity, workflowHandle, &downloadOptions, nullptr);
}
done:
workflow_free_string(workFolder);
workflow_free_file_entity(entity);
ADUC_FileEntity_Uninit(&fileEntity);
free(updateName);
return result;
}
@ -196,7 +200,8 @@ done:
ADUC_Result SWUpdateHandlerImpl::Install(const tagADUC_WorkflowData* workflowData)
{
ADUC_Result result = { ADUC_Result_Failure };
ADUC_FileEntity* entity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
ADUC_WorkflowHandle workflowHandle = workflowData->WorkflowHandle;
char* workFolder = workflow_get_workfolder(workflowHandle);
@ -218,7 +223,7 @@ ADUC_Result SWUpdateHandlerImpl::Install(const tagADUC_WorkflowData* workflowDat
goto done;
}
if (!workflow_get_update_file(workflowHandle, 0, &entity))
if (!workflow_get_update_file(workflowHandle, 0, &fileEntity))
{
result.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_INSTALL_FAILURE_BAD_FILE_ENTITY;
goto done;
@ -239,7 +244,7 @@ ADUC_Result SWUpdateHandlerImpl::Install(const tagADUC_WorkflowData* workflowDat
adushconst::update_action_install };
std::stringstream data;
data << workFolder << "/" << entity->TargetFilename;
data << workFolder << "/" << fileEntity.TargetFilename;
args.emplace_back(adushconst::target_data_opt);
args.emplace_back(data.str().c_str());
@ -263,7 +268,7 @@ ADUC_Result SWUpdateHandlerImpl::Install(const tagADUC_WorkflowData* workflowDat
done:
workflow_free_string(workFolder);
workflow_free_file_entity(entity);
ADUC_FileEntity_Uninit(&fileEntity);
return result;
}
@ -326,10 +331,7 @@ ADUC_Result SWUpdateHandlerImpl::Apply(const tagADUC_WorkflowData* workflowData)
CancelApply(ADUC_LOG_FOLDER);
}
result = {
.ResultCode = ADUC_Result_Success,
.ExtendedResultCode = 0
};
result = { .ResultCode = ADUC_Result_Success, .ExtendedResultCode = 0 };
done:
workflow_free_string(workFolder);

Просмотреть файл

@ -9,7 +9,7 @@ set (
"${ADUC_CONF_FOLDER}/${SWUPDATE_HANDLER_CONF_FILE}"
CACHE STRING "Path to the SWUpdate handler configuration file.")
add_library (${target_name} SHARED "")
add_library (${target_name} MODULE)
add_library (aduc::${target_name} ALIAS ${target_name})
@ -33,6 +33,7 @@ target_link_libraries (
aduc::exception_utils
aduc::extension_manager
aduc::logging
aduc::parser_utils
aduc::process_utils
aduc::string_utils
aduc::system_utils

Просмотреть файл

@ -62,7 +62,7 @@ The SWUpdate Handler support following handler properties (`handlerProperties`)
| Name | Type | Description |
|---|---|---|
|--workfolder| string | Full path to a work (sandbox) folder used by an Agent when performing update-related tasks. |
|--work-folder| string | Full path to a work (sandbox) folder used by an Agent when performing update-related tasks. |
|--output-file|string|Full path to an output file that swupdate script should write to|
|--log-file|string| Full path to a log file that swupdate script should write to. (This is different that Agent's log file)|
|--result-file|string|Full path to an ADUC_Result file that swupdate script must write the end result of the update tasks to. If this file does not exist or cannot be parsed, the task will be considered failed.|

Просмотреть файл

@ -51,6 +51,9 @@ public:
std::string& commandFilePath,
std::vector<std::string>& args);
private:
ADUC_Result CancelApply(const tagADUC_WorkflowData* workflowData);
protected:
// Protected constructor, must call CreateContentHandler factory method or from derived simulator class
SWUpdateHandlerImpl()

Просмотреть файл

@ -15,6 +15,7 @@
#include "aduc/adu_core_exports.h"
#include "aduc/extension_manager.hpp"
#include "aduc/logging.h"
#include "aduc/parser_utils.h" // ADUC_FileEntity_Uninit
#include "aduc/process_utils.hpp"
#include "aduc/string_c_utils.h"
#include "aduc/string_utils.hpp"
@ -68,7 +69,8 @@ static ADUC_Result SWUpdate_Handler_DownloadScriptFile(ADUC_WorkflowHandle handl
{
ADUC_Result result = { ADUC_Result_Failure };
char* workFolder = nullptr;
ADUC_FileEntity* entity = nullptr;
ADUC_FileEntity entity;
memset(&entity, 0, sizeof(entity));
int fileCount = workflow_get_update_files_count(handle);
int createResult = 0;
// Download the main script file.
@ -105,17 +107,15 @@ static ADUC_Result SWUpdate_Handler_DownloadScriptFile(ADUC_WorkflowHandle handl
try
{
result = ExtensionManager::Download(entity, handle, &Default_ExtensionManager_Download_Options, nullptr);
result = ExtensionManager::Download(&entity, handle, &Default_ExtensionManager_Download_Options, nullptr);
}
catch (...)
{
result.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_PRIMARY_FILE_FAILURE_UNKNOWNEXCEPTION;
}
workflow_free_file_entity(entity);
entity = nullptr;
done:
ADUC_FileEntity_Uninit(&entity);
workflow_free_string(workFolder);
return result;
}
@ -262,7 +262,7 @@ ADUC_Result SWUpdateHandler_PerformAction(
workflow_peek_result_details(workflowData->WorkflowHandle));
done:
if (IsAducResultCodeFailure(result.ResultCode) && workflowData->WorkflowHandle != nullptr)
if (IsAducResultCodeFailure(result.ResultCode))
{
workflow_set_result(workflowData->WorkflowHandle, result);
workflow_set_state(workflowData->WorkflowHandle, ADUCITF_State_Failed);
@ -296,7 +296,8 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
ADUC_WorkflowHandle workflowHandle = workflowData->WorkflowHandle;
char* installedCriteria = nullptr;
char* workFolder = workflow_get_workfolder(workflowData->WorkflowHandle);
ADUC_FileEntity* entity = nullptr;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
int fileCount = workflow_get_update_files_count(workflowHandle);
ADUC_Result result = SWUpdate_Handler_DownloadScriptFile(workflowHandle);
@ -321,7 +322,7 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
{
Log_Info("Downloading file #%d", i);
if (!workflow_get_update_file(workflowHandle, i, &entity))
if (!workflow_get_update_file(workflowHandle, i, &fileEntity))
{
result = { .ResultCode = ADUC_Result_Failure,
.ExtendedResultCode = ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_FAILURE_GET_PAYLOAD_FILE_ENTITY };
@ -331,7 +332,7 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
try
{
result = ExtensionManager::Download(
entity, workflowHandle, &Default_ExtensionManager_Download_Options, nullptr);
&fileEntity, workflowHandle, &Default_ExtensionManager_Download_Options, nullptr);
}
catch (...)
{
@ -340,9 +341,6 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
ADUC_ERC_SWUPDATE_HANDLER_DOWNLOAD_PAYLOAD_FILE_FAILURE_UNKNOWNEXCEPTION };
}
workflow_free_file_entity(entity);
entity = nullptr;
if (IsAducResultCodeFailure(result.ResultCode))
{
Log_Error("Cannot download payload file#%d. (0x%X)", i, result.ExtendedResultCode);
@ -355,7 +353,7 @@ ADUC_Result SWUpdateHandlerImpl::Download(const tagADUC_WorkflowData* workflowDa
done:
workflow_free_string(workFolder);
workflow_free_file_entity(entity);
ADUC_FileEntity_Uninit(&fileEntity);
workflow_free_string(installedCriteria);
Log_Info("SWUpdate_Handler download task end.");
return result;
@ -370,6 +368,27 @@ done:
ADUC_Result SWUpdateHandlerImpl::Install(const tagADUC_WorkflowData* workflowData)
{
ADUC_Result result = PerformAction("--action-install", workflowData);
// Note: the handler must request a system reboot or agent restart if required.
switch (result.ResultCode)
{
case ADUC_Result_Install_RequiredImmediateReboot:
workflow_request_immediate_reboot(workflowData->WorkflowHandle);
break;
case ADUC_Result_Install_RequiredReboot:
workflow_request_reboot(workflowData->WorkflowHandle);
break;
case ADUC_Result_Install_RequiredImmediateAgentRestart:
workflow_request_immediate_agent_restart(workflowData->WorkflowHandle);
break;
case ADUC_Result_Install_RequiredAgentRestart:
workflow_request_agent_restart(workflowData->WorkflowHandle);
break;
}
return result;
}
@ -386,56 +405,36 @@ ADUC_Result SWUpdateHandlerImpl::Apply(const tagADUC_WorkflowData* workflowData)
char* workFolder = workflow_get_workfolder(workflowData->WorkflowHandle);
Log_Info("Applying data from %s", workFolder);
// Execute the install command with "-a" to apply the install by telling
// the bootloader to boot to the updated partition.
// This is equivalent to : command << SWUpdateCommand << " -l " << _logFolder << " -a"
std::string command = adushconst::adu_shell;
std::vector<std::string> args{ adushconst::update_type_opt,
adushconst::update_type_microsoft_swupdate,
adushconst::update_action_opt,
adushconst::update_action_apply };
args.emplace_back(adushconst::target_log_folder_opt);
// Note: this implementation of SWUpdate Handler is relying on ADUC_LOG_FOLDER value from build pipeline.
// For GA, we should make this configurable in du-config.json.
args.emplace_back(ADUC_LOG_FOLDER);
std::string output;
const int exitCode = ADUC_LaunchChildProcess(command, args, output);
if (exitCode != 0)
{
Log_Error("Apply failed, extendedResultCode = %d", exitCode);
result = { ADUC_Result_Failure, exitCode };
goto done;
}
result = PerformAction("--action-apply", workflowData);
// Cancellation requested after applied?
if (workflow_get_operation_cancel_requested(workflowData->WorkflowHandle))
{
Cancel(workflowData);
goto done;
result = Cancel(workflowData);
}
result = {
.ResultCode = ADUC_Result_Success,
.ExtendedResultCode = 0
};
// Note: the handler must request a system reboot or agent restart if required.
switch (result.ResultCode)
{
case ADUC_Result_Apply_RequiredImmediateReboot:
workflow_request_immediate_reboot(workflowData->WorkflowHandle);
break;
case ADUC_Result_Apply_RequiredReboot:
workflow_request_reboot(workflowData->WorkflowHandle);
break;
case ADUC_Result_Apply_RequiredImmediateAgentRestart:
workflow_request_immediate_agent_restart(workflowData->WorkflowHandle);
break;
case ADUC_Result_Apply_RequiredAgentRestart:
workflow_request_agent_restart(workflowData->WorkflowHandle);
break;
}
done:
workflow_free_string(workFolder);
// Always require a reboot after successful apply
if (IsAducResultCodeSuccess(result.ResultCode))
{
workflow_request_immediate_reboot(workflowData->WorkflowHandle);
result = { ADUC_Result_Apply_RequiredImmediateReboot };
}
return result;
}
@ -811,14 +810,22 @@ ADUC_Result SWUpdateHandlerImpl::PrepareCommandArguments(
}
// Default options.
args.emplace_back("--workfolder");
args.emplace_back("--work-folder");
args.emplace_back(workFolder);
args.emplace_back("--result-file");
args.emplace_back(resultFilePath);
args.emplace_back("--installed-criteria");
args.emplace_back(installedCriteria);
if (IsNullOrEmpty(installedCriteria))
{
Log_Info("--installed-criteria is not specified");
}
else
{
args.emplace_back("--installed-criteria");
args.emplace_back(installedCriteria);
}
result = { ADUC_Result_Success };
@ -848,30 +855,21 @@ ADUC_Result SWUpdateHandlerImpl::PerformAction(const std::string& action, const
*
* @return ADUC_Result The result of the cancel.
*/
static ADUC_Result CancelApply(const char* logFolder)
ADUC_Result SWUpdateHandlerImpl::CancelApply(const tagADUC_WorkflowData* workflowData)
{
// Execute the install command with "-r" to reverts the apply by
// telling the bootloader to boot into the current partition
ADUC_Result result;
// This is equivalent to : command << c_installScript << " -l " << logFolder << " -r"
std::string command = adushconst::adu_shell;
std::vector<std::string> args{ adushconst::update_type_opt, adushconst::update_type_microsoft_swupdate,
adushconst::update_action_opt, adushconst::update_action_apply,
adushconst::target_log_folder_opt, logFolder };
std::string output;
const int exitCode = ADUC_LaunchChildProcess(command, args, output);
if (exitCode != 0)
result = PerformAction("--action-cancel", workflowData);
if (result.ResultCode != ADUC_Result_Cancel_Success)
{
// If failed to cancel apply, apply should return SuccessRebootRequired.
Log_Error("Failed to cancel Apply, extendedResultCode = %d", exitCode);
return ADUC_Result{ ADUC_Result_Failure, exitCode };
Log_Error("Failed to cancel Apply, extendedResultCode = (0x%X)", result.ExtendedResultCode);
return result;
}
else
{
Log_Info("Apply was cancelled");
return ADUC_Result{ ADUC_Result_Failure_Cancelled };
}
Log_Info("Apply was cancelled");
return ADUC_Result{ ADUC_Result_Failure_Cancelled };
}
/**
@ -899,11 +897,11 @@ ADUC_Result SWUpdateHandlerImpl::Backup(const tagADUC_WorkflowData* workflowData
ADUC_Result SWUpdateHandlerImpl::Restore(const tagADUC_WorkflowData* workflowData)
{
ADUC_Result result = { ADUC_Result_Restore_Success };
ADUC_Result cancel_result = CancelApply(ADUC_LOG_FOLDER);
ADUC_Result cancel_result = CancelApply(workflowData);
if (cancel_result.ResultCode != ADUC_Result_Failure_Cancelled)
{
result = { .ResultCode = ADUC_Result_Failure,
.ExtendedResultCode = ADUC_ERC_UPPERLEVEL_WORKFLOW_FAILED_RESTORE_FAILED };
}
return result;
}
}

Просмотреть файл

@ -39,6 +39,7 @@ target_link_libraries (
aduc::c_utils
aduc::exception_utils
aduc::extension_manager
aduc::parser_utils
aduc::process_utils
aduc::string_utils
aduc::system_utils

Просмотреть файл

@ -139,7 +139,7 @@ TEST_CASE("SWUpdate Prepare Arguments Test")
CHECK_THAT(
scriptOutput,
Equals(
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-install --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --workfolder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-install --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --work-folder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
args.clear();
result = SWUpdateHandler_PerformAction(
@ -151,7 +151,7 @@ TEST_CASE("SWUpdate Prepare Arguments Test")
CHECK_THAT(
scriptOutput,
Equals(
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-apply --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --workfolder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-apply --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --work-folder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
args.clear();
result = SWUpdateHandler_PerformAction(
@ -163,7 +163,7 @@ TEST_CASE("SWUpdate Prepare Arguments Test")
CHECK_THAT(
scriptOutput,
Equals(
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-cancel --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --workfolder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-cancel --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --work-folder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
args.clear();
result = SWUpdateHandler_PerformAction(
@ -175,7 +175,7 @@ TEST_CASE("SWUpdate Prepare Arguments Test")
CHECK_THAT(
scriptOutput,
Equals(
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-is-installed --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --workfolder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/example-du-swupdate-script.sh" --target-options --action-is-installed --target-options --swu-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --work-folder --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8" --target-options --result-file --target-options "/var/lib/adu/downloads/d19de7fb-11d8-45f7-88e0-03872a591de8/aduc_result.json" --target-options --installed-criteria --target-options "grep '^This is swupdate filecopy test version 1.0$' /usr/local/du/tests/swupdate-filecopy-test/mock-update-for-file-copy-test-1.txt")"));
args.clear();
ExtensionManager::Uninit();
@ -219,7 +219,7 @@ TEST_CASE("SWUpdate sample script --action-is-installed")
CHECK_THAT(
scriptOutput,
Equals(
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/tmp/adu/testdata/swupdate_filecopy/example-du-swupdate-script.sh" --target-options --action-is-installed --target-options --swu-file --target-options "/tmp/adu/testdata/swupdate_filecopy/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --software-version-file --target-options "/tmp/adu/testdata/test-device/vacuum-1/data/mock-update-for-file-copy-test-1.txt" --target-options --workfolder --target-options "/tmp/adu/testdata/swupdate_filecopy" --target-options --result-file --target-options "/tmp/adu/testdata/swupdate_filecopy/aduc_result.json" --target-options --installed-criteria --target-options "This is swupdate filecopy test version 1.0")"));
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/tmp/adu/testdata/swupdate_filecopy/example-du-swupdate-script.sh" --target-options --action-is-installed --target-options --swu-file --target-options "/tmp/adu/testdata/swupdate_filecopy/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --software-version-file --target-options "/tmp/adu/testdata/test-device/vacuum-1/data/mock-update-for-file-copy-test-1.txt" --target-options --work-folder --target-options "/tmp/adu/testdata/swupdate_filecopy" --target-options --result-file --target-options "/tmp/adu/testdata/swupdate_filecopy/aduc_result.json" --target-options --installed-criteria --target-options "This is swupdate filecopy test version 1.0")"));
std::string output;
int exitCode = ADUC_LaunchChildProcess(commandLineArgs[0], commandLineArgs, output);
@ -271,7 +271,7 @@ TEST_CASE("SWUpdate sample script --action-download")
CHECK_THAT(
scriptOutput,
Equals(
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/tmp/adu/testdata/swupdate_filecopy/example-du-swupdate-script.sh" --target-options --action-download --target-options --swu-file --target-options "/tmp/adu/testdata/swupdate_filecopy/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --software-version-file --target-options "/tmp/adu/testdata/test-device/vacuum-1/data/mock-update-for-file-copy-test-1.txt" --target-options --workfolder --target-options "/tmp/adu/testdata/swupdate_filecopy" --target-options --result-file --target-options "/tmp/adu/testdata/swupdate_filecopy/aduc_result.json" --target-options --installed-criteria --target-options "This is swupdate filecopy test version 1.0")"));
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/tmp/adu/testdata/swupdate_filecopy/example-du-swupdate-script.sh" --target-options --action-download --target-options --swu-file --target-options "/tmp/adu/testdata/swupdate_filecopy/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --software-version-file --target-options "/tmp/adu/testdata/test-device/vacuum-1/data/mock-update-for-file-copy-test-1.txt" --target-options --work-folder --target-options "/tmp/adu/testdata/swupdate_filecopy" --target-options --result-file --target-options "/tmp/adu/testdata/swupdate_filecopy/aduc_result.json" --target-options --installed-criteria --target-options "This is swupdate filecopy test version 1.0")"));
std::string output;
int exitCode = ADUC_LaunchChildProcess(commandLineArgs[0], commandLineArgs, output);
@ -323,7 +323,7 @@ TEST_CASE("SWUpdate sample script --action-install", "[!hide][functional_test]")
CHECK_THAT(
scriptOutput,
Equals(
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/tmp/adu/testdata/swupdate_filecopy/example-du-swupdate-script.sh" --target-options --action-install --target-options --swu-file --target-options "/tmp/adu/testdata/swupdate_filecopy/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --software-version-file --target-options "/tmp/adu/testdata/test-device/vacuum-1/data/mock-update-for-file-copy-test-1.txt" --target-options --workfolder --target-options "/tmp/adu/testdata/swupdate_filecopy" --target-options --result-file --target-options "/tmp/adu/testdata/swupdate_filecopy/aduc_result.json" --target-options --installed-criteria --target-options "This is swupdate filecopy test version 1.0")"));
R"( --update-type "microsoft/script" --update-action "execute" --target-data "/tmp/adu/testdata/swupdate_filecopy/example-du-swupdate-script.sh" --target-options --action-install --target-options --swu-file --target-options "/tmp/adu/testdata/swupdate_filecopy/du-agent-swupdate-filecopy-test-1_1.0.swu" --target-options --software-version-file --target-options "/tmp/adu/testdata/test-device/vacuum-1/data/mock-update-for-file-copy-test-1.txt" --target-options --work-folder --target-options "/tmp/adu/testdata/swupdate_filecopy" --target-options --result-file --target-options "/tmp/adu/testdata/swupdate_filecopy/aduc_result.json" --target-options --installed-criteria --target-options "This is swupdate filecopy test version 1.0")"));
std::string output;
int exitCode = ADUC_LaunchChildProcess(commandLineArgs[0], commandLineArgs, output);

Просмотреть файл

@ -52,7 +52,7 @@ log_error_pref="\033[1;31m[E]\033[0m"
# Files and Folders information
#
workfolder=
output_file=/adu/logs/swpupdate.output
output_file=/adu/logs/swupdate.output
log_file=/adu/logs/swupdate.log
swupdate_log_file=/adu/logs/swupdate_log_file
result_file=/adu/logs/swupdate.result.json
@ -221,7 +221,7 @@ print_help() {
echo "File and Folder information"
echo "==========================="
echo ""
echo "--workfolder A work-folder (or sandbox folder)."
echo "--work-folder A work-folder (or sandbox folder)."
echo "--swu-file, --image-file An image file (.swu) file to install."
echo "--output-file An output file."
echo "--log-file A log file."
@ -242,7 +242,7 @@ print_help() {
echo ""
echo "Scenario: perform install action"
echo "================================"
echo " <script> --log-level 0 --action-install --intalled-criteria 1.0 --swu-file example-device-update.swu --workfolder <sandbox-folder>"
echo " <script> --log-level 0 --action-install --intalled-criteria 1.0 --swu-file example-device-update.swu --work-folder <sandbox-folder>"
echo ""
}
@ -318,10 +318,10 @@ while [[ $1 != "" ]]; do
shift
;;
--workfolder)
--work-folder)
shift
if [[ -z $1 || $1 == -* ]]; then
error "--workfolder parameter is mandatory."
error "--work-folder parameter is mandatory."
$ret 1
fi
workfolder="$1"
@ -551,7 +551,7 @@ InstallUpdate() {
resultCode=0
extendedResultCode=0
resultDetails=""
ret_val=0
ret_val=1
#
# Note: we could simulate 'component off-line' scenario here.
@ -570,7 +570,7 @@ InstallUpdate() {
elif [[ $resultCode == 0 ]]; then
# Failed to determine whether the update has been installed or not.
# Return current ADUC_Result
echo "Failed to determine wehther the update has been installed or note."
echo "Failed to determine wehther the update has been installed or not."
elif [[ $resultCode -eq 901 ]]; then
# Not installed.
@ -589,14 +589,16 @@ InstallUpdate() {
# Generated RSA public key from private key using command:
# openssl rsa -in ${WORKDIR}/priv.pem -out ${WORKDIR}/public.pem -outform PEM -pubout
ret_val=1
if [[ ${public_key_file} -eq "" ]]; then
# Call swupdate with the image file and no signature validations
swupdate -v -i "${image_file}" -e ${selection} &>> "${swupdate_log_file}"
ret_val=$?
else
# Call swupdate with the image file and the public key for signature validation
swupdate -v -i "${image_file}" -k "${public_key_file}" -e ${selection} &>> "${swupdate_log_file}"
ret_val=$?
fi
ret_val=$?
if [[ $ret_val -eq 0 ]]; then
resultCode=600
@ -647,7 +649,7 @@ ApplyUpdate() {
extendedResultCode=0
resultDetails=""
echo "Cancelling update." >> "${log_file}"
echo "Applying." >> "${log_file}"
# Set the bootloader environment variable
# to tell the bootloader to boot into the new partition.
@ -657,14 +659,18 @@ ApplyUpdate() {
ret_val=$?
if [[ $ret_val -eq 0 ]]; then
if [ "$restart_to_apply" == "yes" ]; then
# ADUC_Result_Apply_RequiredImmediateReboot = 705
log_info "restart_to_apply=$restart_to_apply"
log_info "restart_agent_to_apply=$restart_agent_to_apply"
if [[ ${restart_to_apply} == "yes" ]]; then
log_info "Returning ADUC_Result_Apply_RequiredImmediateReboot(705)"
resultCode=705
elif [ "$restart_agent_to_apply" == "yes" ]; then
# ADUC_Result_Apply_RequiredImmediateAgentRestart = 707
elif [[ ${restart_agent_to_apply} == "yes" ]]; then
log_info "Returning ADUC_Result_Apply_RequiredImmediateAgentRestart(707)"
resultCode=707
else
# ADUC_Result_Apply_Success = 700
log_info "Returning ADUC_Result_Apply_Success(700)"
resultCode=700
fi
extendedResultCode=0

Просмотреть файл

@ -203,7 +203,7 @@ print_help() {
echo "File and Folderinformation"
echo "=========================="
echo ""
echo "--workfolder A work-folder (or sandbox folder)."
echo "--work-folder A work-folder (or sandbox folder)."
echo "--swu-file A swu file to install."
echo "--swu-log-file A log file for swupdate command."
echo "--output-file An output file."
@ -290,10 +290,10 @@ while [[ $1 != "" ]]; do
shift
;;
--workfolder)
--work-folder)
shift
if [[ -z $1 || $1 == -* ]]; then
error "--workfolder parameter is mandatory."
error "--work-folder parameter is mandatory."
$ret 1
fi
workfolder="$1"

Просмотреть файл

@ -10,7 +10,7 @@ set (target_name microsoft_steps_1)
find_package (Parson REQUIRED)
find_package (IotHubClient REQUIRED)
add_library (${target_name} SHARED)
add_library (${target_name} MODULE)
add_library (aduc::${target_name} ALIAS ${target_name})
target_sources (${target_name} PRIVATE src/steps_handler.cpp src/handler_create.cpp)
@ -42,6 +42,7 @@ target_link_libraries (
aduc::extension_manager
aduc::extension_utils
aduc::logging
aduc::parser_utils
aduc::process_utils
aduc::string_utils
aduc::system_utils

Просмотреть файл

@ -12,18 +12,17 @@
#include "aduc/extension_manager.hpp"
#include "aduc/extension_manager_download_options.h"
#include "aduc/logging.h"
#include "aduc/parser_utils.h" // ADUC_FileEntity_Uninit
#include "aduc/string_c_utils.h" // IsNullOrEmpty
#include "aduc/string_utils.hpp"
#include "aduc/system_utils.h"
#include "aduc/workflow_utils.h"
#include "parson.h"
#include <sstream>
#include <string>
#include <azure_c_shared_utility/crt_abstractions.h> // mallocAndStrcpy
#include <azure_c_shared_utility/strings.h> // STRING_*
#include <parson.h>
#include <sstream>
#include <string>
// Note: this requires ${CMAKE_DL_LIBS}
#include <dlfcn.h>
@ -100,8 +99,9 @@ ADUC_Result PrepareStepsWorkflowDataObject(ADUC_WorkflowHandle handle)
for (unsigned int i = 0; i < stepCount; i++)
{
STRING_HANDLE childId = nullptr;
ADUC_FileEntity* entity = nullptr;
childHandle = nullptr;
ADUC_FileEntity entity;
memset(&entity, 0, sizeof(entity));
if (workflow_is_inline_step(handle, i))
{
@ -140,7 +140,7 @@ ADUC_Result PrepareStepsWorkflowDataObject(ADUC_WorkflowHandle handle)
"Downloading a detached Update manifest file for level#%d step#%d (file id:%s).",
workflowLevel,
i,
entity->FileId);
entity.FileId);
try
{
@ -148,7 +148,7 @@ ADUC_Result PrepareStepsWorkflowDataObject(ADUC_WorkflowHandle handle)
.retryTimeout = DO_RETRY_TIMEOUT_DEFAULT,
};
result = ExtensionManager::Download(entity, handle, &downloadOptions, nullptr);
result = ExtensionManager::Download(&entity, handle, &downloadOptions, nullptr);
}
catch (...)
{
@ -156,15 +156,12 @@ ADUC_Result PrepareStepsWorkflowDataObject(ADUC_WorkflowHandle handle)
"Exception occurred while downloading a detached Update Manifest file for level#%d step#%d (file id:%s).",
workflowLevel,
i,
entity->FileId);
entity.FileId);
result.ExtendedResultCode = ADUC_ERC_STEPS_HANDLER_DOWNLOAD_FAILURE_UNKNOWNEXCEPTION;
}
std::stringstream childManifestFile;
childManifestFile << workFolder << "/" << entity->TargetFilename;
workflow_free_file_entity(entity);
entity = nullptr;
childManifestFile << workFolder << "/" << entity.TargetFilename;
// For 'microsoft/steps:1' implementation, abort download task as soon as an error occurs.
if (IsAducResultCodeFailure(result.ResultCode))
@ -260,13 +257,14 @@ ADUC_Result PrepareStepsWorkflowDataObject(ADUC_WorkflowHandle handle)
result = { ADUC_Result_Success };
done:
workflow_free_string(workFolder);
ADUC_FileEntity_Uninit(entity);
if (IsAducResultCodeFailure(result.ResultCode))
{
workflow_free(childHandle);
}
workflow_free_string(workFolder);
workflow_free_file_entity(entity);
return result;
}
@ -605,6 +603,7 @@ static ADUC_Result StepsHandler_Download(const tagADUC_WorkflowData* workflowDat
{
const char* errorFmt = "Cannot load a handler for step #%d (handler :%s)";
Log_Error(errorFmt, i, stepUpdateType);
workflow_set_result(stepHandle, result);
workflow_set_result_details(handle, errorFmt, i, stepUpdateType == nullptr ? "NULL" : stepUpdateType);
goto done;
}
@ -887,6 +886,7 @@ static ADUC_Result StepsHandler_Install(const tagADUC_WorkflowData* workflowData
{
const char* errorFmt = "Cannot load a handler for step #%d (handler :%s)";
Log_Error(errorFmt, i, stepUpdateType);
workflow_set_result(stepHandle, result);
workflow_set_result_details(handle, errorFmt, i, stepUpdateType == nullptr ? "NULL" : stepUpdateType);
goto done;
}

Просмотреть файл

@ -10,9 +10,6 @@ add_library (aduc::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
if (ADUC_PLATFORM_LAYER STREQUAL "linux")
add_subdirectory (linux_platform_layer)
target_link_libraries (${PROJECT_NAME} INTERFACE aduc::linux_platform_layer)
elseif (ADUC_PLATFORM_LAYER STREQUAL "simulator")
add_subdirectory (simulator_platform_layer)
target_link_libraries (${PROJECT_NAME} INTERFACE aduc::simulator_platform_layer)
else ()
message (FATAL_ERROR "Invalid platform layer specified. ${ADUC_PLATFORM_LAYER}")
endif ()

Просмотреть файл

@ -1,42 +0,0 @@
cmake_minimum_required (VERSION 3.5)
set (target_name simulator_platform_layer)
include (agentRules)
compileasc99 ()
disablertti ()
add_library (
${target_name} STATIC
src/simulator_adu_core_exports.cpp
src/simulator_adu_core_impl.cpp
src/simulator_device_info.cpp
src/simulator_device_info_exports.cpp
src/uhttp_downloader.cpp)
add_library (aduc::${target_name} ALIAS ${target_name})
#
# Turn -fPIC on, in order to use this library in another shared library.
#
set_property (TARGET ${target_name} PROPERTY POSITION_INDEPENDENT_CODE ON)
target_include_directories (${target_name} PUBLIC ${ADUC_EXPORT_INCLUDES}
${CMAKE_CURRENT_SOURCE_DIR}/src)
find_package (azure_c_shared_utility REQUIRED)
target_compile_definitions (
${target_name} PRIVATE ADUC_DEVICEINFO_MANUFACTURER="${ADUC_DEVICEINFO_MANUFACTURER}"
ADUC_DEVICEINFO_MODEL="${ADUC_DEVICEINFO_MODEL}")
target_link_libraries (
${target_name}
PRIVATE aduc::c_utils
aduc::exception_utils
aduc::logging
aduc::string_utils
aduc::workflow_utils
aziotsharedutil
uhttp)

Просмотреть файл

@ -1,189 +0,0 @@
/**
* @file simulator_adu_core_exports.cpp
* @brief Implements exported methods for platform-specific ADUC agent code.
*
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
#include "simulator_adu_core_impl.hpp"
#include "simulator_device_info.h"
#include <ostream>
#include <unordered_map>
#include <aduc/adu_core_exports.h>
#include <aduc/logging.h>
/**
* @brief Convert SimulationType to string for an ostream.
*
* @param strm ostream to write to.
* @param type Value to convert.
* @return ostream& @p strm.
*/
std::ostream& operator<<(std::ostream& strm, const SimulationType& type)
{
switch (type)
{
case SimulationType::DownloadFailed:
strm << "DownloadFailed";
break;
case SimulationType::InstallationFailed:
strm << "InstallationFailed";
break;
case SimulationType::ApplyFailed:
strm << "ApplyFailed";
break;
case SimulationType::IsInstalledFailed:
strm << "IsInstalledFailed";
break;
case SimulationType::AllSuccessful:
strm << "AllSuccessful";
break;
}
return strm;
}
EXTERN_C_BEGIN
/**
* @brief Register this module for callbacks.
*
* @param data Information about this module (e.g. callback methods)
* @param argc Count of optional arguments.
* @param argv Initialization arguments, size is argc.
* @return ADUC_Result Result code.
*/
ADUC_Result ADUC_RegisterPlatformLayer(ADUC_UpdateActionCallbacks* data, unsigned int argc, const char** argv)
{
try
{
// simulation_mode= argument.
const std::string simulationModeArgPrefix{ "simulation_mode=" };
const std::unordered_map<std::string, SimulationType> simulationMap{
{ "downloadfailed", SimulationType::DownloadFailed },
{ "installationfailed", SimulationType::InstallationFailed },
{ "applyfailed", SimulationType::ApplyFailed },
{ "isinstalledfailed", SimulationType::IsInstalledFailed },
{ "allsuccessful", SimulationType::AllSuccessful },
};
SimulationType simulationType = SimulationType::AllSuccessful;
const std::string manufacturerArgPrefix{ "deviceinfo_manufacturer=" };
const std::string modelArgPrefix{ "deviceinfo_model=" };
const std::string swVersionArgPrefix{ "deviceinfo_swversion=" };
for (unsigned index = 0; index < argc; ++index)
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
const std::string argument{ argv[index] };
const unsigned int dashdash_cch = 2; // 2 character in "--"
if (argument.substr(0, dashdash_cch) != "--")
{
continue;
}
if (argument.substr(dashdash_cch, manufacturerArgPrefix.size()) == manufacturerArgPrefix)
{
const std::string value{ argument.substr(dashdash_cch + manufacturerArgPrefix.size()) };
Log_Info("[Args] Using DeviceInfo manufacturer %s", value.c_str());
Simulator_DeviceInfo_SetManufacturer(value.c_str());
}
else if (argument.substr(dashdash_cch, modelArgPrefix.size()) == modelArgPrefix)
{
const std::string value{ argument.substr(dashdash_cch + modelArgPrefix.size()) };
Log_Info("[Args] Using DeviceInfo model %s", value.c_str());
Simulator_DeviceInfo_SetModel(value.c_str());
}
else if (argument.substr(dashdash_cch, swVersionArgPrefix.size()) == swVersionArgPrefix)
{
const std::string value{ argument.substr(dashdash_cch + swVersionArgPrefix.size()) };
Log_Info("[Args] Using DeviceInfo swversion %s", value.c_str());
Simulator_DeviceInfo_SetSwVersion(value.c_str());
}
else if (argument.substr(dashdash_cch, simulationModeArgPrefix.size()) == simulationModeArgPrefix)
{
const std::string value{ argument.substr(dashdash_cch + simulationModeArgPrefix.size()) };
if (value.empty())
{
continue;
}
try
{
simulationType = simulationMap.at(value);
}
catch (std::out_of_range&)
{
Log_Error("[Args] Invalid simulation mode %s", value.c_str());
throw;
}
Log_Info("[Args] Using simulation mode %s", value.c_str());
}
}
std::unique_ptr<ADUC::SimulatorPlatformLayer> pImpl{ ADUC::SimulatorPlatformLayer::Create(
simulationType) };
ADUC_Result result{ pImpl->SetUpdateActionCallbacks(data) };
// The platform layer object is now owned by the UpdateActionCallbacks object.
pImpl.release();
return result;
}
catch (const ADUC::Exception& e)
{
Log_Error("Unhandled ADU Agent exception. code: %d, message: %s", e.Code(), e.Message().c_str());
return ADUC_Result{ ADUC_Result_Failure, e.Code() };
}
catch (const std::exception& e)
{
Log_Error("Unhandled std exception: %s", e.what());
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
catch (...)
{
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
}
/**
* @brief Unregister this module.
*
* @param token Token that was returned from #ADUC_RegisterPlatformLayer call.
*/
void ADUC_Unregister(ADUC_Token token)
{
ADUC::SimulatorPlatformLayer* pImpl{ static_cast<ADUC::SimulatorPlatformLayer*>(token) };
delete pImpl; // NOLINT(cppcoreguidelines-owning-memory)
}
/**
* @brief Reboot the system.
*
* @returns int errno, 0 if success.
*/
int ADUC_RebootSystem()
{
Log_Info("ADUC_RebootSystem called.");
// Here's where the system would be rebooted.
return 0;
}
/**
* @brief Restart the ADU Agent.
*
* @returns int errno, 0 if success.
*/
int ADUC_RestartAgent()
{
Log_Info("ADUC_RestartAgent called.");
// Here's where the agent would be restarted.
return 0;
}
EXTERN_C_END

Просмотреть файл

@ -1,288 +0,0 @@
/**
* @file simulator_adu_core_impl.cpp
* @brief Implements an ADUC "simulator" mode.
*
* Define DISABLE_REAL_DOWNLOADING to disable support for real downloads, e.g. to ease porting.
*
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
#include "simulator_adu_core_impl.hpp"
#include "simulator_device_info.h"
#include <chrono>
#include <future> // this_thread
#include <cstring>
#include <vector>
#include "aduc/logging.h"
#include "aduc/string_utils.hpp"
#include "aduc/workflow_data_utils.h"
#include "aduc/workflow_utils.h"
#include "uhttp_downloader.h"
using ADUC::SimulatorPlatformLayer;
std::unique_ptr<SimulatorPlatformLayer>
SimulatorPlatformLayer::Create(SimulationType type /*= SimulationType::AllSuccessful*/)
{
return std::unique_ptr<SimulatorPlatformLayer>{ new SimulatorPlatformLayer(type) };
}
/**
* @brief Construct a new Simulator Impl object
*
* @param type Simulation type to run.
*/
SimulatorPlatformLayer::SimulatorPlatformLayer(SimulationType type) :
_simulationType(type), _cancellationRequested(false)
{
}
ADUC_Result SimulatorPlatformLayer::SetUpdateActionCallbacks(ADUC_UpdateActionCallbacks* data)
{
// Message handlers.
data->IdleCallback = IdleCallback;
data->DownloadCallback = DownloadCallback;
data->InstallCallback = InstallCallback;
data->ApplyCallback = ApplyCallback;
data->CancelCallback = CancelCallback;
data->IsInstalledCallback = IsInstalledCallback;
data->SandboxCreateCallback = SandboxCreateCallback;
data->SandboxDestroyCallback = SandboxDestroyCallback;
data->DoWorkCallback = DoWorkCallback;
// Opaque token, passed to callbacks.
data->PlatformLayerHandle = this;
return ADUC_Result{ ADUC_Result_Register_Success };
}
void SimulatorPlatformLayer::Idle(const char* workflowId)
{
Log_Info("{%s} Now idle", workflowId);
_cancellationRequested = false;
}
ADUC_Result SimulatorPlatformLayer::Download(const ADUC_WorkflowData* workflowData)
{
ADUC_Result result = { ADUC_Result_Failure };
ADUC_FileEntity* entity = nullptr;
ADUC_WorkflowHandle handle = workflowData->WorkflowHandle;
const char* workflowId = workflow_peek_id(handle);
char* updateType = workflow_get_update_type(handle);
char* workFolder = workflow_get_workfolder(handle);
Log_Info(
"{%s} (UpdateType: %s) Downloading %d files to %s",
workflowId,
updateType,
workflow_get_update_files_count(handle),
workFolder);
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
if (!workflow_get_update_file(handle, 0, &entity))
{
result = { .ResultCode = ADUC_Result_Failure,
.ExtendedResultCode = ADUC_ERC_COMPONENTS_HANDLER_GET_FILE_ENTITY_FAILURE };
goto done;
}
// Note: for simulator, we don't load Update Content Handler.
if (CancellationRequested())
{
Log_Warn("Cancellation requested. Cancelling download");
workflowData->DownloadProgressCallback(workflowId, entity->FileId, ADUC_DownloadProgressState_Cancelled, 0, 0);
result = { ADUC_Result_Failure_Cancelled };
goto done;
}
Log_Info(
"File Info\n\tHash: %s\n\tUri: %s\n\tFile: %s", entity->FileId, entity->DownloadUri, entity->TargetFilename);
if (GetSimulationType() == SimulationType::DownloadFailed)
{
Log_Warn("Simulating a download failure");
workflowData->DownloadProgressCallback(workflowId, entity->FileId, ADUC_DownloadProgressState_Error, 0, 0);
result = { ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
goto done;
}
// Simulation mode.
workflowData->DownloadProgressCallback(
workflowId, entity->FileId, ADUC_DownloadProgressState_Completed, 424242, 424242);
Log_Info("Simulator sleeping...");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// Download in progress.
result = { ADUC_Result_Download_InProgress };
Log_Info("Download resultCode: %d, extendedCode: %d", result.ResultCode, result.ExtendedResultCode);
done:
workflow_free_string(updateType);
workflow_free_string(workFolder);
workflow_free_file_entity(entity);
// Success!
return result;
}
ADUC_Result SimulatorPlatformLayer::Install(const ADUC_WorkflowData* workflowData)
{
ADUC_Result result;
ADUC_WorkflowHandle handle = workflowData->WorkflowHandle;
char* updateType = workflow_get_update_type(handle);
char* workFolder = workflow_get_workfolder(handle);
Log_Info("{%s} Installing from %s", workflow_peek_id(handle), workFolder);
if (CancellationRequested())
{
Log_Warn("\tCancellation requested. Cancelling install");
result = { ADUC_Result_Failure_Cancelled };
goto done;
}
Log_Info("Simulator sleeping...");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (GetSimulationType() == SimulationType::InstallationFailed)
{
Log_Warn("Simulating an install failure");
result = { ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
goto done;
}
result = { ADUC_Result_Install_Success };
done:
workflow_free_string(updateType);
workflow_free_string(workFolder);
return result;
}
ADUC_Result SimulatorPlatformLayer::Apply(const ADUC_WorkflowData* workflowData)
{
ADUC_Result result;
ADUC_WorkflowHandle handle = workflowData->WorkflowHandle;
char* updateType = workflow_get_update_type(handle);
char* workFolder = workflow_get_workfolder(handle);
Log_Info("{%s} Applying data from %s", workflow_peek_id(handle), workFolder);
if (CancellationRequested())
{
Log_Warn("\tCancellation requested. Cancelling apply");
result = { ADUC_Result_Failure_Cancelled };
goto done;
}
Log_Info("Simulator sleeping...");
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (GetSimulationType() == SimulationType::ApplyFailed)
{
Log_Warn("Simulating an apply failure");
result = { ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
goto done;
}
Log_Info("Apply succeeded.");
result = { ADUC_Result_Apply_Success };
done:
workflow_free_string(updateType);
workflow_free_string(workFolder);
// Can alternately return ADUC_Result_Apply_RequiredReboot to indicate reboot required.
// Success is returned here to force a new swVersion to be sent back to the server.
return result;
}
void SimulatorPlatformLayer::Cancel(const ADUC_WorkflowData* workflowData)
{
Log_Info("{%s} Cancel requested", workflow_peek_id(workflowData->WorkflowHandle));
_cancellationRequested = true;
}
ADUC_Result SimulatorPlatformLayer::IsInstalled(const ADUC_WorkflowData* workflowData)
{
Log_Info("IsInstalled called");
ContentHandler* contentHandler = nullptr;
char* installedCriteria = ADUC_WorkflowData_GetInstalledCriteria(workflowData);
char* updateType = ADUC_WorkflowData_GetUpdateType(workflowData);
ADUC_Result result = { ADUC_Result_Failure };
if (updateType == nullptr)
{
result = { ADUC_Result_Failure };
goto done;
}
if (installedCriteria == nullptr)
{
result = { ADUC_Result_IsInstalled_NotInstalled };
goto done;
}
if (GetSimulationType() == SimulationType::IsInstalledFailed)
{
Log_Warn("Simulating IsInstalled failure");
result = { ADUC_Result_Failure, 42 };
goto done;
}
result = ExtensionManager::LoadUpdateContentHandlerExtension(updateType, &contentHandler);
if (IsAducResultCodeFailure(result.ResultCode))
{
goto done;
}
result = { contentHandler->IsInstalled(workflowData) };
done:
workflow_free_string(installedCriteria);
workflow_free_string(updateType);
return result;
}
ADUC_Result SimulatorPlatformLayer::SandboxCreate(const char* workflowId, char* workFolder)
{
Log_Info("{%s} Creating sandbox %s", workflowId, workFolder);
// Simulation.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return ADUC_Result{ ADUC_Result_SandboxCreate_Success };
}
void SimulatorPlatformLayer::SandboxDestroy(const char* workflowId, const char* workFolder)
{
// If SandboxCreate failed or didn't specify a workfolder, we'll get nullptr here.
if (workFolder == nullptr)
{
return;
}
Log_Info("{%s} Deleting sandbox: %s", workflowId, workFolder);
// Simulation.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}

Просмотреть файл

@ -1,506 +0,0 @@
/**
* @file simulator_adu_core_impl.hpp
* @brief Implements an ADUC "simulator" mode.
*
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
#ifndef SIMULATOR_ADU_CORE_IMPL_HPP
#define SIMULATOR_ADU_CORE_IMPL_HPP
#include <exception>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include <aduc/adu_core_exports.h>
#include <aduc/content_handler.hpp>
#include <aduc/exception_utils.hpp>
#include <aduc/logging.h>
#include <aduc/result.h>
/**
* @brief Simulation type to run.
*/
enum class SimulationType
{
DownloadFailed, /**< Simulate a download failure. */
BackupFailed, /**< Simulate a backup failure. */
InstallationFailed, /**< Simulate an install failure. */
ApplyFailed, /**< Simulate an apply failure. */
RestoreFailed, /**< Simulate an restore failure. */
IsInstalledFailed, /**< Simulate IsInstalled failure. */
AllSuccessful, /**< Simulate a successful run. */
};
namespace ADUC
{
/**
* @brief Implementation class for UpdateAction handlers.
*/
class SimulatorPlatformLayer
{
public:
static std::unique_ptr<SimulatorPlatformLayer>
Create(SimulationType type = SimulationType::AllSuccessful);
// Delete copy ctor, copy assignment, move ctor and move assignment operators.
SimulatorPlatformLayer(const SimulatorPlatformLayer&) = delete;
SimulatorPlatformLayer& operator=(const SimulatorPlatformLayer&) = delete;
SimulatorPlatformLayer(SimulatorPlatformLayer&&) = delete;
SimulatorPlatformLayer& operator=(SimulatorPlatformLayer&&) = delete;
~SimulatorPlatformLayer() = default;
/**
* @brief Set the #ADUC_UpdateActionCallbacks object
*
* @param data Object to set.
* @return ADUC_Result ResultCode.
*/
ADUC_Result SetUpdateActionCallbacks(ADUC_UpdateActionCallbacks* data);
private:
//
// Static callbacks.
//
/**
* @brief Implements Idle callback.
*
* @param token Opaque token.
* @param workflowId Current workflow identifier.
*/
static void IdleCallback(ADUC_Token token, const char* workflowId)
{
ADUC::ExceptionUtils::CallVoidMethodAndHandleExceptions(
[&token, &workflowId]() -> void { static_cast<SimulatorPlatformLayer*>(token)->Idle(workflowId); });
}
/**
* @brief Implements Download callback.
*
* @param token Opaque token.
* @param workflowId Current workflow identifier.
* @param updateType
* @param info #ADUC_WrokflowData with information on how to download.
* @return ADUC_Result
*/
/**
* @brief Implements Download callback.
*
* @param token Opaque token.
* @param workCompletionData Contains information on what to do when task is completed.
* @param info ADUC_WorkflowDataToken with information on how to download.
* @return ADUC_Result
*/
static ADUC_Result DownloadCallback(
ADUC_Token token,
const ADUC_WorkCompletionData* workCompletionData,
ADUC_WorkflowDataToken info) noexcept
{
const ADUC_WorkflowData* workflowData = static_cast<const ADUC_WorkflowData*>(info);
try
{
Log_Info("Download thread started");
// Pointers passed to this method are guaranteed to be valid until WorkCompletionCallback is called.
std::thread worker{ [token, workCompletionData, workflowData] {
const ADUC_Result result{ ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure,
[&token, &workCompletionData, &workflowData]() -> ADUC_Result {
return static_cast<SimulatorPlatformLayer*>(token)->Download(workflowData);
}) };
// Report result to main thread.
workCompletionData->WorkCompletionCallback(workCompletionData->WorkCompletionToken, result, true /* isAsync */);
} };
// Allow the thread to work independently of this main thread.
worker.detach();
// Indicate that we've spun off a thread to do the actual work.
return ADUC_Result{ ADUC_Result_Download_InProgress };
}
catch (const ADUC::Exception& e)
{
Log_Error("Unhandled ADU Agent exception. code: %d, message: %s", e.Code(), e.Message().c_str());
return ADUC_Result{ ADUC_Result_Failure, e.Code() };
}
catch (const std::exception& e)
{
Log_Error("Unhandled std exception: %s", e.what());
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
catch (...)
{
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
}
/**
* @brief Implements Install callback.
*
* @param token Opaque token.
* @param workCompletionData Contains information on what to do when task is completed.
* @param info #ADUC_WorkflowData with information on how to install.
* @return ADUC_Result
*/
static ADUC_Result InstallCallback(
ADUC_Token token,
const ADUC_WorkCompletionData* workCompletionData,
ADUC_WorkflowDataToken info) noexcept
{
const ADUC_WorkflowData* workflowData = static_cast<const ADUC_WorkflowData*>(info);
try
{
Log_Info("Install thread started");
// Pointers passed to this method are guaranteed to be valid until WorkCompletionCallback is called.
std::thread worker{ [token, workCompletionData, workflowData] {
const ADUC_Result result{ ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure, [&token, &workCompletionData, &workflowData]() -> ADUC_Result {
return static_cast<SimulatorPlatformLayer*>(token)->Install(workflowData);
}) };
// Report result to main thread.
workCompletionData->WorkCompletionCallback(workCompletionData->WorkCompletionToken, result, true /* isAsync */);
} };
// Allow the thread to work independently of this main thread.
worker.detach();
// Indicate that we've spun off a thread to do the actual work.
return ADUC_Result{ ADUC_Result_Install_InProgress };
}
catch (const ADUC::Exception& e)
{
Log_Error("Unhandled ADU Agent exception. code: %d, message: %s", e.Code(), e.Message().c_str());
return ADUC_Result{ ADUC_Result_Failure, e.Code() };
}
catch (const std::exception& e)
{
Log_Error("Unhandled std exception: %s", e.what());
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
catch (...)
{
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
}
/**
* @brief Implements Apply callback.
*
* @param token Opaque token.
* @param workCompletionData Contains information on what to do when task is completed.
* @param info #ADUC_WorkflowData with information on how to apply.
* @return ADUC_Result
*/
static ADUC_Result ApplyCallback(
ADUC_Token token,
const ADUC_WorkCompletionData* workCompletionData,
ADUC_WorkflowDataToken info) noexcept
{
const ADUC_WorkflowData* workflowData = static_cast<const ADUC_WorkflowData*>(info);
try
{
Log_Info("Apply thread started");
// Pointers passed to this method are guaranteed to be valid until WorkCompletionCallback is called.
std::thread worker{ [token, workCompletionData, workflowData] {
const ADUC_Result result{ ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure, [&token, &workCompletionData, &workflowData]() -> ADUC_Result {
return static_cast<SimulatorPlatformLayer*>(token)->Apply(workflowData);
}) };
// Report result to main thread.
workCompletionData->WorkCompletionCallback(workCompletionData->WorkCompletionToken, result, true /* isAsync */);
} };
// Allow the thread to work independently of this main thread.
worker.detach();
// Indicate that we've spun off a thread to do the actual work.
return ADUC_Result{ ADUC_Result_Apply_InProgress };
}
catch (const ADUC::Exception& e)
{
Log_Error("Unhandled ADU Agent exception. code: %d, message: %s", e.Code(), e.Message().c_str());
return ADUC_Result{ ADUC_Result_Failure, e.Code() };
}
catch (const std::exception& e)
{
Log_Error("Unhandled std exception: %s", e.what());
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
catch (...)
{
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
}
/**
* @brief Implements Backup callback.
*
* @param token Opaque token.
* @param workCompletionData Contains information on what to do when task is completed.
* @param info #ADUC_WorkflowData with information on how to backup.
* @return ADUC_Result
*/
static ADUC_Result BackupCallback(
ADUC_Token token, const ADUC_WorkCompletionData* workCompletionData, ADUC_WorkflowDataToken info) noexcept
{
const ADUC_WorkflowData* workflowData = static_cast<const ADUC_WorkflowData*>(info);
try
{
Log_Info("Backup thread started");
// Pointers passed to this method are guaranteed to be valid until WorkCompletionCallback is called.
std::thread worker{ [token, workCompletionData, workflowData] {
const ADUC_Result result{ ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure, [&token, &workCompletionData, &workflowData]() -> ADUC_Result {
return static_cast<SimulatorPlatformLayer*>(token)->Backup(workflowData);
}) };
// Report result to main thread.
workCompletionData->WorkCompletionCallback(workCompletionData->WorkCompletionToken, result, true /* isAsync */);
} };
// Allow the thread to work independently of this main thread.
worker.detach();
// Indicate that we've spun off a thread to do the actual work.
return ADUC_Result{ ADUC_Result_Backup_InProgress };
}
catch (const ADUC::Exception& e)
{
Log_Error("Unhandled ADU Agent exception. code: %d, message: %s", e.Code(), e.Message().c_str());
return ADUC_Result{ ADUC_Result_Failure, e.Code() };
}
catch (const std::exception& e)
{
Log_Error("Unhandled std exception: %s", e.what());
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
catch (...)
{
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
}
/**
* @brief Implements Restore callback.
*
* @param token Opaque token.
* @param workCompletionData Contains information on what to do when task is completed.
* @param info #ADUC_WorkflowData with information on how to restore.
* @return ADUC_Result
*/
static ADUC_Result RestoreCallback(
ADUC_Token token, const ADUC_WorkCompletionData* workCompletionData, ADUC_WorkflowDataToken info) noexcept
{
const ADUC_WorkflowData* workflowData = static_cast<const ADUC_WorkflowData*>(info);
try
{
Log_Info("Restore thread started");
// Pointers passed to this method are guaranteed to be valid until WorkCompletionCallback is called.
std::thread worker{ [token, workCompletionData, workflowData] {
const ADUC_Result result{ ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure, [&token, &workCompletionData, &workflowData]() -> ADUC_Result {
return static_cast<SimulatorPlatformLayer*>(token)->Restore(workflowData);
}) };
// Report result to main thread.
workCompletionData->WorkCompletionCallback(workCompletionData->WorkCompletionToken, result, true /* isAsync */);
} };
// Allow the thread to work independently of this main thread.
worker.detach();
// Indicate that we've spun off a thread to do the actual work.
return ADUC_Result{ ADUC_Result_Restore_InProgress };
}
catch (const ADUC::Exception& e)
{
Log_Error("Unhandled ADU Agent exception. code: %d, message: %s", e.Code(), e.Message().c_str());
return ADUC_Result{ ADUC_Result_Failure, e.Code() };
}
catch (const std::exception& e)
{
Log_Error("Unhandled std exception: %s", e.what());
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
catch (...)
{
return ADUC_Result{ ADUC_Result_Failure, ADUC_ERC_NOTRECOVERABLE };
}
}
/**
* @brief Implements Cancel callback.
*
* @param token Opaque token.
* @param info #ADUC_WorkflowData with information on how to apply.
*/
static void CancelCallback(ADUC_Token token, ADUC_WorkflowDataToken info) noexcept
{
Log_Info("CancelCallback called");
const ADUC_WorkflowData* workflowData = static_cast<const ADUC_WorkflowData*>(info);
ADUC::ExceptionUtils::CallVoidMethodAndHandleExceptions([&token, &workflowData]() -> void {
static_cast<SimulatorPlatformLayer*>(token)->Cancel(workflowData);
});
}
static ADUC_Result IsInstalledCallback(ADUC_Token token, ADUC_WorkflowDataToken info) noexcept
{
Log_Info("IsInstalledCallback called");
const ADUC_WorkflowData* workflowData = static_cast<const ADUC_WorkflowData*>(info);
return ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure, [&token, &workflowData]() -> ADUC_Result {
return static_cast<SimulatorPlatformLayer*>(token)->IsInstalled(workflowData);
});
}
/**
* @brief Implements SandboxCreate callback.
*
* @param token Contains pointer to our class instance.
* @param workFolder Location of sandbox, or NULL if no sandbox is required, e.g. fileless OS.
* Must be allocated using malloc.
*
* @return ADUC_Result
*/
static ADUC_Result SandboxCreateCallback(ADUC_Token token, const char* workflowId, char* workFolder)
{
return ADUC::ExceptionUtils::CallResultMethodAndHandleExceptions(
ADUC_Result_Failure, [&token, &workflowId, &workFolder]() -> ADUC_Result {
return static_cast<SimulatorPlatformLayer*>(token)->SandboxCreate(workflowId, workFolder);
});
}
/**
* @brief Implements SandboxDestroy callback.
*
* @param token Contains pointer to our class instance.
* @param workflowId Unique workflow identifier.
* @param workFolder Sandbox that was returned from SandboxCreate - can be NULL.
*/
static void SandboxDestroyCallback(ADUC_Token token, const char* workflowId, const char* workFolder)
{
ADUC::ExceptionUtils::CallVoidMethodAndHandleExceptions([&token, &workflowId, &workFolder]() -> void {
static_cast<SimulatorPlatformLayer*>(token)->SandboxDestroy(workflowId, workFolder);
});
}
/**
* @brief Implements DoWork callback.
*
* @param token Opaque token.
* @param workflowData Current workflow data object.
*/
static void DoWorkCallback(ADUC_Token token, ADUC_WorkflowDataToken workflowData) noexcept
{
// Not used in this example.
// Not used in this code.
UNREFERENCED_PARAMETER(token);
UNREFERENCED_PARAMETER(workflowData);
}
//
// Implementation.
//
// Private constructor, must use Create factory method to creat an object.
SimulatorPlatformLayer(SimulationType type);
/**
* @brief Class implementation of Idle method.
*/
void Idle(const char* workflowId);
/**
* @brief Class implementation of Download method.
* @return ADUC_Result
*/
ADUC_Result Download(const ADUC_WorkflowData* workflowData);
/**
* @brief Class implementation of Install method.
* @return ADUC_Result
*/
ADUC_Result Install(const ADUC_WorkflowData* workflowData);
/**
* @brief Class implementation of Apply method.
* @return ADUC_Result
*/
ADUC_Result Apply(const ADUC_WorkflowData* workflowData);
/**
* @brief Class implementation of Cancel method.
*/
void Cancel(const ADUC_WorkflowData* workflowData);
ADUC_Result IsInstalled(const ADUC_WorkflowData* workflowData);
/**
* @brief Class implementation of SandboxCreate method.
* @param workflowId Unique workflow identifier.
* @param workFolder Location of sandbox, or NULL if no sandbox is required, e.g. fileless OS.
* Must be allocated using malloc.
*/
ADUC_Result SandboxCreate(const char* workflowId, char* workFolder);
/**
* @brief Class implementation of SandboxDestroy method.
*
* @param workflowId Unique workflow identifier.
* @param workFolder Sandbox that was returned from SandboxCreate - can be NULL.
*/
void SandboxDestroy(const char* workflowId, const char* workFolder);
//
// Accessors.
//
/**
* @brief Get the #SimulationType object
*
* @return SimulationType
*/
SimulationType GetSimulationType() const
{
return _simulationType;
}
/**
* @brief Determine if cancellation was requested.
*
* @return bool True if requested.
*/
bool CancellationRequested() const
{
return _cancellationRequested;
}
//
// Members.
//
/**
* @brief Simulation that's being run.
*/
SimulationType _simulationType;
/**
* @brief Was Cancel called?
*/
bool _cancellationRequested;
};
} // namespace ADUC
#endif // SIMULATOR_ADU_CORE_IMPL_HPP

Просмотреть файл

@ -1,105 +0,0 @@
/**
* @file simulator_device_info.cpp
* @brief Methods to set and return simulated device info values.
*
* These methods are not thread safe.
*
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
#include "simulator_device_info.h"
#include <string>
/**
* @brief Simulated manufacturer.
*/
static std::string g_simulatedManufacturer{ ADUC_DEVICEINFO_MANUFACTURER }; // NOLINT(cert-err58-cpp)
/**
* @brief Simulated model.
*/
static std::string g_simulatedModel{ ADUC_DEVICEINFO_MODEL }; // NOLINT(cert-err58-cpp)
/**
* @brief Simulated software version.
*/
static std::string g_simulatedSwVersion{ "0.0.0.0" }; // NOLINT(cert-err58-cpp)
/**
* @brief Set the simulated manufacturer name.
*
* @param manufacturer Manufacturer name.
*/
void Simulator_DeviceInfo_SetManufacturer(const char* manufacturer)
{
try
{
g_simulatedManufacturer = manufacturer;
}
catch (...)
{
}
}
/**
* @brief Get the simulated manufacturer name.
*
* @return const char* Manufacturer name.
*/
const char* Simulator_DeviceInfo_GetManufacturer()
{
return g_simulatedManufacturer.c_str();
}
/**
* @brief Set the simulated model name.
*
* @param model Model name.
*/
void Simulator_DeviceInfo_SetModel(const char* model)
{
try
{
g_simulatedModel = model;
}
catch (...)
{
}
}
/**
* @brief Get the simulated model name.
*
* @return const char* Model name.
*/
const char* Simulator_DeviceInfo_GetModel()
{
return g_simulatedModel.c_str();
}
/**
* @brief Set the simulated software version.
*
* @param version Software version.
*/
void Simulator_DeviceInfo_SetSwVersion(const char* version)
{
try
{
g_simulatedSwVersion = version;
}
catch (...)
{
}
}
/**
* @brief Get the simulated software version.
*
* @return const char* Software version.
*/
const char* Simulator_DeviceInfo_GetSwVersion()
{
return g_simulatedSwVersion.c_str();
}

Просмотреть файл

@ -1,22 +0,0 @@
/**
* @file simulator_device_info.h
* @brief Methods to set and return simulated device info values.
*
* These methods are not thread safe.
*
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
#ifndef SIMULATOR_DEVICE_INFO_H
#define SIMULATOR_DEVICE_INFO_H
void Simulator_DeviceInfo_SetManufacturer(const char* manufacturer);
const char* Simulator_DeviceInfo_GetManufacturer();
void Simulator_DeviceInfo_SetModel(const char* model);
const char* Simulator_DeviceInfo_GetModel();
void Simulator_DeviceInfo_SetSwVersion(const char* version);
const char* Simulator_DeviceInfo_GetSwVersion();
#endif // SIMULATOR_DEVICE_INFO_H

Просмотреть файл

@ -1,248 +0,0 @@
/**
* @file simulator_device_info_exports.cpp
* @brief Implements exported methods for platform-specific device information code.
*
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*/
#include "simulator_device_info.h"
#include <functional>
#include <unordered_map>
#include <cstring>
#include <aduc/device_info_exports.h>
/**
* @brief Get manufacturer
* Company name of the device manufacturer.
* This could be the same as the name of the original equipment manufacturer (OEM).
* e.g. Contoso
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetManufacturer()
{
// Value must be returned at least once, so initialize to true.
static std::string lastReportedValue;
if (lastReportedValue == Simulator_DeviceInfo_GetManufacturer())
{
// Value hasn't changed since last report.
return nullptr;
}
try
{
lastReportedValue = Simulator_DeviceInfo_GetManufacturer();
}
catch (...)
{
}
return strdup(lastReportedValue.c_str());
}
/**
* @brief Get device model.
* Device model name or ID.
* e.g. Surface Book 2
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetModel()
{
// Value must be returned at least once, so initialize to true.
static std::string lastReportedValue;
if (lastReportedValue == Simulator_DeviceInfo_GetModel())
{
// Value hasn't changed since last report.
return nullptr;
}
try
{
lastReportedValue = Simulator_DeviceInfo_GetModel();
}
catch (...)
{
}
return strdup(lastReportedValue.c_str());
}
/**
* @brief Get operating system name.
* Name of the operating system on the device.
* e.g. Windows 10 IoT Core
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetOsName()
{
// Value must be returned at least once, so initialize to true.
static bool valueIsDirty = true;
if (valueIsDirty)
{
valueIsDirty = false;
return strdup("Linux");
}
// Value not expected to change again, so return nullptr;
return nullptr;
}
/**
* @brief Get software version.
* Version of the software on your device.
* This could be the version of your firmware.
* e.g. 1.3.45
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetSwVersion()
{
// Value must be returned at least once, so initialize to true.
static std::string lastReportedValue;
if (lastReportedValue == Simulator_DeviceInfo_GetSwVersion())
{
// Value hasn't changed since last report.
return nullptr;
}
try
{
lastReportedValue = Simulator_DeviceInfo_GetSwVersion();
}
catch (...)
{
}
return strdup(lastReportedValue.c_str());
}
/**
* @brief Get processor architecture.
* Architecture of the processor on the device.
* e.g. x64
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetProcessorArchitecture()
{
// Value must be returned at least once, so initialize to true.
static bool valueIsDirty = true;
if (valueIsDirty)
{
valueIsDirty = false;
return strdup("x86_64");
}
// Value not expected to change again, so return nullptr;
return nullptr;
}
/**
* @brief Get processor manufacturer.
* Name of the manufacturer of the processor on the device.
* e.g. Intel
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetProcessorManufacturer()
{
// Value must be returned at least once, so initialize to true.
static bool valueIsDirty = true;
if (valueIsDirty)
{
valueIsDirty = false;
return strdup("GenuineIntel");
}
// Value not expected to change again, so return nullptr;
return nullptr;
}
/**
* @brief Get total memory.
* Total available memory on the device in kilobytes.
* e.g. 256000
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetTotalMemory()
{
// Value must be returned at least once, so initialize to true.
static bool valueIsDirty = true;
if (valueIsDirty)
{
valueIsDirty = false;
return strdup("256000");
}
// Value not expected to change again, so return nullptr;
return nullptr;
}
/**
* @brief Get total storage.
* Total available storage on the device in kilobytes.
* e.g. 2048000
*
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
static char* DeviceInfo_GetTotalStorage()
{
// Value must be returned at least once, so initialize to true.
static bool valueIsDirty = true;
if (valueIsDirty)
{
valueIsDirty = false;
return strdup("2048000");
}
// Value not expected to change again, so return nullptr;
return nullptr;
}
//
// Exported methods
//
EXTERN_C_BEGIN
/**
* @brief Return a specific device information value.
*
* @param property Property to retrieve
* @return char* Value of property allocated with malloc, or nullptr on error or value not changed since last call.
*/
char* DI_GetDeviceInformationValue(DI_DeviceInfoProperty property)
{
char* value = nullptr;
try
{
const std::unordered_map<DI_DeviceInfoProperty, std::function<char*()>> simulationMap{
{ DIIP_Manufacturer, DeviceInfo_GetManufacturer },
{ DIIP_Model, DeviceInfo_GetModel },
{ DIIP_OsName, DeviceInfo_GetOsName },
{ DIIP_SoftwareVersion, DeviceInfo_GetSwVersion },
{ DIIP_ProcessorArchitecture, DeviceInfo_GetProcessorArchitecture },
{ DIIP_ProcessorManufacturer, DeviceInfo_GetProcessorManufacturer },
{ DIIP_TotalMemory, DeviceInfo_GetTotalMemory },
{ DIIP_TotalStorage, DeviceInfo_GetTotalStorage },
};
// Call the handler for the device info property to retrieve current value.
value = simulationMap.at(property)();
}
catch (...)
{
value = nullptr;
}
return value;
}
EXTERN_C_END

Просмотреть файл

@ -1,440 +0,0 @@
/**
* @file uhttp_downloader.cpp
* @brief Simple HTTP downloader based on uHTTP
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
* Note that uHTTP is a rudimentary HTTP implementation and may not support production-level requirements.
*/
#include "uhttp_downloader.h"
#include <azure_c_shared_utility/azure_base64.h>
#include <azure_c_shared_utility/buffer_.h>
#include <azure_c_shared_utility/platform.h>
#include <azure_c_shared_utility/sha.h>
#include <azure_c_shared_utility/socketio.h>
#include <azure_c_shared_utility/tlsio.h>
#include <azure_uhttp_c/uhttp.h>
#include <fstream>
#include <string>
#include <aduc/logging.h>
class UHttpDownloader
{
public:
UHttpDownloader() = default;
~UHttpDownloader() = default;
UHttpDownloader(const UHttpDownloader&) = delete;
UHttpDownloader& operator=(const UHttpDownloader&) = delete;
UHttpDownloader(UHttpDownloader&&) = delete;
UHttpDownloader& operator=(UHttpDownloader&&) = delete;
UHttpDownloaderResult
Download(const char* url, const char* base64Sha256Hash, const char* outputFile, unsigned int timeoutSecs);
static UHttpDownloaderResult ResultFromHttpClientResult(HTTP_CLIENT_RESULT result);
static UHttpDownloaderResult ResultFromHttpCallbackReason(HTTP_CALLBACK_REASON result);
private:
bool HashMatches(const unsigned char* content, size_t content_len);
void OnRequestCallback(
HTTP_CALLBACK_REASON reason,
const unsigned char* content,
size_t content_len,
unsigned int statusCode,
HTTP_HEADERS_HANDLE /*responseHeadersHandle*/);
static UHttpDownloaderResult
ParseUrl(const char* url, unsigned* port, std::string* hostName, std::string* relativePath)
{
std::string temp{ url };
size_t scheme_cch;
if (temp.substr(0, 7) == "http://")
{
*port = 80;
scheme_cch = 7;
}
else if (temp.substr(0, 8) == "https://")
{
*port = 443;
scheme_cch = 8;
}
else
{
return DR_INVALID_ARG;
}
// NOTE: Assumes port isn't specified, e.g. "example.com:80"
const std::size_t start = temp.find('/', scheme_cch);
if (start == std::string::npos)
{
return DR_INVALID_ARG;
}
const std::size_t end = temp.find('/', start);
if (end == std::string::npos)
{
return DR_INVALID_ARG;
}
*hostName = temp.substr(scheme_cch, start - scheme_cch);
*relativePath = temp.substr(end);
return DR_OK;
}
std::string m_base64Sha256Hash;
std::string m_outputFile;
bool m_keepRunning = false;
UHttpDownloaderResult m_reason = DR_INVALID_STATE;
unsigned int m_statusCode = 500;
};
bool UHttpDownloader::HashMatches(const unsigned char* content, size_t content_len)
{
bool hashMatches = false;
const SHAversion algorithm = SHAversion::SHA256;
USHAContext context;
if (USHAReset(&context, algorithm) == 0)
{
if (USHAInput(&context, content, content_len) == 0)
{
// "USHAHashSize(algorithm)" is more precise, but requires a variable length array, or heap allocation.
unsigned char buffer_hash[USHAMaxHashSize];
if (USHAResult(&context, buffer_hash) == 0)
{
STRING_HANDLE encoded_file_hash = Azure_Base64_Encode_Bytes(buffer_hash, USHAHashSize(algorithm));
if (encoded_file_hash != nullptr)
{
hashMatches = (strcmp(m_base64Sha256Hash.c_str(), STRING_c_str(encoded_file_hash)) == 0);
STRING_delete(encoded_file_hash);
}
}
}
}
return hashMatches;
}
void UHttpDownloader::OnRequestCallback(
HTTP_CALLBACK_REASON reason,
const unsigned char* content,
size_t content_len,
unsigned int statusCode,
HTTP_HEADERS_HANDLE /*responseHeadersHandle*/)
{
// No more work to do after we get the callback.
m_keepRunning = false;
m_reason = ResultFromHttpCallbackReason(reason);
if (reason != HTTP_CALLBACK_REASON_OK)
{
Log_Warn("onrequestcallback failed, error %u", reason);
return;
}
if (statusCode != 200)
{
Log_Warn("onrequestcallback failed, statuscode %u", statusCode);
m_reason = DR_CALLBACK_ERROR;
m_statusCode = statusCode;
return;
}
//
// We've got data!
//
// check the hash.
if (!HashMatches(content, content_len))
{
Log_Warn("Invalid content hash");
m_reason = DR_CALLBACK_ERROR;
return;
}
// Hash checks out, so Write it to a file.
std::ofstream ofile(m_outputFile, std::ios::binary);
if (ofile.fail())
{
Log_Warn("unable to open %s", m_outputFile.c_str());
m_reason = DR_FILE_ERROR;
return;
}
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
ofile.write(reinterpret_cast<const char*>(content), sizeof(*content) * content_len);
if (ofile.fail())
{
Log_Warn("unable to write %s", m_outputFile.c_str());
m_reason = DR_FILE_ERROR;
return;
}
}
UHttpDownloaderResult UHttpDownloader::Download(
const char* url, const char* base64Sha256Hash, const char* outputFile, unsigned int timeoutSecs)
{
// RAII wrapper for HTTP_CLIENT_HANDLE
class HttpClientHandle
{
public:
explicit HttpClientHandle(HTTP_CLIENT_HANDLE handle) : _handle(handle)
{
}
~HttpClientHandle()
{
if (_handle != nullptr)
{
uhttp_client_close(
_handle,
[](void* /*context*/) {
// auto instance = static_cast<UHttpDownloader*>(context);
},
this);
uhttp_client_destroy(_handle);
}
}
HttpClientHandle(const HttpClientHandle&) = delete;
HttpClientHandle& operator=(const HttpClientHandle&) = delete;
HttpClientHandle(HttpClientHandle&&) = delete;
HttpClientHandle& operator=(HttpClientHandle&&) = delete;
HTTP_CLIENT_HANDLE Get() const
{
return _handle;
}
private:
HTTP_CLIENT_HANDLE _handle;
};
unsigned int port;
std::string hostname;
std::string relativePath;
m_reason = ParseUrl(url, &port, &hostname, &relativePath);
if (m_reason != DR_OK)
{
Log_Warn("ParseUrl failed, error %u", m_reason);
return m_reason;
}
m_base64Sha256Hash = base64Sha256Hash;
m_outputFile = outputFile;
m_keepRunning = true;
m_statusCode = 200;
//
// Create HTTP or HTTPS uHttp client.
//
const IO_INTERFACE_DESCRIPTION* io_interface_desc;
TLSIO_CONFIG tlsIoConfig = {}; // HTTPS
SOCKETIO_CONFIG socketIoConfig = {}; // HTTP
const void* xioParam; // points to either tlsIoConfig or socketIoConfig.
if (port != 80)
{
// HTTPS
tlsIoConfig.hostname = hostname.c_str();
tlsIoConfig.port = port;
xioParam = &tlsIoConfig;
// Get the TLS definition
io_interface_desc = platform_get_default_tlsio();
}
else
{
// HTTP
socketIoConfig.hostname = hostname.c_str();
socketIoConfig.port = port;
xioParam = &socketIoConfig;
// Get the socket definition
io_interface_desc = socketio_get_interface_description();
}
HttpClientHandle handle{ uhttp_client_create(
io_interface_desc,
xioParam,
[](void* context, HTTP_CALLBACK_REASON reason) -> void {
auto instance = static_cast<UHttpDownloader*>(context);
instance->m_reason = ResultFromHttpCallbackReason(reason);
if (reason != HTTP_CALLBACK_REASON_OK)
{
instance->m_keepRunning = false;
return;
}
},
this) };
if (handle.Get() == nullptr)
{
Log_Warn("client_create failed");
return DR_ERROR;
}
//
// Open uHttp connection.
//
HTTP_CLIENT_RESULT result;
result = uhttp_client_open(
handle.Get(),
hostname.c_str(),
port,
[](void* context, HTTP_CALLBACK_REASON reason) -> void {
auto instance = static_cast<UHttpDownloader*>(context);
instance->m_reason = ResultFromHttpCallbackReason(reason);
if (reason != HTTP_CALLBACK_REASON_OK)
{
Log_Warn("client_open callback failed, error %u", reason);
instance->m_keepRunning = false;
return;
}
},
this);
if (result != HTTP_CLIENT_OK)
{
Log_Warn("client_create failed, error %u", result);
return ResultFromHttpClientResult(result);
}
//
// Execute the GET request.
//
result = uhttp_client_execute_request(
handle.Get(),
HTTP_CLIENT_REQUEST_GET,
relativePath.c_str(),
nullptr /*HTTP_HEADERS_HANDLE*/,
nullptr /*content*/,
0 /*content_len*/,
[](void* context,
HTTP_CALLBACK_REASON reason,
const unsigned char* content,
size_t content_len,
unsigned int statusCode,
HTTP_HEADERS_HANDLE responseHeadersHandle) -> void {
auto instance = static_cast<UHttpDownloader*>(context);
instance->OnRequestCallback(reason, content, content_len, statusCode, responseHeadersHandle);
},
this);
if (result != HTTP_CLIENT_OK)
{
Log_Warn("client_execute failed, error %u", result);
return ResultFromHttpClientResult(result);
}
//
// Start worker loop. Run until complete or timeout.
//
const time_t start_request_time = get_time(nullptr);
bool timeout = false;
do
{
uhttp_client_dowork(handle.Get());
timeout = difftime(get_time(nullptr), start_request_time) > timeoutSecs;
} while (m_keepRunning && !timeout);
if (timeout)
{
Log_Warn("dowork timed out");
return DR_TIMEOUT;
}
return m_reason;
}
/* static */
UHttpDownloaderResult UHttpDownloader::ResultFromHttpClientResult(HTTP_CLIENT_RESULT result)
{
using ResultMap = struct tagResultMap
{
HTTP_CLIENT_RESULT From;
UHttpDownloaderResult To;
};
const ResultMap resultMap[] = {
{ HTTP_CLIENT_OK, DR_OK },
{ HTTP_CLIENT_INVALID_ARG, DR_INVALID_ARG },
{ HTTP_CLIENT_ERROR, DR_ERROR },
{ HTTP_CLIENT_OPEN_FAILED, DR_OPEN_FAILED },
{ HTTP_CLIENT_SEND_FAILED, DR_SEND_FAILED },
{ HTTP_CLIENT_ALREADY_INIT, DR_ALREADY_INIT },
{ HTTP_CLIENT_HTTP_HEADERS_FAILED, DR_HTTP_HEADERS_FAILED },
{ HTTP_CLIENT_INVALID_STATE, DR_INVALID_STATE },
};
for (const ResultMap& entry : resultMap)
{
if (result == entry.From)
{
return entry.To;
}
}
return DR_ERROR;
}
/* static */
UHttpDownloaderResult UHttpDownloader::ResultFromHttpCallbackReason(HTTP_CALLBACK_REASON result)
{
using ResultMap = struct tagResultMap
{
HTTP_CALLBACK_REASON From;
UHttpDownloaderResult To;
};
const ResultMap resultMap[] = {
// #define HTTP_CALLBACK_REASON_VALUES
{ HTTP_CALLBACK_REASON_OK, DR_OK },
{ HTTP_CALLBACK_REASON_OPEN_FAILED, DR_CALLBACK_OPEN_FAILED },
{ HTTP_CALLBACK_REASON_SEND_FAILED, DR_CALLBACK_SEND_FAILED },
{ HTTP_CALLBACK_REASON_ERROR, DR_CALLBACK_ERROR },
{ HTTP_CALLBACK_REASON_PARSING_ERROR, DR_CALLBACK_PARSING_ERROR },
{ HTTP_CALLBACK_REASON_DESTROY, DR_CALLBACK_DESTROY },
{ HTTP_CALLBACK_REASON_DISCONNECTED, DR_CALLBACK_DISCONNECTED },
};
for (const ResultMap& entry : resultMap)
{
if (result == entry.From)
{
return entry.To;
}
}
return DR_CALLBACK_ERROR;
}
UHttpDownloaderResult
DownloadFile(const char* url, const char* base64Sha256Hash, const char* outputFile, unsigned int timeoutSecs)
{
UHttpDownloader downloader;
return downloader.Download(url, base64Sha256Hash, outputFile, timeoutSecs);
}

Просмотреть файл

@ -1,37 +0,0 @@
/**
* @file uhttp_downloader.h
* @brief Simple HTTP downloader based on uHTTP
* @copyright Copyright (c) Microsoft Corporation.
* Licensed under the MIT License.
*
* Note that uHTTP is a rudimentary HTTP implementation and may not support production-level requirements.
*/
#ifndef UHTTP_DOWNLOADER_H
#define UHTTP_DOWNLOADER_H
typedef enum tagUHttpDownloaderResult
{
DR_OK,
DR_INVALID_ARG,
DR_TIMEOUT,
DR_FILE_ERROR,
DR_ERROR,
DR_OPEN_FAILED,
DR_SEND_FAILED,
DR_ALREADY_INIT,
DR_HTTP_HEADERS_FAILED,
DR_INVALID_STATE,
DR_CALLBACK_OPEN_FAILED,
DR_CALLBACK_SEND_FAILED,
DR_CALLBACK_ERROR,
DR_CALLBACK_PARSING_ERROR,
DR_CALLBACK_DESTROY,
DR_CALLBACK_DISCONNECTED,
} UHttpDownloaderResult;
UHttpDownloaderResult
DownloadFile(const char* url, const char* base64Sha256Hash, const char* outputFile, unsigned int timeoutSecs = 60);
#endif // UHTTP_DOWNLOADER_H

Просмотреть файл

@ -223,6 +223,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Missing Update Name")
@ -231,6 +232,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Missing Version Number")
@ -239,6 +241,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Missing Delimiter")
@ -247,6 +250,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Negative Number")
@ -255,6 +259,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Ransome Negative Number")
@ -263,6 +268,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Zero")
@ -273,6 +279,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
CHECK(ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
CHECK_THAT(updateTypeName, Equals("microsoft/apt"));
CHECK(updateTypeVersion == 0);
free(updateTypeName);
}
SECTION("Positive Number")
@ -283,6 +290,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
CHECK(ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
CHECK_THAT(updateTypeName, Equals("microsoft/apt"));
CHECK(updateTypeVersion == 1);
free(updateTypeName);
}
SECTION("Positive Large Number")
@ -293,6 +301,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
CHECK(ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
CHECK_THAT(updateTypeName, Equals("microsoft/apt"));
CHECK(updateTypeVersion == 4294967294);
free(updateTypeName);
}
SECTION("Positive UINT MAX")
@ -301,6 +310,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Positive Larger Than UINT MAX")
@ -309,6 +319,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Positive ULONG MAX")
@ -317,6 +328,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Version contains space")
@ -325,6 +337,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
SECTION("Decimal version")
@ -333,6 +346,7 @@ TEST_CASE("ADUC_ParseUpdateType and atoui")
char* updateTypeName = nullptr;
unsigned int updateTypeVersion;
CHECK(!ADUC_ParseUpdateType(updateType, &updateTypeName, &updateTypeVersion));
free(updateTypeName);
}
}

Просмотреть файл

@ -17,10 +17,6 @@ target_include_directories (${PROJECT_NAME} PUBLIC inc)
target_compile_definitions (${PROJECT_NAME} PRIVATE ADUC_CONF_FILE_PATH="${ADUC_CONF_FILE_PATH}"
ADUC_PLATFORM_LAYER="${ADUC_PLATFORM_LAYER}")
if (ADUC_PLATFORM_LAYER STREQUAL "simulator")
target_compile_definitions (${PROJECT_NAME} PRIVATE ADUC_PLATFORM_SIMULATOR)
endif ()
target_link_libraries (
${PROJECT_NAME}
PUBLIC aduc::c_utils

Просмотреть файл

@ -61,8 +61,6 @@ typedef struct tagADUC_ConfigInfo
char* model; /**< Device info model. */
bool simulateUnhealthyState; /**< A configuration for simulator. */
char* edgegatewayCertPath; /**< Edge gateway certificate path */
ADUC_AgentInfo* agents; /**< Array of agents that are configured. */

Просмотреть файл

@ -296,10 +296,6 @@ bool ADUC_ConfigInfo_Init(ADUC_ConfigInfo* config, const char* configFilePath)
}
}
#ifdef ADUC_PLATFORM_SIMULATOR
config->simulateUnhealthyState = ADUC_JSON_GetBooleanField(root_value, "simulateUnhealthyState");
#endif
const JSON_Object* root_object = json_value_get_object(root_value);
config->aduShellTrustedUsers = json_object_get_array(root_object, "aduShellTrustedUsers");

Просмотреть файл

@ -26,10 +26,6 @@ target_compile_definitions (
${PROJECT_NAME} PRIVATE ADUC_CONF_FILE_PATH="${ADUC_CONF_FILE_PATH}"
ADUC_PLATFORM_LAYER="${ADUC_PLATFORM_LAYER}")
if (ADUC_PLATFORM_LAYER STREQUAL "simulator")
target_compile_definitions (${PROJECT_NAME} PRIVATE ADUC_PLATFORM_SIMULATOR)
endif ()
include (CTest)
include (Catch)
catch_discover_tests (${PROJECT_NAME})

Просмотреть файл

@ -29,7 +29,6 @@ static const char* validConfigContentStr =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": true,)"
R"("manufacturer": "device_info_manufacturer",)"
R"("model": "device_info_model",)"
R"("compatPropertyNames": "manufacturer,model",)"
@ -61,7 +60,6 @@ static const char* validConfigContentNoCompatPropertyNames =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": true,)"
R"("manufacturer": "device_info_manufacturer",)"
R"("model": "device_info_model",)"
R"("agents": [)"
@ -92,7 +90,6 @@ static const char* validConfigContentMqttIotHubProtocol =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": true,)"
R"("manufacturer": "device_info_manufacturer",)"
R"("model": "device_info_model",)"
R"("iotHubProtocol": "mqtt",)"
@ -124,7 +121,6 @@ static const char* validConfigContentMqttWebSocketsIotHubProtocol =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": true,)"
R"("manufacturer": "device_info_manufacturer",)"
R"("model": "device_info_model",)"
R"("iotHubProtocol": "mqtt/ws",)"
@ -156,7 +152,6 @@ static const char* validConfigContentMissingIotHubProtocol =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": true,)"
R"("manufacturer": "device_info_manufacturer",)"
R"("model": "device_info_model",)"
R"("agents": [)"
@ -187,7 +182,6 @@ static const char* invalidConfigContentNoDeviceInfoStr =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": false,)"
R"("agents": [)"
R"({ )"
R"("name": "host-update",)"
@ -216,7 +210,6 @@ static const char* invalidConfigContentNoDevicePropertiesStr =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": true,)"
R"("manufacturer": "device_info_manufacturer",)"
R"("model": "device_info_model",)"
R"("compatPropertyNames": "manufacturer,model",)"
@ -246,7 +239,6 @@ static const char* invalidConfigContentStr =
R"({)"
R"("schemaVersion": "1.1",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": false,)"
R"("agents": [])"
R"(})";
@ -254,7 +246,6 @@ static const char* validConfigContentAdditionalPropertyNames =
R"({)"
R"("schemaVersion": "1.0",)"
R"("aduShellTrustedUsers": ["adu","do"],)"
R"("simulateUnhealthyState": true,)"
R"("manufacturer": "device_info_manufacturer",)"
R"("model": "device_info_model",)"
R"("agents": [)"
@ -323,9 +314,6 @@ TEST_CASE_METHOD(GlobalMockHookTestCaseFixture, "ADUC_ConfigInfo_Init Functional
CHECK(ADUC_ConfigInfo_Init(&config, "/etc/adu/du-config.json"));
CHECK_THAT(json_array_get_string(config.aduShellTrustedUsers, 0), Equals("adu"));
CHECK_THAT(json_array_get_string(config.aduShellTrustedUsers, 1), Equals("do"));
#ifdef ADUC_PLATFORM_SIMULATOR
CHECK(config.simulateUnhealthyState);
#endif
CHECK_THAT(config.schemaVersion, Equals("1.1"));
CHECK_THAT(config.manufacturer, Equals("device_info_manufacturer"));
CHECK_THAT(config.model, Equals("device_info_model"));

Просмотреть файл

@ -16,12 +16,7 @@ find_package (azure_c_shared_utility REQUIRED)
target_link_libraries (${PROJECT_NAME} PUBLIC aziotsharedutil PRIVATE aduc::logging aduc::c_utils aduc::config_utils aduc::string_utils)
if ((NOT
${ADUC_PLATFORM_LAYER}
STREQUAL
"simulator"
)
AND ADUC_BUILD_UNIT_TESTS)
if (ADUC_BUILD_UNIT_TESTS)
add_subdirectory (tests)
add_subdirectory (test_helper)
endif ()

Просмотреть файл

@ -233,20 +233,20 @@ size_t workflow_get_update_files_count(ADUC_WorkflowHandle handle);
*
* @param handle A workflow data object handle.
* @param index An index of the file to get.
* @param entity An output file entity object. Caller must free the object with workflow_free_file_entity().
* @return true If succeeded.
* @param entity An output file entity object. Caller must uninitialize it via ADUC_FileEntity_Uninit when done.
* @return true on success.
*/
bool workflow_get_update_file(ADUC_WorkflowHandle handle, size_t index, ADUC_FileEntity** entity);
bool workflow_get_update_file(ADUC_WorkflowHandle handle, size_t index, ADUC_FileEntity* entity);
/**
* @brief Gets the update file entity by name.
*
* @param handle A workflow data object handle.
* @param fileName File name.
* @param entity An output file entity object. Caller must free the object with workflow_free_file_entity().
* @return true If succeeded.
* @param[in] handle A workflow data object handle.
* @param[in] fileName File name.
* @param[out] entity An output file entity object. Caller must uninitialize it via ADUC_FileEntity_Uninit().
* @return true on success.
*/
bool workflow_get_update_file_by_name(ADUC_WorkflowHandle handle, const char* fileName, ADUC_FileEntity** entity);
bool workflow_get_update_file_by_name(ADUC_WorkflowHandle handle, const char* fileName, ADUC_FileEntity* entity);
/**
* @brief Gets the inode associated with the update file entity at the specified index.
@ -278,19 +278,12 @@ size_t workflow_get_bundle_updates_count(ADUC_WorkflowHandle handle);
/**
* @brief Gets a bundle update file at specified index.
*
* @param handle A workflow data object handle.
* @param index An index of the file to get.
* @param entity An output file entity object. Caller must free the object with workflow_free_file_entity().
* @return true If succeeded.
* @param[in] handle A workflow data object handle.
* @param[in] index An index of the file to get.
* @param[out] entity An output file entity object.
* @return true on success.
*/
bool workflow_get_bundle_updates_file(ADUC_WorkflowHandle handle, size_t index, ADUC_FileEntity** entity);
/**
* @brief Free specified file entity object.
*
* @param entity A pointer to file entity object to be freed.
*/
void workflow_free_file_entity(ADUC_FileEntity* entity);
bool workflow_get_bundle_updates_file(ADUC_WorkflowHandle handle, size_t index, ADUC_FileEntity* entity);
/**
* @brief Get an Update Manifest property (string) without copying the value.
@ -438,7 +431,7 @@ ADUC_WorkflowHandle workflow_get_child(ADUC_WorkflowHandle handle, int index);
* @param index An index indicate the location the @p childHandle will be inserted at.
* To insert at the end of the list, pass '-1'.
* @param childHandle A child workflow object handle.
* @return true If succeeded.
* @return true on success.
*/
bool workflow_insert_child(ADUC_WorkflowHandle handle, int index, ADUC_WorkflowHandle childHandle);
@ -721,13 +714,12 @@ workflow_peek_update_manifest_handler_properties_string(ADUC_WorkflowHandle hand
/**
* @brief Gets a reference step update manifest file at specified index.
*
* @param handle A workflow data object handle.
* @param stepIndex A step index.
* @param entity An output reference step update manifest file entity object.
* Caller must free the object with workflow_free_file_entity().
* @return Returns true if succeeded.
* @param[in] handle A workflow data object handle.
* @param[in] stepIndex A step index.
* @param[out] entity An output reference step update manifest file entity object.
* @return Returns true on success.
*/
bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t stepIndex, ADUC_FileEntity** entity);
bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t stepIndex, ADUC_FileEntity* entity);
/**
* @brief Gets a serialized json string of the specified workflow's Update Manifest.

Просмотреть файл

@ -786,7 +786,8 @@ ADUC_Result _workflow_parse(bool isFile, const char* source, bool validateManife
JSON_Value* updateActionJson = NULL;
char* workFolder = NULL;
STRING_HANDLE detachedUpdateManifestFilePath = NULL;
ADUC_FileEntity* fileEntity = NULL;
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
if (handle == NULL)
{
@ -942,7 +943,7 @@ ADUC_Result _workflow_parse(bool isFile, const char* source, bool validateManife
// Download the detached update manifest file.
result = ExtensionManager_Download(
fileEntity, handle, &Default_ExtensionManager_Download_Options, NULL /* downloadProgressCallback */);
&fileEntity, handle, &Default_ExtensionManager_Download_Options, NULL /* downloadProgressCallback */);
if (IsAducResultCodeFailure(result.ResultCode))
{
workflow_set_result_details(
@ -953,7 +954,7 @@ ADUC_Result _workflow_parse(bool isFile, const char* source, bool validateManife
{
// Replace existing updateManifest with the one from detached update manifest file.
detachedUpdateManifestFilePath =
STRING_construct_sprintf("%s/%s", workFolder, fileEntity->TargetFilename);
STRING_construct_sprintf("%s/%s", workFolder, fileEntity.TargetFilename);
JSON_Object* rootObj =
json_value_get_object(json_parse_file(STRING_c_str(detachedUpdateManifestFilePath)));
const char* updateManifestString = json_object_get_string(rootObj, ADUCITF_FIELDNAME_UPDATEMANIFEST);
@ -993,8 +994,7 @@ ADUC_Result _workflow_parse(bool isFile, const char* source, bool validateManife
done:
workflow_free_file_entity(fileEntity);
fileEntity = NULL;
ADUC_FileEntity_Uninit(&fileEntity);
STRING_delete(detachedUpdateManifestFilePath);
@ -1733,7 +1733,7 @@ size_t workflow_get_update_files_count(ADUC_WorkflowHandle handle)
return files == NULL ? 0 : json_object_get_count(files);
}
bool workflow_get_update_file(ADUC_WorkflowHandle handle, size_t index, ADUC_FileEntity** entity)
bool workflow_get_update_file(ADUC_WorkflowHandle handle, size_t index, ADUC_FileEntity* entity)
{
if (entity == NULL)
{
@ -1750,8 +1750,6 @@ bool workflow_get_update_file(ADUC_WorkflowHandle handle, size_t index, ADUC_Fil
const JSON_Object* files = NULL;
const JSON_Object* file = NULL;
const JSON_Object* fileUrls = NULL;
ADUC_FileEntity* newEntity = NULL;
*entity = NULL;
const char* uri = NULL;
const char* fileId = NULL;
const char* name = NULL;
@ -1807,13 +1805,7 @@ bool workflow_get_update_file(ADUC_WorkflowHandle handle, size_t index, ADUC_Fil
sizeInBytes = json_object_get_number(file, ADUCITF_FIELDNAME_SIZEINBYTES);
}
newEntity = calloc(1, sizeof(*newEntity));
if (newEntity == NULL)
{
goto done;
}
if (!ADUC_FileEntity_Init(newEntity, fileId, name, uri, arguments, tempHash, tempHashCount, sizeInBytes))
if (!ADUC_FileEntity_Init(entity, fileId, name, uri, arguments, tempHash, tempHashCount, sizeInBytes))
{
Log_Error("Invalid file entity arguments");
goto done;
@ -1823,22 +1815,18 @@ bool workflow_get_update_file(ADUC_WorkflowHandle handle, size_t index, ADUC_Fil
ADUC_Hash_FreeArray(tempHashCount, tempHash);
tempHash = NULL;
if (!ParseFileEntityDownloadHandler(handle, file, newEntity))
if (!ParseFileEntityDownloadHandler(handle, file, entity))
{
goto done;
}
succeeded = true;
*entity = newEntity;
newEntity = NULL;
done:
if (newEntity != NULL)
if (!succeeded)
{
newEntity->Hash = NULL; // Manually free hash array below...
ADUC_FileEntity_Uninit(newEntity);
free(newEntity);
entity->Hash = NULL; // Manually free hash array below that is pointed to by tempHash...
ADUC_FileEntity_Uninit(entity);
}
if (tempHash != NULL)
@ -1849,7 +1837,7 @@ done:
return succeeded;
}
bool workflow_get_update_file_by_name(ADUC_WorkflowHandle handle, const char* fileName, ADUC_FileEntity** entity)
bool workflow_get_update_file_by_name(ADUC_WorkflowHandle handle, const char* fileName, ADUC_FileEntity* entity)
{
if (entity == NULL)
{
@ -1866,8 +1854,6 @@ bool workflow_get_update_file_by_name(ADUC_WorkflowHandle handle, const char* fi
const JSON_Object* files = NULL;
const JSON_Object* file = NULL;
const JSON_Object* fileUrls = NULL;
ADUC_FileEntity* newEntity = NULL;
*entity = NULL;
const char* uri = NULL;
const char* fileId = NULL;
const char* name = NULL;
@ -1931,21 +1917,13 @@ bool workflow_get_update_file_by_name(ADUC_WorkflowHandle handle, const char* fi
sizeInBytes = json_object_get_number(file, ADUCITF_FIELDNAME_SIZEINBYTES);
}
newEntity = calloc(1, sizeof(*newEntity));
if (newEntity == NULL)
{
goto done;
}
if (!ADUC_FileEntity_Init(newEntity, fileId, name, uri, arguments, tempHash, tempHashCount, sizeInBytes))
if (!ADUC_FileEntity_Init(entity, fileId, name, uri, arguments, tempHash, tempHashCount, sizeInBytes))
{
Log_Error("Invalid file entity arguments");
goto done;
}
*entity = newEntity;
if (!ParseFileEntityDownloadHandler(handle, file, *entity))
if (!ParseFileEntityDownloadHandler(handle, file, entity))
{
goto done;
}
@ -1955,12 +1933,8 @@ bool workflow_get_update_file_by_name(ADUC_WorkflowHandle handle, const char* fi
done:
if (!succeeded)
{
if (newEntity != NULL)
{
newEntity->Hash = NULL; // Manually free hash array below...
ADUC_FileEntity_Uninit(newEntity);
free(newEntity);
}
entity->Hash = NULL; // will be freed with tempHash below
ADUC_FileEntity_Uninit(entity);
if (tempHash != NULL)
{
@ -2032,17 +2006,6 @@ bool workflow_set_update_file_inode(ADUC_WorkflowHandle handle, size_t index, in
return true;
}
/**
* @brief Uninitialize and free specified file entity object.
*
* @param entity A file entity object.
*/
void workflow_free_file_entity(ADUC_FileEntity* entity)
{
ADUC_FileEntity_Uninit(entity);
free(entity);
}
/**
* @brief Get an Update Manifest property (string) without copying the value.
* Caller must not free the pointer.
@ -3501,19 +3464,13 @@ const char* workflow_peek_update_manifest_step_handler(ADUC_WorkflowHandle handl
/**
* @brief Gets a reference step update manifest file at specified index.
*
* @param handle A workflow data object handle.
* @param stepIndex A step index.
* @param entity An output reference step update manifest file entity object.
* Caller must free the object with workflow_free_file_entity().
* @return true If succeeded.
* @param handle[in] A workflow data object handle.
* @param stepIndex[in] A step index.
* @param entity[out] An output reference step update manifest file entity object.
* @return true on success.
*/
bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t stepIndex, ADUC_FileEntity** entity)
bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t stepIndex, ADUC_FileEntity* entity)
{
if (entity == NULL)
{
return false;
}
size_t count = workflow_get_instructions_steps_count(handle);
if (stepIndex >= count)
{
@ -3521,6 +3478,7 @@ bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t
}
bool succeeded = false;
bool fileEntityInited = false;
JSON_Object* step = json_array_get_object(workflow_get_instructions_steps_array(handle), stepIndex);
const char* fileId = json_object_get_string(step, STEP_PROPERTY_FIELD_DETACHED_MANIFEST_FILE_ID);
const JSON_Object* files = _workflow_get_update_manifest_files_map(handle);
@ -3531,8 +3489,6 @@ bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t
size_t tempHashCount = 0;
ADUC_Hash* tempHash = NULL;
*entity = NULL;
// Find fileurls map in this workflow, and its enclosing workflow(s).
ADUC_WorkflowHandle h = handle;
@ -3570,19 +3526,15 @@ bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t
sizeInBytes = json_object_get_number(file, ADUCITF_FIELDNAME_SIZEINBYTES);
}
*entity = calloc(1, sizeof(**entity));
if (*entity == NULL)
{
goto done;
}
if (!ADUC_FileEntity_Init(*entity, fileId, name, uri, NULL /*arguments*/, tempHash, tempHashCount, sizeInBytes))
if (!ADUC_FileEntity_Init(entity, fileId, name, uri, NULL /*arguments*/, tempHash, tempHashCount, sizeInBytes))
{
Log_Error("Invalid file entity arguments");
goto done;
}
if (!ParseFileEntityDownloadHandler(handle, file, *entity))
fileEntityInited = true;
if (!ParseFileEntityDownloadHandler(handle, file, entity))
{
goto done;
}
@ -3591,14 +3543,9 @@ bool workflow_get_step_detached_manifest_file(ADUC_WorkflowHandle handle, size_t
done:
if (!succeeded)
if (!succeeded && fileEntityInited)
{
if (*entity != NULL)
{
ADUC_FileEntity_Uninit(*entity);
free(*entity);
*entity = NULL;
}
ADUC_FileEntity_Uninit(entity);
}
return succeeded;

Просмотреть файл

@ -11,6 +11,7 @@
#include <catch2/catch.hpp>
using Catch::Matchers::Equals;
#include <aduc/parser_utils.h> // ADUC_FileEntity_Uninit
#include <aduc/workflow_utils.h>
#include <fstream>
#include <parson.h>
@ -78,15 +79,16 @@ TEST_CASE("workflow_get_update_file with download handler")
size_t filecount = workflow_get_update_files_count(handle);
REQUIRE(filecount == 1);
ADUC_FileEntity* file = nullptr;
REQUIRE(workflow_get_update_file(handle, 0, &file));
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
REQUIRE(workflow_get_update_file(handle, 0, &fileEntity));
CHECK_THAT(file->DownloadHandlerId, Equals("microsoft/delta:1"));
CHECK_THAT(fileEntity.DownloadHandlerId, Equals("microsoft/delta:1"));
CHECK(file->RelatedFileCount == 1);
CHECK(file->RelatedFiles != nullptr);
CHECK(fileEntity.RelatedFileCount == 1);
CHECK(fileEntity.RelatedFiles != nullptr);
const auto& relatedFile = file->RelatedFiles[0];
const auto& relatedFile = fileEntity.RelatedFiles[0];
CHECK_THAT(relatedFile.FileId, Equals(deltaUpdateFileId));
CHECK_THAT(relatedFile.DownloadUri, Equals(deltaUpdateFileUrl));
@ -103,6 +105,8 @@ TEST_CASE("workflow_get_update_file with download handler")
CHECK_THAT(relatedFile.Properties[0].Value, Equals("SOURCE_UPDATE_HASH"));
CHECK_THAT(relatedFile.Properties[1].Name, Equals("microsoft.sourceFileHashAlgorithm"));
CHECK_THAT(relatedFile.Properties[1].Value, Equals("sha256"));
ADUC_FileEntity_Uninit(&fileEntity);
}
// clang-format off
@ -126,10 +130,13 @@ TEST_CASE("workflow_get_update_file - upd metadata missing relatedFile URL")
{
ADUC_WorkflowHandle handle = nullptr;
ADUC_Result result = workflow_init(manifest_missing_related_file_file_url, true /* validateManifest */, &handle);
ADUC_Result result =
workflow_init(manifest_missing_related_file_file_url, true /* validateManifest */, &handle);
REQUIRE(IsAducResultCodeSuccess(result.ResultCode));
ADUC_FileEntity* file = nullptr;
CHECK_FALSE(workflow_get_update_file(handle, 0, &file));
ADUC_FileEntity fileEntity;
memset(&fileEntity, 0, sizeof(fileEntity));
CHECK_FALSE(workflow_get_update_file(handle, 0, &fileEntity));
ADUC_FileEntity_Uninit(&fileEntity);
}
}

Просмотреть файл

@ -82,20 +82,18 @@ TEST_CASE("Initialization test")
auto filecount = workflow_get_update_files_count(handle);
REQUIRE(filecount == 2);
ADUC_FileEntity* file0 = nullptr;
ADUC_FileEntity file0;
memset(&file0, 0, sizeof(file0));
bool success = workflow_get_update_file(handle, 0, &file0);
REQUIRE(success);
REQUIRE(file0 != nullptr);
CHECK_THAT(file0->FileId, Equals("f483750ebb885d32c"));
CHECK(file0->HashCount == 1);
CHECK_THAT(file0.FileId, Equals("f483750ebb885d32c"));
CHECK(file0.HashCount == 1);
CHECK_THAT(
file0->DownloadUri,
file0.DownloadUri,
Equals(
"http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/e5cc19d5e9174c93ada35cc315f1fb1d/apt-manifest-tree-1.0.json"));
ADUC_FileEntity_Uninit(file0);
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory, cppcoreguidelines-no-malloc, hicpp-no-malloc)
free(file0);
ADUC_FileEntity_Uninit(&file0);
char* updateId = workflow_get_expected_update_id_string(handle);
CHECK_THAT(updateId, Equals("{\"provider\":\"Contoso\",\"name\":\"Virtual-Vacuum\",\"version\":\"20.0\"}"));
@ -132,8 +130,7 @@ TEST_CASE("Get Compatibility")
CHECK(result.ResultCode != 0);
CHECK(result.ExtendedResultCode == 0);
const char* expectedValue =
R"([{"deviceManufacturer":"contoso","deviceModel":"virtual-vacuum-v1"}])";
const char* expectedValue = R"([{"deviceManufacturer":"contoso","deviceModel":"virtual-vacuum-v1"}])";
char* compats = workflow_get_compatibility(handle);
CHECK_THAT(compats, Equals(expectedValue));
@ -183,20 +180,18 @@ TEST_CASE("Child workflow uses fileUrls from parent")
workflow_insert_child(bundle, 0, leaf0);
// Check that leaf 0 file has the right download uri.
ADUC_FileEntity* file0 = nullptr;
ADUC_FileEntity file0;
memset(&file0, 0, sizeof(file0));
bool success = workflow_get_update_file(leaf0, 0, &file0);
REQUIRE(success);
REQUIRE(file0 != nullptr);
CHECK_THAT(file0->FileId, Equals("f13b5435aab7c18da"));
CHECK(file0->HashCount == 1);
CHECK_THAT(file0.FileId, Equals("f13b5435aab7c18da"));
CHECK(file0.HashCount == 1);
CHECK_THAT(
file0->DownloadUri,
file0.DownloadUri,
Equals(
"http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/c02058a476a242d7bc0e3c576c180051/contoso-motor-installscript.sh"));
ADUC_FileEntity_Uninit(file0);
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory, cppcoreguidelines-no-malloc, hicpp-no-malloc)
free(file0);
ADUC_FileEntity_Uninit(&file0);
workflow_free(bundle);
}
@ -213,22 +208,19 @@ TEST_CASE("Get update file by name")
REQUIRE(filecount == 2);
// Check that leaf 0 file has the right download uri.
ADUC_FileEntity* file0 = nullptr;
ADUC_FileEntity file0;
memset(&file0, 0, sizeof(file0));
bool success =
workflow_get_update_file_by_name(bundle, "contoso.contoso-virtual-motors.1.1.updatemanifest.json", &file0);
CHECK(success);
CHECK(file0 != nullptr);
CHECK_THAT(file0->FileId, Equals("f222b9ffefaaac577"));
CHECK(file0->HashCount == 1);
CHECK_THAT(file0.FileId, Equals("f222b9ffefaaac577"));
CHECK(file0.HashCount == 1);
CHECK_THAT(
file0->DownloadUri,
file0.DownloadUri,
Equals(
"http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/31c38c3340a84e38ae8d30ce340f4a49/contoso.contoso-virtual-motors.1.1.updatemanifest.json"));
ADUC_FileEntity_Uninit(file0);
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory, cppcoreguidelines-no-malloc, hicpp-no-malloc)
free(file0);
ADUC_FileEntity_Uninit(&file0);
workflow_free(bundle);
}
@ -244,22 +236,19 @@ TEST_CASE("Get update file by name - mixed case")
REQUIRE(filecount == 2);
// Check that leaf 0 file has the right download uri.
ADUC_FileEntity* file0 = nullptr;
ADUC_FileEntity file0;
memset(&file0, 0, sizeof(file0));
bool success =
workflow_get_update_file_by_name(bundle, "contoso.Contoso-virtual-motors.1.1.updatemanifest.json", &file0);
CHECK(success);
CHECK(file0 != nullptr);
CHECK_THAT(file0->FileId, Equals("f222b9ffefaaac577"));
CHECK(file0->HashCount == 1);
CHECK_THAT(file0.FileId, Equals("f222b9ffefaaac577"));
CHECK(file0.HashCount == 1);
CHECK_THAT(
file0->DownloadUri,
file0.DownloadUri,
Equals(
"http://duinstance2.b.nlu.dl.adu.microsoft.com/westus2/duinstance2/31c38c3340a84e38ae8d30ce340f4a49/contoso.contoso-virtual-motors.1.1.updatemanifest.json"));
ADUC_FileEntity_Uninit(file0);
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory, cppcoreguidelines-no-malloc, hicpp-no-malloc)
free(file0);
ADUC_FileEntity_Uninit(&file0);
workflow_free(bundle);
}