From 5b83d46fb241ac27d6b98c6d5689a851c39824e2 Mon Sep 17 00:00:00 2001 From: Christina Ying Wang Date: Mon, 9 Dec 2024 12:49:18 -0800 Subject: [PATCH] Target hostapp hook: Only patch should_be_operated_by__release if null With Supervisor managed HUP, we'll soon start relying on should_be_operated_by__release to determine the target hostapp release. The Supervisor reports os_version and os_variant on device provision, and the current target hostapp hook will set this field when receiving that current state report. However, SV manage HUP means this field could be set prior to device provision, so we don't want to overwrite it if it's not null. Change-type: patch Signed-off-by: Christina Ying Wang --- src/features/hostapp/hooks/target-hostapp.ts | 30 +++++++++++++---- test/15_target-hostapp.ts | 34 ++++++++++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/features/hostapp/hooks/target-hostapp.ts b/src/features/hostapp/hooks/target-hostapp.ts index e19c82209..8295d8edd 100644 --- a/src/features/hostapp/hooks/target-hostapp.ts +++ b/src/features/hostapp/hooks/target-hostapp.ts @@ -63,7 +63,7 @@ hooks.addPureHook('PATCH', 'resin', 'device', { /** * When a device checks in with it's initial OS version, set the corresponding should_be_operated_by__release resource - * using its current reported version. + * using its current reported version only if should_be_operated_by__release is null. */ hooks.addPureHook('PATCH', 'resin', 'device', { async PRERUN(args) { @@ -72,12 +72,28 @@ hooks.addPureHook('PATCH', 'resin', 'device', { args.request.values.os_variant != null ) { const ids = await sbvrUtils.getAffectedIds(args); - await setOSReleaseResource( - args.api, - ids, - args.request.values.os_version, - args.request.values.os_variant, - ); + // Only set device's should_be_operated_by__release if it's null. + // This ensures the target hostapp field isn't overwritten when + // a device reports OS info on provision. + const devicesWithNullOperatedByRelease = await args.api.get({ + resource: 'device', + options: { + $filter: { + id: { $in: ids }, + should_be_operated_by__release: null, + }, + $select: ['id'], + }, + }); + + if (devicesWithNullOperatedByRelease.length > 0) { + await setOSReleaseResource( + args.api, + devicesWithNullOperatedByRelease.map((d) => d.id), + args.request.values.os_version, + args.request.values.os_variant, + ); + } } }, }); diff --git a/test/15_target-hostapp.ts b/test/15_target-hostapp.ts index 27233202d..3d521a9b4 100644 --- a/test/15_target-hostapp.ts +++ b/test/15_target-hostapp.ts @@ -633,6 +633,40 @@ export default () => { .expect(200); expect(dev.d[0].should_be_operated_by__release).to.be.null; }); + + it('should not overwrite existing should_be_operated_by__release when device reports OS info', async () => { + // First set up a device with a specific target release + await supertest(admin) + .patch(`/${version}/device(${device1.id})`) + .send({ + should_be_operated_by__release: nuc2_51_0_rev1prodTagAndSemverId, + }) + .expect(200); + + // Verify initial state + await expectResourceToMatch(pineUser, 'device', device1.id, { + should_be_operated_by__release: { + __id: nuc2_51_0_rev1prodTagAndSemverId, + }, + }); + + // Now patch the device with OS info that would normally map to a different release + await device1.patchStateV2({ + local: { + os_version: 'balenaOS 2.90.1+rev1', // This would normally map to nucDraft2_90_1rev1SemverOnlyId + os_variant: 'prod', + }, + }); + + // Verify the should_be_operated_by__release was not changed + await expectResourceToMatch(pineUser, 'device', device1.id, { + should_be_operated_by__release: { + __id: nuc2_51_0_rev1prodTagAndSemverId, + }, + os_version: 'balenaOS 2.90.1+rev1', + os_variant: 'prod', + }); + }); }); }); };