Skip to content

Files

Latest commit

5bccad2 · Dec 9, 2021

History

History
722 lines (614 loc) · 29.6 KB

ota-cli-workflow.md

File metadata and controls

722 lines (614 loc) · 29.6 KB

Creating an OTA update with the AWS CLI

When you use the AWS CLI to create an OTA update, you:

  1. Digitally sign your firmware image.

  2. Create a stream of your digitally signed firmware image.

  3. Start an OTA update job.

Digitally signing your firmware update

When you use the AWS CLI to perform OTA updates, you can use Code Signing for AWS IoT, or you can sign your firmware update yourself. For a list of the cryptographic signing and hashing algorithms supported by Code Signing for AWS IoT, see SigningConfigurationOverrides. If you want to use a cryptographic algorithm that is not supported by Code Signing for AWS IoT, you must sign your firmware binary before you upload it to Amazon S3.

Signing your firmware image with Code Signing for AWS IoT

To sign your firmware image using Code Signing for AWS IoT, you can use one of the AWS SDKs or command line tools. For more information about Code Signing for AWS IoT, see Code Signing for AWS IoT.

After you install and configure the code-signing tools, copy your unsigned firmware image to your Amazon S3 bucket and start a code-signing job with the following AWS CLI commands. The put-signing-profile command creates a reusable code-signing profile. The start-signing-job command starts the signing job.

aws signer put-signing-profile \
    --profile-name your_profile_name \
    --signing-material certificateArn=arn:aws:acm::your-region:your-aws-account-id:certificate/your-certificate-id \
    --platform your-hardware-platform \
    --signing-parameters certname=your_certificate_path_on_device
aws signer start-signing-job \
    --source 's3={bucketName=your_s3_bucket,key=your_s3_object_key,version=your_s3_object_version_id}' \
    --destination 's3={bucketName=your_destination_bucket}' \
    --profile-name your_profile_name

Note
your-source-bucket-name and your-destination-bucket-name can be the same Amazon S3 bucket.

These are the parameters for the put-signing-profile and start-signing-job commands:

source
Specifies the location of the unsigned firmware in an S3 bucket.

  • bucketName: The name of your S3 bucket.
  • key: The key (file name) of your firmware in your S3 bucket.
  • version: The S3 version of your firmware in your S3 bucket. This is different from your firmware version. You can find it by browsing to the Amazon S3 console, choosing your bucket, and at the top of the page, next to Versions, choosing Show.

destination
The destination on the device to which the signed firmware in the S3 bucket will be copied. The format of this parameter is the same as the source parameter.

signing-material
The ARN of your code-signing certificate. This ARN is generated when you import your certificate into ACM.

signing-parameters
A map of key-value pairs for signing. These can include any information that you want to use during signing.
This parameter is required when you are creating a code-signing profile for signing OTA updates with Code Signing for AWS IoT.

platform
The platformId of the hardware platform to which you are distributing the OTA update.
To return a list of the available platforms and their platformId values, use the aws signer list-signing-platforms command.

The signing job starts and writes the signed firmware image into the destination Amazon S3 bucket. The file name for the signed firmware image is a GUID. You need this file name when you create a stream. You can find the file name by browsing to the Amazon S3 console and choosing your bucket. If you don't see a file with a GUID file name, refresh your browser.

The command displays a job ARN and job ID. You need these values later on. For more information about Code Signing for AWS IoT, see Code Signing for AWS IoT.

Signing your firmware image manually

Digitally sign your firmware image and upload your signed firmware image into your Amazon S3 bucket.

Creating a stream of your firmware update

A stream is an abstract interface to data that can be consumed by a device. A stream can hide the complexity of accessing data stored in different locations or different cloud-based services. The OTA Update Manager service enables you to use multiple pieces of data, stored in various locations in Amazon S3, to perform an OTA Update.

When you create an AWS IoT OTA Update, you can also create a stream that contains your signed firmware update. Make a JSON file (stream.json) that identifies your signed firmware image. The JSON file should contain the following.

[
  {
    "fileId":"your_file_id",
    "s3Location":{
      "bucket":"your_bucket_name",
      "key":"your_s3_object_key"
    }
  }   
]

These are the attributes in the JSON file:

