Skip to content

Commit

Permalink
Merge pull request #1443 from balena-io/jaomaloy/detached-hup
Browse files Browse the repository at this point in the history
Add option for detached HUP on startOsUpdate
  • Loading branch information
flowzone-app[bot] authored Oct 25, 2024
2 parents 9e4fd03 + 8923df6 commit cb0cd3c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 18 deletions.
22 changes: 13 additions & 9 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@ const sdk = fromSharedOptions();
* [.pinToRelease(uuidOrIdOrArray, fullReleaseHashOrId)](#balena.models.device.pinToRelease) ⇒ <code>Promise</code>
* [.trackApplicationRelease(uuidOrIdOrArray)](#balena.models.device.trackApplicationRelease) ⇒ <code>Promise</code>
* [.setSupervisorRelease(uuidOrIdOrArray, supervisorVersionOrId)](#balena.models.device.setSupervisorRelease) ⇒ <code>Promise</code>
* [.startOsUpdate(uuidOrUuids, targetOsVersion)](#balena.models.device.startOsUpdate) ⇒ <code>Promise</code>
* [.getOsUpdateStatus(uuid)](#balena.models.device.getOsUpdateStatus) ⇒ <code>Promise</code>
* [.startOsUpdate(uuidOrUuids, targetOsVersion, [options])](#balena.models.device.startOsUpdate) ⇒ <code>Promise</code>
* ~~[.getOsUpdateStatus(uuid)](#balena.models.device.getOsUpdateStatus) ⇒ <code>Promise</code>~~
* [.ping(uuidOrId)](#balena.models.device.ping) ⇒ <code>Promise</code>
* ~~[.getApplicationInfo(uuidOrId)](#balena.models.device.getApplicationInfo) ⇒ <code>Promise</code>~~
* [.identify(uuidOrId)](#balena.models.device.identify) ⇒ <code>Promise</code>
Expand Down Expand Up @@ -708,8 +708,8 @@ balena.models.device.get(123).catch(function (error) {
* [.pinToRelease(uuidOrIdOrArray, fullReleaseHashOrId)](#balena.models.device.pinToRelease) ⇒ <code>Promise</code>
* [.trackApplicationRelease(uuidOrIdOrArray)](#balena.models.device.trackApplicationRelease) ⇒ <code>Promise</code>
* [.setSupervisorRelease(uuidOrIdOrArray, supervisorVersionOrId)](#balena.models.device.setSupervisorRelease) ⇒ <code>Promise</code>
* [.startOsUpdate(uuidOrUuids, targetOsVersion)](#balena.models.device.startOsUpdate) ⇒ <code>Promise</code>
* [.getOsUpdateStatus(uuid)](#balena.models.device.getOsUpdateStatus) ⇒ <code>Promise</code>
* [.startOsUpdate(uuidOrUuids, targetOsVersion, [options])](#balena.models.device.startOsUpdate) ⇒ <code>Promise</code>
* ~~[.getOsUpdateStatus(uuid)](#balena.models.device.getOsUpdateStatus) ⇒ <code>Promise</code>~~
* [.ping(uuidOrId)](#balena.models.device.ping) ⇒ <code>Promise</code>
* ~~[.getApplicationInfo(uuidOrId)](#balena.models.device.getApplicationInfo) ⇒ <code>Promise</code>~~
* [.identify(uuidOrId)](#balena.models.device.identify) ⇒ <code>Promise</code>
Expand Down Expand Up @@ -2283,8 +2283,8 @@ balena.models.application.revokeSupportAccess(123);
* [.pinToRelease(uuidOrIdOrArray, fullReleaseHashOrId)](#balena.models.device.pinToRelease) ⇒ <code>Promise</code>
* [.trackApplicationRelease(uuidOrIdOrArray)](#balena.models.device.trackApplicationRelease) ⇒ <code>Promise</code>
* [.setSupervisorRelease(uuidOrIdOrArray, supervisorVersionOrId)](#balena.models.device.setSupervisorRelease) ⇒ <code>Promise</code>
* [.startOsUpdate(uuidOrUuids, targetOsVersion)](#balena.models.device.startOsUpdate) ⇒ <code>Promise</code>
* [.getOsUpdateStatus(uuid)](#balena.models.device.getOsUpdateStatus) ⇒ <code>Promise</code>
* [.startOsUpdate(uuidOrUuids, targetOsVersion, [options])](#balena.models.device.startOsUpdate) ⇒ <code>Promise</code>
* ~~[.getOsUpdateStatus(uuid)](#balena.models.device.getOsUpdateStatus) ⇒ <code>Promise</code>~~
* [.ping(uuidOrId)](#balena.models.device.ping) ⇒ <code>Promise</code>
* ~~[.getApplicationInfo(uuidOrId)](#balena.models.device.getApplicationInfo) ⇒ <code>Promise</code>~~
* [.identify(uuidOrId)](#balena.models.device.identify) ⇒ <code>Promise</code>
Expand Down Expand Up @@ -4017,7 +4017,7 @@ balena.models.device.setSupervisorRelease(123, '11.4.14').then(function() {
```
<a name="balena.models.device.startOsUpdate"></a>

##### device.startOsUpdate(uuidOrUuids, targetOsVersion) ⇒ <code>Promise</code>
##### device.startOsUpdate(uuidOrUuids, targetOsVersion, [options]) ⇒ <code>Promise</code>
**Kind**: static method of [<code>device</code>](#balena.models.device)
**Summary**: Start an OS update on a device
**Access**: public
Expand All @@ -4027,6 +4027,8 @@ balena.models.device.setSupervisorRelease(123, '11.4.14').then(function() {
| --- | --- | --- |
| uuidOrUuids | <code>String</code> \| <code>Array.&lt;String&gt;</code> | full device uuid or array of full uuids |
| targetOsVersion | <code>String</code> | semver-compatible version for the target device Unsupported (unpublished) version will result in rejection. The version **must** be the exact version number, a "prod" variant and greater than the one running on the device. To resolve the semver-compatible range use `balena.model.os.getMaxSatisfyingVersion`. |
| [options] | <code>Object</code> | options |
| [options.runDetached] | <code>Boolean</code> | run the update in detached mode. Default behaviour is runDetached=false but is DEPRECATED and will be removed in a future release. Use runDetached=true for more reliable updates. |

**Example**
```js
Expand All @@ -4036,9 +4038,11 @@ balena.models.device.startOsUpdate('7cf02a687b74206f92cb455969cf8e98', '2.29.2+r
```
<a name="balena.models.device.getOsUpdateStatus"></a>

##### device.getOsUpdateStatus(uuid) ⇒ <code>Promise</code>
##### ~~device.getOsUpdateStatus(uuid) ⇒ <code>Promise</code>~~
***Deprecated***

**Kind**: static method of [<code>device</code>](#balena.models.device)
**Summary**: Get the OS update status of a device
**Summary**: Get the OS update status of a device. This will no longer return a useful status for runDetached=true updates.
**Access**: public
**Fulfil**: <code>Object</code> - action response

Expand Down
19 changes: 16 additions & 3 deletions src/models/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,9 @@ const getDeviceModel = function (

const getOsUpdateHelper = once(async () => {
const $deviceUrlsBase = await getDeviceUrlsBase();
const { getOsUpdateHelper: _getOsUpdateHelper } =
require('../util/device-actions/os-update') as typeof import('../util/device-actions/os-update');
const _getOsUpdateHelper = (
await import('../util/device-actions/os-update')
).getOsUpdateHelper;
return _getOsUpdateHelper($deviceUrlsBase, request);
});
/* eslint-enable @typescript-eslint/no-require-imports */
Expand Down Expand Up @@ -334,14 +335,17 @@ const getDeviceModel = function (
async function startOsUpdate(
uuidOrUuids: string,
targetOsVersion: string,
options?: { runDetached?: boolean },
): Promise<OsUpdateActionResult>;
async function startOsUpdate(
uuidOrUuids: string[],
targetOsVersion: string,
options?: { runDetached?: boolean },
): Promise<Dictionary<OsUpdateActionResult>>;
async function startOsUpdate(
uuidOrUuids: string | string[],
targetOsVersion: string,
options: { runDetached?: boolean } = { runDetached: false },
): Promise<OsUpdateActionResult | Dictionary<OsUpdateActionResult>> {
if (!targetOsVersion) {
throw new errors.BalenaInvalidParameterError(
Expand Down Expand Up @@ -369,6 +373,7 @@ const getDeviceModel = function (
);

const osUpdateHelper = await getOsUpdateHelper();

const results: Dictionary<
ResolvableReturnType<typeof osUpdateHelper.startOsUpdate>
> = {};
Expand Down Expand Up @@ -410,10 +415,13 @@ const getDeviceModel = function (
);
}
}

// use the v2 device actions api for detached updates
await limitedMap(devices, async (device) => {
results[device.uuid] = await osUpdateHelper.startOsUpdate(
device.uuid,
targetOsVersion,
options.runDetached === true ? 'v2' : 'v1',
);
});
},
Expand Down Expand Up @@ -2262,6 +2270,10 @@ const getDeviceModel = function (
* Unsupported (unpublished) version will result in rejection.
* The version **must** be the exact version number, a "prod" variant and greater than the one running on the device.
* To resolve the semver-compatible range use `balena.model.os.getMaxSatisfyingVersion`.
* @param {Object} [options] - options
* @param {Boolean} [options.runDetached] - run the update in detached mode.
* Default behaviour is runDetached=false but is DEPRECATED and will be removed in a future release. Use runDetached=true
* for more reliable updates.
* @fulfil {Object} - action response
* @returns {Promise}
*
Expand All @@ -2273,7 +2285,8 @@ const getDeviceModel = function (
startOsUpdate,

/**
* @summary Get the OS update status of a device
* @deprecated
* @summary Get the OS update status of a device. This will no longer return a useful status for runDetached=true updates.
* @name getOsUpdateStatus
* @public
* @function
Expand Down
12 changes: 8 additions & 4 deletions src/util/device-actions/device-actions-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { BalenaRequest } from 'balena-request';
interface MakeActionRequestParams {
uuid: string;
actionNameOrId: string | number;
deviceActionsApiVersion: 'v1' | 'v2';
params?: any;
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
extraOptions: any;
Expand All @@ -11,6 +12,7 @@ interface MakeActionRequestParams {
interface StartActionParams {
uuid: string;
actionName: string;
deviceActionsApiVersion: 'v1' | 'v2';
params: any;
extraOptions?: any;
}
Expand All @@ -21,28 +23,28 @@ interface GetActionStatusParams {
extraOptions?: any;
}

const DEVICE_ACTIONS_API_VERSION = 'v1';

export class DeviceActionsService {
private actionsEndpoint: string;

constructor(
deviceUrlsBase: string,
private request: BalenaRequest,
) {
this.actionsEndpoint = `https://actions.${deviceUrlsBase}/${DEVICE_ACTIONS_API_VERSION}`;
this.actionsEndpoint = `https://actions.${deviceUrlsBase}`;
}

public startAction = <T>({
uuid,
actionName,
deviceActionsApiVersion,
params,
extraOptions,
}: StartActionParams) =>
this.makeActionRequest<T>({
method: 'POST',
uuid,
actionNameOrId: actionName,
deviceActionsApiVersion,
params,
extraOptions,
});
Expand All @@ -55,6 +57,7 @@ export class DeviceActionsService {
this.makeActionRequest<T>({
method: 'GET',
uuid,
deviceActionsApiVersion: 'v1',
actionNameOrId: actionId,
extraOptions,
});
Expand All @@ -63,14 +66,15 @@ export class DeviceActionsService {
method,
uuid,
actionNameOrId,
deviceActionsApiVersion,
params,
extraOptions,
}: MakeActionRequestParams): Promise<T> => {
const data = params ? { parameters: params } : null;

const { body } = await this.request.send<T>({
method,
url: `${this.actionsEndpoint}/${uuid}/${actionNameOrId}`,
url: `${this.actionsEndpoint}/${deviceActionsApiVersion}/${uuid}/${actionNameOrId}`,
body: data,
...extraOptions,
});
Expand Down
15 changes: 13 additions & 2 deletions src/util/device-actions/os-update/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ const OS_UPDATE_ACTION_NAME = 'resinhup';

// See: https://github.com/balena-io/resin-proxy/issues/51#issuecomment-274251469
export interface OsUpdateActionResult {
status: 'idle' | 'in_progress' | 'done' | 'error' | 'configuring';
status:
| 'idle'
| 'in_progress'
| 'done'
| 'error'
| 'configuring'
| 'triggered';
parameters?: {
target_version: string;
};
Expand All @@ -22,10 +28,15 @@ export const getOsUpdateHelper = function (
request,
);

const startOsUpdate = (uuid: string, targetOsVersion: string) => {
const startOsUpdate = (
uuid: string,
targetOsVersion: string,
deviceActionsApiVersion: 'v1' | 'v2',
) => {
return deviceActionsService.startAction<OsUpdateActionResult>({
uuid,
actionName: OS_UPDATE_ACTION_NAME,
deviceActionsApiVersion,
params: {
target_version: targetOsVersion,
},
Expand Down

0 comments on commit cb0cd3c

Please sign in to comment.