I'm trying to make an update using Azure Device Update on ubuntu 22.04. When my update is of type apt (microsoft/apt:1) it works fine.
But when I try to run a script (microsoft/script:1) i'm getting error from ADU: 810549253 (0x30500005).
ADUC_ERC_SCRIPT_HANDLER_MISSING_SCRIPTFILENAME_PROPERTY MAKE_ADUC_EXTENDEDRESULTCODE_FOR_COMPONENT_ADUC_CONTENT_HANDLER_SCRIPT(5)
List of errors: result.h
Here the script that I want to run:
script_test.sh:
#!/bin/bash
# Create a directory
mkdir -p /home/azureuser/this_was_create_by_adu
# Create a text file with specified content inside the directory
echo "this file was generated by adu" > /home/azureuser/this_was_create_by_adu/generated_file.txt
# Confirmation message
echo "Directory and file have been created successfully."
The import manifest:
script_test.importmanifest.json:
{
"updateId": {
"name": "script",
"provider": "me",
"version": "7.0.0"
},
"compatibility": [
{
"manufacturer": "hp",
"model": "elite"
}
],
"createdDateTime": "2024-10-23T09:33:11Z",
"files": [
{
"filename": "script_test.sh",
"hashes": {
"sha256": "lHKs3UsbWJAE3Svz3KwPCWibEofSPisKfB2rsbyIM4E="
},
"sizeInBytes": 328
}
],
"instructions": {
"steps": [
{
"files": [
"script_test.sh"
],
"handler": "microsoft/script:1",
"handlerProperties": {
"installedCriteria": "1.0",
},
"type": "inline"
}
]
},
"manifestVersion": "5.0"
}
The log error:
2024-11-05T15:39:52.8793Z 5742[7981] [I] Try to load a handler for current update manifest version 5 (handler: 'microsoft/update-manifest:5') [GetUpdateManifestHandler:114] 2024-11-05T15:39:52.8793Z 5742[7981] [I] Loading handler for 'microsoft/update-manifest:5'. [LoadUpdateContentHandlerExtension:208] 2024-11-05T15:39:52.8794Z 5742[7981] [I] Loading extension 'microsoft/update-manifest:5'. Reg file : /var/lib/adu/extensions/update_content_handlers/microsoft_update-manifest_5/content_handler.json [LoadExtensionLibrary:85] 2024-11-05T15:39:52.8794Z 5742[7981] [D] Determining contract version for 'microsoft/update-manifest:5'. [LoadUpdateContentHandlerExtension:303] 2024-11-05T15:39:52.8794Z 5742[7981] [D] Got 1.0 contract version for 'microsoft/update-manifest:5' handler [LoadUpdateContentHandlerExtension:331] 2024-11-05T15:39:52.8794Z 5742[7981] [D] Caching new handler for 'microsoft/update-manifest:5'. [LoadUpdateContentHandlerExtension:340] 2024-11-05T15:39:52.8797Z 5742[7981] [I] Action 'Download' complete. Result: 0 (failed), 810549253 (0x30500005) [ADUC_Workflow_WorkCompletionCallback:890] 2024-11-05T15:39:52.8797Z 5742[7981] [I] WorkCompletionCallback: Download failed. Going to state Failed [ADUC_Workflow_WorkCompletionCallback:1016] 2024-11-05T15:39:52.8797Z 5742[7981] [I] Setting UpdateState to Failed [ADUC_Workflow_SetUpdateStateHelper:1088]
2024-11-05T15:39:52.8797Z 5742[7981] [D] [ADUC_D2C_Message_SendAsync:526] ==== MULTI-LINE LOG BEGIN ==== Queueing message (t:0, c:0x64006e50, m:{"deviceUpdate":{"__t":"c","agent":{"lastInstallResult":{"stepResults":{"step_0":{"resultCode":0,"extendedResultCodes":"00000000","resultDetails":null}},"resultCode":0,"extendedResultCodes":"30500005,A0000FFF","resultDetails":""},"state":255,"workflow":{"action":3,"id":"aebe0066-67ba-4d78-a247-2656d91dd7c8"}}}})2024-11-05T15:39:52.8797Z 5742[7981] [D] [ADUC_D2C_Message_SendAsync:526] ==== MULTI-LINE LOG END ====
2024-11-05T15:39:52.8815Z 5742[7981] [I] Workflow is Complete. [ADUC_Workflow_AutoTransitionWorkflow:758] 2024-11-05T15:39:53.2803Z 5742[5742] [D] context:0xb6b015a0 [DefaultIoTHubSendReportedStateCompletedCallback:205] 2024-11-05T15:39:53.2803Z 5742[5742] [D] D2C message processed successfully (t:0, r:0, content:0xb8465da0 ) [DefaultIoTHubSendReportedStateCompletedCallback:233] 2024-11-05T15:39:53.2803Z 5742[5742] [D] Send message completed (status:3) [OnUpdateResultD2CMessageCompleted:64] 2024-11-05T15:39:53.2804Z 5742[5742] [D] context:0xb6b01640 [DefaultIoTHubSendReportedStateCompletedCallback:205] 2024-11-05T15:39:53.2804Z 5742[5742] [D] D2C message processed successfully (t:1, r:0, content:0xb843b8c0 ) [DefaultIoTHubSendReportedStateCompletedCallback:233] 2024-11-05T15:39:53.2804Z 5742[5742] [D] Send message completed (status:3) [OnUpdateResultD2CMessageCompleted:64] 2024-11-05T15:39:53.2804Z 5742[5742] [D] Sending D2C message (t:0, retries:0). [ProcessMessage:390]
2024-11-05T15:39:53.2804Z 5742[5742] [D] [ADUC_D2C_Default_Message_Transport_Function:580] ==== MULTI-LINE LOG BEGIN ==== Sending D2C message: {"deviceUpdate":{"__t":"c","agent":{"lastInstallResult":{"stepResults":{"step_0":{"resultCode":0,"extendedResultCodes":"00000000","resultDetails":null}},"resultCode":0,"extendedResultCodes":"30500005,A0000FFF","resultDetails":""},"state":255,"workflow":{"action":3,"id":"aebe0066-67ba-4d78-a247-2656d91dd7c8"}}}}2024-11-05T15:39:53.2804Z 5742[5742] [D] [ADUC_D2C_Default_Message_Transport_Function:580] ==== MULTI-LINE LOG END ====
After restarting the Virtual Machine that I was using for testing, I encountered a different error:
"The install script doesn't create a result file '/var/lib/adu/downloads/aebe0066-67ba-4d78-a247-2656d91dd7c8/action_download_aduc_result.json'."
According to the responses on the issue I opened on GitHub, I noticed that I wasn't writing the result to the result file, which is mandatory
https://github.com/Azure/iot-hub-device-update/issues/667.
Following the documentation and the example script I rewrote the script and the import manifest and it worked properly:
script_test.importmanifest.json:
{
"compatibility": [
{
"manufacturer": "hp",
"model": "elite"
}
],
"createdDateTime": "2024-11-15T14:30:05Z",
"files": [
{
"filename": "script_test.sh",
"hashes": {
"sha256": "WRgOrX+fgPECHrmEX1i6XmnghiYwe+4PGPv0Tjm2vpQ="
},
"sizeInBytes": 5902
}
],
"instructions": {
"steps": [
{
"files": [
"script_test.sh"
],
"handler": "microsoft/script:1",
"handlerProperties": {
"arguments": "",
"scriptFileName": "script_test.sh",
"installedCriteria": "1.0"
},
"type": "inline"
}
]
},
"manifestVersion": "5.0",
"updateId": {
"name": "scriptupdate",
"provider": "me",
"version": "51.0.0"
}
}
script_test.sh
#!/bin/bash
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# Ensure that getopt starts from first option if ". <script.sh>" was used.
OPTIND=1
# Ensure we don't end the user's terminal session if invoked from source (".").
if [[ $0 != "${BASH_SOURCE[0]}" ]]; then
ret='return'
else
ret='exit'
fi
# Output formatting.
# Log level: 0=debug, 1=info, 2=warning, 3=error, 4=none
log_level=1
warn() { echo -e "\033[1;33mWarning:\033[0m $*" >&2; }
error() { echo -e "\033[1;31mError:\033[0m $*" >&2; }
header() { echo -e "\e[4m\e[1m\e[1;32m$*\e[0m"; }
bullet() { echo -e "\e[1;34m*\e[0m $*"; }
# Log debug prefix - blue
log_debug_pref="\033[1;30m[D]\033[0m"
# Log info prefix - blue
log_info_pref="\033[1;34m[I]\033[0m"
# Log warning prefix - yellow
log_warn_pref="\033[1;33m[W]\033[0m"
# Log error prefix - red
log_error_pref="\033[1;31m[E]\033[0m"
#
# Install poicy
#
#install_error_policy="abort"
#install_reboot_policy="none"
# component_props will contain a map of property.
declare -A component_props
#
# Files and Folders information
#
workfolder=
output_file=
log_file=
result_file=
#
# Device Update specific arguments
#
do_install_action=
#
# Remaining aguments and parameters
#
PARAMS=
#
# Output, Logs, and Result helper functions.
#
_timestamp=
update_timestamp() {
# See https://man7.org/linux/man-pages/man1/date.1.html
_timestamp="$(date +'%Y/%m/%d:%H%M%S')"
}
log_debug() {
if [ $log_level -gt 0 ]; then
return
fi
log "$log_debug_pref" "$@"
}
log_info() {
if [ $log_level -gt 1 ]; then
return
fi
log "$log_info_pref" "$@"
}
log_warn() {
if [ $log_level -gt 2 ]; then
return
fi
log "$log_warn_pref" "$@"
}
log_error() {
if [ $log_level -gt 3 ]; then
return
fi
log "$log_error_pref" "$@"
}
log() {
update_timestamp
if [ -z "$log_file" ]; then
echo -e "[$_timestamp]" "$@" >&1
else
echo "[$_timestamp]" "$@" >> "$log_file"
fi
}
output() {
update_timestamp
if [ -z "$output_file" ]; then
echo "[$_timestamp]" "$@" >&1
else
echo "[$_timestamp]" "$@" >> "$output_file"
fi
}
#
# Write result json string to result file.
#
result() {
# NOTE: don't insert timestamp in result file.
if [ -z "$result_file" ]; then
echo "$@" >&1
else
echo "$@" > "$result_file"
fi
}
log "Log begin:"
output "Output begin:"
#
# Parsing arguments
#
while [[ $1 != "" ]]; do
case $1 in
#
# Component-related arguments.
#
# Following arguments and parameters will be populated by the Script Step Handler.
#
#
# Device Update specific arguments.
#
--action-install)
shift
log_info "Will runscript as 'installer' script."
do_install_action=yes
;;
#
# Update artifacts
#
--work-folder)
shift
if [[ -z $1 || $1 == -* ]]; then
error "--work-folder parameter is mandatory."
$ret 1
fi
workfolder="$1"
echo "Workfolder: $workfolder"
shift
;;
#
# Output-related arguments.
#
# --out-file <file_path>, --result-file <file_path>, --log-file <file_path>
#
--output-file)
shift
if [[ -z $1 || $1 == -* ]]; then
error "--out-file parameter is mandatory."
$ret 1
fi
output_file="$1"
#
#Create output file path.
#
# Delete existing log.
rm -f -r "$output_file"
# Create dir(s) recursively (include filename, well remove it in the following line...).
mkdir -p "$output_file"
shift
;;
--result-file)
shift
if [[ -z $1 || $1 == -* ]]; then
error "--result-file parameter is mandatory."
$ret 1
fi
result_file="$1"
#
#Create result file path.
#
# Delete existing log.
rm -f -r "$result_file"
# Create dir(s) recursively (include filename, well remove it in the following line...).
touch "$result_file"
shift
;;
--log-file)
shift
if [[ -z $1 || $1 == -* ]]; then
error "--log-file parameter is mandatory."
$ret 1
fi
log_file="$1"
shift
;;
--log-level)
shift
if [[ -z $1 || $1 == -* ]]; then
error "--log-level parameter is mandatory."
$ret 1
fi
log_level=$1
shift
;;
-h | --help)
print_help
$ret 0
;;
*) # preserve positional arguments
PARAMS="$PARAMS $1"
shift
;;
esac
done
#
# Main
#
resultCode=0
extendedResultCode=1
resultDetails=""
# Update apt-get
sudo apt-get update
# Install cowsay
sudo apt-get install cowsay
# Create a directory
mkdir -p /home/azureuser/this_was_create_by_adu
# Create a text file with specified content inside the directory
echo "this file was generated by adu on $(TZ='UTC-1' date '+%Y-%m-%d %H:%M:%S %Z')" > /home/azureuser/this_was_create_by_adu/generated_file.txt
# Confirmation message
if [ -d "/home/azureuser/this_was_create_by_adu" ] && [ -f "/home/azureuser/this_was_create_by_adu/generated_file.txt" ]; then
log_info "Both directory and file exist."
resultCode=600
extendedResultCode=0
resultDetails="folder and file created"
ret_val=0
else
log_info "Either the directory or file does not exist."
resultDetails="Folder and/or file have been not created"
exit 1
fi
# Prepare ADUC_Result json.
aduc_result_json="{\"resultCode\":$resultCode, \"extendedResultCode\":$extendedResultCode,\"resultDetails\":\"$resultDetails\"}"
# Show output.
output "Result:" "$aduc_result_json"
# Write ADUC_Result to result file.
result "$aduc_result_json"
exit 0