fileId
An arbitrary integer between 0–255 that identifies your firmware image.

s3Location
The bucket and key for the firmware to stream.
bucket
The Amazon S3 bucket where your unsigned firmware image is stored.
key
The file name of your signed firmware image in the Amazon S3 bucket. You can find this value in the Amazon S3 console by looking at the contents of your bucket.
If you are using Code Signing for AWS IoT, the file name is a GUID generated by Code Signing for AWS IoT.

Use the create-stream AWS CLI command to create a stream.

aws iot create-stream \
    --stream-id your_stream_id \
    --description your_description \
    --files file://stream.json \
    --role-arn your_role_arn

These are the arguments for the create-stream AWS CLI command:

stream-id
An arbitrary string to identify the stream.

description
An optional description of the stream.

files
One or more references to JSON files that contain data about firmware images to stream. The JSON file must contain the following attributes:
fileId
An arbitrary file ID.
s3Location
The bucket name where the signed firmware image is stored and the key (file name) of the signed firmware image.
bucket
The Amazon S3 bucket where the signed firmware image is stored.
key
The key (file name) of the signed firmware image.
When you use Code Signing for AWS IoT, this key is a GUID. The following is an example stream.json file.

[
    {
        "fileId":123,
        "s3Location": {
            "bucket":"codesign-ota-bucket",
            "key":"48c67f3c-63bb-4f92-a98a-4ee0fbc2bef6"
        }
    }
]

role-arn
The OTA service role that also grants access to the Amazon S3 bucket where the firmware image is stored.

To find the Amazon S3 object key of your signed firmware image, use the aws signer describe-signing-job --job-id my-job-id command where my-job-id is the job ID displayed by the create-signing-job AWS CLI command. The output of the describe-signing-job command contains the key of the signed firmware image.

... text deleted for brevity ...
  "signedObject": {
    "s3": {
      "bucketName": "ota-bucket",
      "key": "7309da2c-9111-48ac-8ee4-5a4262af4429"
    }
  }
... text deleted for brevity ...

Creating an OTA update

Use the create-ota-update AWS CLI command to create an OTA update job.

Note
Do not use any personally identifiable information (PII) in your OTA update job ID. Examples of personally identifiable information include:
Names. IP addresses. Email addresses. Locations. Bank details. Medical information.

aws iot  create-ota-update \
    --ota-update-id value \
    [--description value] \
    --targets value \
    [--protocols value] \
    [--target-selection value] \
    [--aws-job-executions-rollout-config value] \
    [--aws-job-presigned-url-config value] \
    [--aws-job-abort-config value] \
    [--aws-job-timeout-config value] \
    --files value \
    --role-arn value \
    [--additional-parameters value] \
    [--tags value]  \
    [--cli-input-json value] \
    [--generate-cli-skeleton]

cli-input-json format

{
  "otaUpdateId": "string",
  "description": "string",
  "targets": [
    "string"
  ],
  "protocols": [
    "string"
  ],
  "targetSelection": "string",
  "awsJobExecutionsRolloutConfig": {
    "maximumPerMinute": "integer",
    "exponentialRate": {
      "baseRatePerMinute": "integer",
      "incrementFactor": "double",
      "rateIncreaseCriteria": {
        "numberOfNotifiedThings": "integer",
        "numberOfSucceededThings": "integer"
      }
    }
  },
  "awsJobPresignedUrlConfig": {
    "expiresInSec": "long"
  },
  "awsJobAbortConfig": {
    "abortCriteriaList": [
      {
        "failureType": "string",
        "action": "string",
        "thresholdPercentage": "double",
        "minNumberOfExecutedThings": "integer"
      }
    ]
  },
  "awsJobTimeoutConfig": {
    "inProgressTimeoutInMinutes": "long"
  },
  "files": [
    {
      "fileName": "string",
      "fileType": "integer",
      "fileVersion": "string",
      "fileLocation": {
        "stream": {
          "streamId": "string",
          "fileId": "integer"
        },
        "s3Location": {
          "bucket": "string",
          "key": "string",
          "version": "string"
        }
      },
      "codeSigning": {
        "awsSignerJobId": "string",
        "startSigningJobParameter": {
          "signingProfileParameter": {
            "certificateArn": "string",
            "platform": "string",
            "certificatePathOnDevice": "string"
          },
          "signingProfileName": "string",
          "destination": {
            "s3Destination": {
              "bucket": "string",
              "prefix": "string"
            }
          }
        },
        "customCodeSigning": {
          "signature": {
            "inlineDocument": "blob"
          },
          "certificateChain": {
            "certificateName": "string",
            "inlineDocument": "string"
          },
          "hashAlgorithm": "string",
          "signatureAlgorithm": "string"
        }
      },
      "attributes": {
        "string": "string"
      }
    }
  ],
  "roleArn": "string",
  "additionalParameters": {
    "string": "string"
  },
  "tags": [
    {
      "Key": "string",
      "Value": "string"
    }
  ]
}

