diff --git a/command/ota/upload.go b/command/ota/upload.go index fcb32267..a41cf462 100644 --- a/command/ota/upload.go +++ b/command/ota/upload.go @@ -19,6 +19,7 @@ package ota import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -101,9 +102,18 @@ func Upload(ctx context.Context, params *UploadParams, cred *config.Credentials) expiration = otaDeferredExpirationMins } + var conflictedOta *otaapi.Ota err = iotClient.DeviceOTA(ctx, params.DeviceID, file, expiration) if err != nil { - return err + if errors.Is(err, iot.ErrOtaAlreadyInProgress) { + conflictedOta = &otaapi.Ota{ + DeviceID: params.DeviceID, + Status: "Skipped", + ErrorReason: "OTA already in progress", + } + } else { + return err + } } // Try to get ota-id from API otaID, err := otapi.GetOtaLastStatusByDeviceID(params.DeviceID) @@ -111,7 +121,14 @@ func Upload(ctx context.Context, params *UploadParams, cred *config.Credentials) return err } if otaID != nil && len(otaID.Ota) > 0 { - feedback.PrintResult(otaID.Ota[0]) + if conflictedOta != nil { + toPrint := otaapi.OtaStatusList{ + Ota: []otaapi.Ota{*conflictedOta, otaID.Ota[0]}, + } + feedback.PrintResult(toPrint) + } else { + feedback.PrintResult(otaID.Ota[0]) + } } return nil diff --git a/internal/iot/client.go b/internal/iot/client.go index 55170caa..1ea50544 100644 --- a/internal/iot/client.go +++ b/internal/iot/client.go @@ -28,6 +28,8 @@ import ( "golang.org/x/oauth2" ) +var ErrOtaAlreadyInProgress = fmt.Errorf("ota already in progress") + // Client can perform actions on Arduino IoT Cloud. type Client struct { api *iotclient.APIClient @@ -196,9 +198,12 @@ func (cl *Client) DeviceOTA(ctx context.Context, id string, file *os.File, expir Async: optional.NewBool(true), } resp, err := cl.api.DevicesV2OtaApi.DevicesV2OtaUpload(ctx, id, file, opt) - if err != nil && resp.StatusCode != 409 { // 409 (Conflict) is the status code for an already existing OTA for the same SHA/device, so ignoring it. - err = fmt.Errorf("uploading device ota: %w", errorDetail(err)) - return err + if err != nil { + // 409 (Conflict) is the status code for an already existing OTA in progress for the same device. Handling it in a different way. + if resp.StatusCode == 409 { + return ErrOtaAlreadyInProgress + } + return fmt.Errorf("uploading device ota: %w", errorDetail(err)) } return nil }