Skip to content

Commit

Permalink
Use HUP detached mode for improved resilience with an unreliable network
Browse files Browse the repository at this point in the history
Change-type: patch
Signed-off-by: Ken Bannister <[email protected]>
  • Loading branch information
kb2ma committed Jan 13, 2025
1 parent bce9641 commit b1ab57d
Showing 1 changed file with 42 additions and 16 deletions.
58 changes: 42 additions & 16 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import { getSdk } from 'balena-sdk';
import type { StringValue } from 'ms';
import ms from 'ms';

/** Functional state of HUP on device for our purposes. */
enum HupStatus {
RUNNING,
FAILED,
NOT_RUNNING,
/** For example, can't determine status if can't reach API. */
UNKNOWN,
}

const apiKey = (process.env.BALENA_API_KEY as unknown as string) ?? undefined;
const apiUrl = (process.env.BALENA_API_URL as unknown as string) ?? undefined;
const deviceUuid =
Expand Down Expand Up @@ -83,14 +92,26 @@ const getTargetVersion = async (
});
};

const getUpdateStatus = async (uuid: string): Promise<any> => {
/** Retrieve device model for status of HUP properties. */
const getUpdateStatus = async (uuid: string): Promise<HupStatus> => {
try {
const hupStatus = await balena.models.device.getOsUpdateStatus(uuid);
console.log(hupStatus);
return hupStatus;
const hupProps = await balena.models.device.get(uuid, {
$select: ['status', 'provisioning_state', 'provisioning_progress'],
});
console.log(`Device HUP status: ${JSON.stringify(hupProps)}`);

if (hupProps.status.toLowerCase() === 'configuring') {
if (hupProps.provisioning_state === 'OS update failed') {
return HupStatus.FAILED;
} else {
return HupStatus.RUNNING;
}
} else {
return HupStatus.NOT_RUNNING;
}
} catch (e) {
console.error(`Error getting status: ${e}`);
return false;
return HupStatus.UNKNOWN;
}
};

Expand All @@ -105,11 +126,12 @@ const main = async () => {

console.log('Checking last update status...');
while (
await getUpdateStatus(deviceUuid).then((status) => {
return !status || status.status === 'in_progress';
})
await getUpdateStatus(deviceUuid).then(
status => status === HupStatus.UNKNOWN
|| status === HupStatus.RUNNING,
)
) {
console.log('Another update is already in progress...');
console.log('Another update may be in progress...');
await delay('2m');
}

Expand All @@ -127,16 +149,20 @@ const main = async () => {
} else {
console.log(`Starting balenaOS host update to ${targetVersion}...`);
await balena.models.device
.startOsUpdate(deviceUuid, targetVersion)
.startOsUpdate(deviceUuid, targetVersion, { runDetached: true })
.then(async () => {
// Allow time for server to start HUP on device, which then
// sets Configuring status.
await delay('20s');
while (
// print progress at regular intervals until status changes
// or device reboots
await getUpdateStatus(deviceUuid).then((status) => {
return !status || status.status === 'in_progress';
})
// Print progress at regular intervals while API indicates
// HUP still may be running.
await getUpdateStatus(deviceUuid).then(
status => status === HupStatus.UNKNOWN
|| status === HupStatus.RUNNING,
)
) {
await delay('10s');
await delay('20s');
}
})
.catch((e) => {
Expand Down

0 comments on commit b1ab57d

Please sign in to comment.