cli-input-json fields

Name Type Description
otaUpdateId string (max:128 min:1) The ID of the OTA update to be created.
description string (max:2028) The description of the OTA update.
targets list The devices targeted to receive OTA updates.
protocols list The protocol used to transfer the OTA update image. Valid values are [HTTP], [MQTT], [HTTP, MQTT]. When both HTTP and MQTT are specified, the target device can choose the protocol.
targetSelection string Specifies whether the update will continue to run (CONTINUOUS), or will be complete after all the things specified as targets have completed the update (SNAPSHOT). If continuous, the update may also be run on a thing when a change is detected in a target. For example, an update will run on a thing when the thing is added to a target group, even after the update was completed by all things originally in the group. Valid values: CONTINUOUS | SNAPSHOT. enum: CONTINUOUS | SNAPSHOT
awsJobExecutionsRolloutConfig Configuration for the rollout of OTA updates.
maximumPerMinute integer (max:1000 min:1) The maximum number of OTA update job executions started per minute.
exponentialRate The rate of increase for a job rollout. This parameter allows you to define an exponential rate increase for a job rollout.
baseRatePerMinute integer (max:1000 min:1) The minimum number of things that will be notified of a pending job, per minute, at the start of the job rollout. This is the initial rate of the rollout.
rateIncreaseCriteria The criteria to initiate the increase in rate of rollout for a job. AWS IoT supports up to one digit after the decimal (for example, 1.5, but not 1.55).
numberOfNotifiedThings integer (min:1) When this number of things have been notified, it will initiate an increase in the rollout rate.
numberOfSucceededThings integer (min:1) When this number of things have succeeded in their job execution, it will initiate an increase in the rollout rate.
awsJobPresignedUrlConfig Configuration information for pre-signed URLs.
expiresInSec long How long (in seconds) pre-signed URLs are valid. Valid values are 60 - 3600, the default value is 1800 seconds. Pre-signed URLs are generated when a request for the job document is received.
awsJobAbortConfig The criteria that determine when and how a job stoppage takes place.
abortCriteriaList list The list of criteria that determine when and how to stop the job.
failureType string The type of job execution failures that can initiate a job stoppage. enum: FAILED | REJECTED | TIMED_OUT | ALL
action string The type of job action to take to initiate the job stoppage. enum: CANCEL
minNumberOfExecutedThings integer (min:1) The minimum number of things which must receive job execution notifications before the job can be stopped.
awsJobTimeoutConfig Specifies the amount of time each device has to finish its execution of the job. A timer is started when the job execution status is set to IN_PROGRESS. If the job execution status is not set to another terminal state before the timer expires, it will be automatically set to TIMED_OUT.
inProgressTimeoutInMinutes long Specifies the amount of time, in minutes, this device has to finish execution of this job. The timeout interval can be anywhere between 1 minute and 7 days (1 to 10080 minutes). The in progress timer can't be updated and will apply to all job executions for the job. Whenever a job execution remains in the IN_PROGRESS status for longer than this interval, the job execution will fail and switch to the terminal TIMED_OUT status.
files list The files to be streamed by the OTA update.
fileName string The name of the file.
fileType integer range- max:255 min:0 An integer value you can include in the job document to allow your devices to identify the type of file received from the cloud.
fileVersion string The file version.
fileLocation The location of the updated firmware.
stream The stream that contains the OTA update.
streamId string (max:128 min:1) The stream ID.
fileId integer (max:255 min:0) The ID of a file associated with a stream.
s3Location The location of the updated firmware in S3.
bucket string (min:1) The S3 bucket.
key string (min:1) The S3 key.
version string The S3 bucket version.
codeSigning The code signing method of the file.
awsSignerJobId string The ID of the AWSSignerJob which was created to sign the file.
startSigningJobParameter Describes the code-signing job.
signingProfileParameter Describes the code-signing profile.
certificateArn string Certificate ARN.
platform string The hardware platform of your device.
certificatePathOnDevice string The location of the code-signing certificate on your device.
signingProfileName string The code-signing profile name.
destination The location to write the code-signed file.
s3Destination Describes the location in S3 of the updated firmware.
bucket string (min:1) The S3 bucket that contains the updated firmware.
prefix string The S3 prefix.
customCodeSigning A custom method for code signing a file.
signature The signature for the file.
inlineDocument blob A base64 encoded binary representation of the code signing signature.
certificateChain The certificate chain.
certificateName string The name of the certificate.
inlineDocument string A base64 encoded binary representation of the code signing certificate chain.
hashAlgorithm string The hash algorithm used to code sign the file.
signatureAlgorithm string The signature algorithm used to code sign the file.
attributes map A list of name/attribute pairs.
roleArn string (max:2048 min:20) The IAM role that grants AWS IoT access to the Amazon S3, AWS IoT jobs and AWS Code Signing resources to create an OTA update job.
additionalParameters map A list of additional OTA update parameters which are name-value pairs.
tags list Metadata which can be used to manage updates.
Key string (max:128 min:1) The tag's key.
Value string (max:256 min:1) The tag's value.

