mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-02-22 10:21:01 +00:00
Merge pull request #1498 from balena-io/1476-patch-update-needed
Fixed evaluating if updates are needed to reach target state
This commit is contained in:
commit
ae1d7185c8
@ -307,46 +307,78 @@ export class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const alreadyStarted = (serviceId: number) => {
|
/**
|
||||||
const equalExceptForRunning = currentByServiceId[
|
* Checks that the config for the current and target services matches, ignoring their run state.
|
||||||
serviceId
|
* @param serviceCurrent
|
||||||
].isEqualExceptForRunningState(
|
* @param serviceTarget
|
||||||
targetByServiceId[serviceId],
|
*/
|
||||||
containerIds,
|
const isEqualExceptForRunningState = (
|
||||||
);
|
serviceCurrent: Service,
|
||||||
if (!equalExceptForRunning) {
|
serviceTarget: Service,
|
||||||
// We need to recreate the container, as the configuration has changed
|
) =>
|
||||||
|
serviceCurrent.isEqualExceptForRunningState(serviceTarget, containerIds);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a service is running, if we tracked it as being started, if the config matches the desired config, and if we actually want it to ever be started.
|
||||||
|
* @param serviceCurrent
|
||||||
|
* @param serviceTarget
|
||||||
|
*/
|
||||||
|
const shouldBeStarted = (
|
||||||
|
serviceCurrent: Service,
|
||||||
|
serviceTarget: Service,
|
||||||
|
) => {
|
||||||
|
// If the target run state is stopped, or we are actually running, then we don't care about anything else
|
||||||
|
if (
|
||||||
|
serviceTarget.config.running === false ||
|
||||||
|
serviceCurrent.config.running === true
|
||||||
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetByServiceId[serviceId].config.running) {
|
// Check if we previously remember starting it
|
||||||
// If the container is already running, and we don't need to change it
|
if (
|
||||||
// due to the config, we know it's already been started
|
applicationManager.containerStarted[serviceCurrent.containerId!] != null
|
||||||
return true;
|
) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We recently ran a start step for this container, it just hasn't
|
// If the config otherwise matches, then we should be running
|
||||||
// started running yet
|
return isEqualExceptForRunningState(serviceCurrent, serviceTarget);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a service should be stopped and if we have tracked it as being stopped.
|
||||||
|
*
|
||||||
|
* @param serviceCurrent
|
||||||
|
* @param serviceTarget
|
||||||
|
*/
|
||||||
|
const shouldBeStopped = (
|
||||||
|
serviceCurrent: Service,
|
||||||
|
serviceTarget: Service,
|
||||||
|
) => {
|
||||||
|
// check that we want to stop it, and that it isn't stopped
|
||||||
return (
|
return (
|
||||||
applicationManager.containerStarted[
|
serviceTarget.config.running === false &&
|
||||||
currentByServiceId[serviceId].containerId!
|
// When we issue a stop step, we remove the containerId from this structure.
|
||||||
] != null
|
// We check if the container has been removed first, so that we can ensure we're not providing multiple stop steps.
|
||||||
|
applicationManager.containerStarted[serviceCurrent.containerId!] == null
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const needUpdate = maybeUpdate.filter(
|
/**
|
||||||
(serviceId) =>
|
* Filter all the services which should be updated due to run state change, or config mismatch.
|
||||||
!(
|
*/
|
||||||
currentByServiceId[serviceId].isEqual(
|
const toBeUpdated = maybeUpdate
|
||||||
targetByServiceId[serviceId],
|
.map((serviceId) => ({
|
||||||
containerIds,
|
current: currentByServiceId[serviceId],
|
||||||
) && alreadyStarted(serviceId)
|
target: targetByServiceId[serviceId],
|
||||||
),
|
}))
|
||||||
);
|
.filter(
|
||||||
const toBeUpdated = needUpdate.map((serviceId) => ({
|
({ current: c, target: t }) =>
|
||||||
current: currentByServiceId[serviceId],
|
!isEqualExceptForRunningState(c, t) ||
|
||||||
target: targetByServiceId[serviceId],
|
shouldBeStarted(c, t) ||
|
||||||
}));
|
shouldBeStopped(c, t),
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
installPairs: toBeInstalled,
|
installPairs: toBeInstalled,
|
||||||
|
@ -583,6 +583,49 @@ describe('compose/app', () => {
|
|||||||
expectStep('stop', steps);
|
expectStep('stop', steps);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not try to start a container which has exitted and has restart policy of no', async () => {
|
||||||
|
// Container is a "run once" type of service so it has exitted.
|
||||||
|
const current = createApp(
|
||||||
|
[
|
||||||
|
await createService(
|
||||||
|
{ restart: 'no', running: false },
|
||||||
|
1,
|
||||||
|
'main',
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
{ containerId: 'run_once' },
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mark this container as previously being started
|
||||||
|
applicationManager.containerStarted['run_once'] = true;
|
||||||
|
|
||||||
|
// Now test that another start step is not added on this service
|
||||||
|
const target = createApp(
|
||||||
|
[
|
||||||
|
await createService(
|
||||||
|
{ restart: 'no', running: true },
|
||||||
|
1,
|
||||||
|
'main',
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
{ containerId: 'run_once' },
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
const steps = current.nextStepsForAppUpdate(defaultContext, target);
|
||||||
|
withSteps(steps).rejectStep('start');
|
||||||
|
});
|
||||||
|
|
||||||
it('should recreate a container if the target configuration changes', async () => {
|
it('should recreate a container if the target configuration changes', async () => {
|
||||||
const contextWithImages = {
|
const contextWithImages = {
|
||||||
...defaultContext,
|
...defaultContext,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user