Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Target hostapp hook: Only patch should_be_operated_by__release if null or older release #1891

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions src/features/hostapp/hooks/target-hostapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ 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 or older than the current OS version.
* This ensures the target hostapp field isn't overwritten by an older OS release when a device reports OS info on provision.
*/
hooks.addPureHook('PATCH', 'resin', 'device', {
async PRERUN(args) {
Expand Down Expand Up @@ -121,7 +122,7 @@ async function setOSReleaseResource(
id: { $in: deviceIds },
os_version: null,
},
$select: ['id', 'is_of__device_type'],
$select: ['id', 'should_be_operated_by__release', 'is_of__device_type'],
},
});

Expand All @@ -147,8 +148,6 @@ async function setOSReleaseResource(
return Promise.all(
Array.from(devicesByDeviceTypeId.entries()).map(
async ([deviceTypeId, affectedDevices]) => {
const affectedDeviceIds = affectedDevices.map((d) => d.id);

const osRelease = await getOSReleaseResource(
api,
osVersion,
Expand All @@ -160,6 +159,19 @@ async function setOSReleaseResource(
return;
}

// Only patch should_be_operated_by__release if it's null or older than the reported OS release
const affectedDeviceIds = affectedDevices
.filter(
(d) =>
d.should_be_operated_by__release == null ||
d.should_be_operated_by__release.__id < osRelease.id,
)
.map((d) => d.id);

if (affectedDeviceIds.length === 0) {
return;
}

await rootApi.patch({
resource: 'device',
options: {
Expand Down
103 changes: 103 additions & 0 deletions test/15_target-hostapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,109 @@ export default () => {
.expect(200);
expect(dev.d[0].should_be_operated_by__release).to.be.null;
});

it('should overwrite existing should_be_operated_by__release when device reports OS info if should_be_operated_by__release is null', async () => {
// First set up a device with a specific target release
const device = await fakeDevice.provisionDevice(admin, applicationId);
await supertest(admin)
.patch(`/${version}/device(${device.id})`)
.send({
should_be_operated_by__release: null,
})
.expect(200);

// Verify initial state
await expectResourceToMatch(pineUser, 'device', device.id, {
should_be_operated_by__release: null,
});

// Now patch the device with OS info
await device.patchStateV2({
local: {
os_version: 'balenaOS 2.50.0+rev1',
os_variant: 'prod',
},
});

// Verify the should_be_operated_by__release was updated with OS info
await expectResourceToMatch(pineUser, 'device', device.id, {
should_be_operated_by__release: {
__id: nuc2_50_0_rev1prodId,
},
os_version: 'balenaOS 2.50.0+rev1',
os_variant: 'prod',
});
});

it('should not overwrite existing should_be_operated_by__release when device reports OS info if should_be_operated_by__release is newer', async () => {
// First set up a device with a specific target release
const device = await fakeDevice.provisionDevice(admin, applicationId);
await supertest(admin)
.patch(`/${version}/device(${device.id})`)
.send({
should_be_operated_by__release: nuc2_51_0_rev1prodTagAndSemverId,
})
.expect(200);

// Verify initial state
await expectResourceToMatch(pineUser, 'device', device.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 & older release
await device.patchStateV2({
local: {
os_version: 'balenaOS 2.50.0+rev1',
os_variant: 'prod',
},
});

// Verify the should_be_operated_by__release was not changed
await expectResourceToMatch(pineUser, 'device', device.id, {
should_be_operated_by__release: {
__id: nuc2_51_0_rev1prodTagAndSemverId,
},
os_version: 'balenaOS 2.50.0+rev1',
os_variant: 'prod',
});
});

it('should overwrite existing should_be_operated_by__release when device reports OS info if should_be_operated_by__release is older', async () => {
// First set up a device with a specific target release
const device = await fakeDevice.provisionDevice(admin, applicationId);
await supertest(admin)
.patch(`/${version}/device(${device.id})`)
.send({
should_be_operated_by__release: unifiedSemverOnlyHostAppReleaseId,
})
.expect(200);

// Verify initial state
await expectResourceToMatch(pineUser, 'device', device.id, {
should_be_operated_by__release: {
__id: unifiedSemverOnlyHostAppReleaseId,
},
});

// Now patch the device with OS info that would normally map to a different & newer release
await device.patchStateV2({
local: {
os_version: 'balenaOS 2.88.5+rev1',
os_variant: 'prod',
},
});

// Verify the should_be_operated_by__release was updated with newer release
await expectResourceToMatch(pineUser, 'device', device.id, {
should_be_operated_by__release: {
__id: unifiedSemverRevHostAppReleaseId,
},
os_version: 'balenaOS 2.88.5+rev1',
os_variant: 'prod',
});
});
});
});
};
Loading