Output

{
  "otaUpdateId": "string",
  "awsIotJobId": "string",
  "otaUpdateArn": "string",
  "awsIotJobArn": "string",
  "otaUpdateStatus": "string"
}

AWS CLI output fields

Name Type Description
otaUpdateId string (max:128 min:1) The OTA update ID.
awsIotJobId string The AWS IoT job ID associated with the OTA update.
otaUpdateArn string The OTA update ARN.
awsIotJobArn string The AWS IoT job ARN associated with the OTA update.
otaUpdateStatus string The OTA update status. enum: CREATE_PENDING | CREATE_IN_PROGRESS | CREATE_COMPLETE | CREATE_FAILED

The following is an example of a JSON file passed into the create-ota-update command that uses Code Signing for AWS IoT.

[
  {
    "fileName": "firmware.bin",                
    "fileType": 1,
    "fileLocation": {
      "stream": {
        "streamId": "004",                         
        "fileId":123
      }                        
    },
    "codeSigning": {
      "awsSignerJobId": "48c67f3c-63bb-4f92-a98a-4ee0fbc2bef6"     
    }
  }
]

The following is an example of a JSON file passed into the create-ota-update AWS CLI command that uses an inline file to provide custom code-signing material.

[
  {
    "fileName": "firmware.bin",
    "fileType": 1,
    "fileLocation": {
      "stream": {
        "streamId": "004",
        "fileId": 123
      }
    },
    "codeSigning": {
      "customCodeSigning":{
        "signature":{
          "inlineDocument":"your_signature"
        },
        "certificateChain": {
          "certificateName": "your_certificate_name",
          "inlineDocument":"your_certificate_chain"
        },
        "hashAlgorithm":"your_hash_algorithm",
        "signatureAlgorithm":"your_signature_algorithm"
      }
    }
  }
]

The following is an example of a JSON file passed into the create-ota-update AWS CLI command that allows FreeRTOS OTA to start a code-signing job and create a code-signing profile and stream.

[
  {
    "fileName": "your_firmware_path_on_device",
    "fileType": 1,
    "fileVersion": "1",
    "fileLocation": {
      "s3Location": {
        "bucket": "your_bucket_name",
        "key": "your_object_key",
        "version": "your_S3_object_version"
      }
    },
    "codeSigning":{
      "startSigningJobParameter":{
        "signingProfileName": "myTestProfile",
        "signingProfileParameter": {
          "certificateArn": "your_certificate_arn",
          "platform": "your_platform_id",
          "certificatePathOnDevice": "certificate_path"
        },
        "destination": {
          "s3Destination": {
            "bucket": "your_destination_bucket"
          }
        }
      }
    }  
  }
]

The following is an example of a JSON file passed into the create-ota-update AWS CLI command that creates an OTA update that starts a code-signing job with an existing profile and uses the specified stream.

[
  {
    "fileName": "your_firmware_path_on_device",
    "fileType": 1,
    "fileVersion": "1",
    "fileLocation": {
      "s3Location": {
        "bucket": "your_s3_bucket_name",
        "key": "your_object_key",
        "version": "your_S3_object_version"
      }
    },
    "codeSigning":{
      "startSigningJobParameter":{
        "signingProfileName": "your_unique_profile_name",
        "destination": {
          "s3Destination": {
            "bucket": "your_destination_bucket"
          }
        }
      }
    }  
  }
]

The following is an example of a JSON file passed into the create-ota-update AWS CLI command that allows FreeRTOS OTA to create a stream with an existing code-signing job ID.

[
  {
    "fileName": "your_firmware_path_on_device",
    "fileType": 1,
    "fileVersion": "1",
    "codeSigning":{
      "awsSignerJobId": "your_signer_job_id"
    }  
  }
]

The following is an example of a JSON file passed into the create-ota-update AWS CLI command that creates an OTA update. The update creates a stream from the specified S3 object and uses custom code signing.

[
  {
    "fileName": "your_firmware_path_on_device",
    "fileType": 1,
    "fileVersion": "1",
    "fileLocation": {
      "s3Location": {
        "bucket": "your_bucket_name",
        "key": "your_object_key",
        "version": "your_S3_object_version"
      }
    },
    "codeSigning":{
      "customCodeSigning": {
        "signature":{
          "inlineDocument":"your_signature"
        },
        "certificateChain": {
          "inlineDocument":"your_certificate_chain",
          "certificateName": "your_certificate_path_on_device"
        },
        "hashAlgorithm":"your_hash_algorithm",
        "signatureAlgorithm":"your_sig_algorithm"
      }
    }  
  }
]

Listing OTA updates

You can use the list-ota-updates AWS CLI command to get a list of all OTA updates.

aws iot list-ota-updates

The output from the list-ota-updates command looks like this.

{
  "otaUpdates": [
     
    {
      "otaUpdateId": "my_ota_update2",
      "otaUpdateArn": "arn:aws:iot:us-west-2:123456789012:otaupdate/my_ota_update2",
      "creationDate": 1522778769.042
    },
    {
      "otaUpdateId": "my_ota_update1",
      "otaUpdateArn": "arn:aws:iot:us-west-2:123456789012:otaupdate/my_ota_update1",
      "creationDate": 1522775938.956
    },
    {
      "otaUpdateId": "my_ota_update",
      "otaUpdateArn": "arn:aws:iot:us-west-2:123456789012:otaupdate/my_ota_update",
      "creationDate": 1522775151.031
    }
  ]
}

Getting information about an OTA update

You can use the get-ota-update AWS CLI command to get the creation or deletion status of an OTA update.

aws iot get-ota-update --ota-update-id your-ota-update-id

The output from the get-ota-update command looks like the following.

{ 
    "otaUpdateInfo": { 
        "otaUpdateId": "ota-update-001", 
        "otaUpdateArn": "arn:aws:iot:region:123456789012:otaupdate/ota-update-001", 
        "creationDate": 1575414146.286, 
        "lastModifiedDate": 1575414149.091, 
        "targets": [ 
            "arn:aws:iot:region:123456789012:thing/myDevice" 
        ], 
        "protocols": [ "HTTP" ], 
        "awsJobExecutionsRolloutConfig": { 
            "maximumPerMinute": 0 
        }, 
        "awsJobPresignedUrlConfig": { 
            "expiresInSec": 1800 
        }, 
        "targetSelection": "SNAPSHOT", 
        "otaUpdateFiles": [ 
            { 
                "fileName": "my_firmware.bin", 
                "fileType": 1,
                "fileLocation": { 
                    "s3Location": { 
                        "bucket": "my-bucket", 
                        "key": "my_firmware.bin", 
                        "version": "AvP3bfJC9gyqnwoxPHuTqM5GWENt4iii" 
                    } 
                }, 
                "codeSigning": { 
                    "awsSignerJobId": "b7a55a54-fae5-4d3a-b589-97ed103737c2", 
                    "startSigningJobParameter": { 
                        "signingProfileParameter": {}, 
                        "signingProfileName": "my-profile-name", 
                        "destination": { 
                            "s3Destination": { 
                                "bucket": "some-ota-bucket", 
                                "prefix": "SignedImages/" 
                            } 
                        } 
                    }, 
                    "customCodeSigning": {} 
                } 
            } 
        ], 
        "otaUpdateStatus": "CREATE_COMPLETE", 
        "awsIotJobId": "AFR_OTA-ota-update-001", 
        "awsIotJobArn": "arn:aws:iot:region:123456789012:job/AFR_OTA-ota-update-001" 
    } 
}

The values returned for otaUpdateStatus include the following:

CREATE_PENDING
The creation of an OTA update is pending.

CREATE_IN_PROGRESS
An OTA update is being created.

CREATE_COMPLETE
An OTA update has been created.

CREATE_FAILED
The creation of an OTA update failed.

DELETE_IN_PROGRESS
An OTA update is being deleted.

DELETE_FAILED
The deletion of an OTA update failed.

Note
To get the execution status of an OTA update after it is created, you need to use the describe-job-execution command. For more information, see Describe Job Execution.

Deleting OTA-related data

Currently, you cannot use the AWS IoT console to delete streams or OTA updates. You can use the AWS CLI to delete streams, OTA updates, and the AWS IoT jobs created during an OTA update.

Deleting an OTA stream

When you create an OTA update that uses MQTT, either you can use the command-line or the AWS IoT console to create a stream to break the firmware up into chunks so it can be sent over MQTT. You can delete this stream with the delete-stream AWS CLI command, as shown in the following example.

aws iot delete-stream --stream-id your_stream_id

Deleting an OTA update

When you create an OTA update, the following are created:

  • An entry in the OTA update job database.
  • An AWS IoT job to perform the update.
  • An AWS IoT job execution for each device being updated.

The delete-ota-update command deletes the entry in the OTA update job database only. You must use the delete-job command to delete the AWS IoT job.

Use the delete-ota-update command to delete an OTA update.

aws iot delete-ota-update --ota-update-id your_ota_update_id

ota-update-id
The ID of the OTA update to delete.

delete-stream
Deletes the stream associated with the OTA update.

force-delete-aws-job
Deletes the AWS IoT job associated with the OTA update. If this flag is not set and the job is in the In_Progress state, the job is not deleted.

Deleting an IoT job created for an OTA update

FreeRTOS creates an AWS IoT job when you create an OTA update. A job execution is also created for each device that processes the job. You can use the delete-job AWS CLI command to delete a job and its associated job executions.

aws iot delete-job --job-id your-job-id --no-force

The no-force parameter specifies that only jobs that are in a terminal state (COMPLETED or CANCELLED) can be deleted. You can delete a job that is in a non-terminal state by passing the force parameter. For more information, see DeleteJob API.

Note
Deleting a job with a status of IN_PROGRESS interrupts any job executions that are IN_PROGRESS on your devices and can result in a device being left in a nondeterministic state. Make sure that each device executing a job that has been deleted can recover to a known state.

Depending on the number of job executions created for the job and other factors, it can take a few minutes to delete a job. While the job is being deleted, its status is DELETION_IN_PROGRESS. Attempting to delete or cancel a job whose status is already DELETION_IN_PROGRESS results in an error.

You can use the delete-job-execution to delete a job execution. You might want to delete a job execution when a small number of devices are unable to process a job. This deletes the job execution for a single device, as shown in the following example.

aws iot delete-job-execution --job-id your-job-id --thing-name
                    your-thing-name --execution-number your-job-execution-number --no-force

As with the delete-job AWS CLI command, you can pass the --force parameter to the delete-job-execution to force the deletion of a job execution. For more information , see DeleteJobExecution API.

Note
Deleting a job execution with a status of IN_PROGRESS interrupts any job executions that are IN_PROGRESS on your devices and can result in a device being left in a nondeterministic state. Make sure that each device executing a job that has been deleted can recover to a known state.

For more information about using the OTA update demo application, see Over-the-air updates demo application.