mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-04-19 08:36:14 +00:00
Only uninstall 'fleet' apps when localMode is set
Local mode is still a device level config. Eventually it will become a property of an app, but for now, we don't want the supervisor trying to uninstall supervisor or host app when local mode is set
This commit is contained in:
parent
f1cd3d367c
commit
8bf8792583
@ -84,7 +84,13 @@ export async function getTargetApps(): Promise<DatabaseApp[]> {
|
||||
]);
|
||||
|
||||
const source = localMode ? 'local' : apiEndpoint;
|
||||
targetState = await db.models('app').where({ source });
|
||||
targetState = await db
|
||||
.models('app')
|
||||
.where({ source })
|
||||
// Local mode only applies for fleet "applications"
|
||||
// this prevents the supervisor trying to uninstall
|
||||
// the supervisor or host app for tri-app
|
||||
.orWhereNot({ class: 'fleet' });
|
||||
}
|
||||
return targetState!;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ describe('device-state', () => {
|
||||
// TODO: all these stubs are internal implementation details of
|
||||
// deviceState, we should refactor deviceState to use dependency
|
||||
// injection instead of initializing everything in memory
|
||||
sinon.stub(Service as any, 'extendEnvVars').callsFake((env) => {
|
||||
sinon.stub(Service as any, 'extendEnvVars').callsFake((env: any) => {
|
||||
env['ADDITIONAL_ENV_VAR'] = 'foo';
|
||||
return env;
|
||||
});
|
||||
|
@ -10,7 +10,7 @@ import LocalModeManager, {
|
||||
} from '../src/local-mode';
|
||||
import ShortStackError from './lib/errors';
|
||||
|
||||
describe.skip('LocalModeManager', () => {
|
||||
describe('LocalModeManager', () => {
|
||||
let localMode: LocalModeManager;
|
||||
let dockerStub: sinon.SinonStubbedInstance<typeof docker>;
|
||||
|
||||
|
@ -8,7 +8,6 @@ import * as dbFormat from '../src/device-state/db-format';
|
||||
import log from '../src/lib/supervisor-console';
|
||||
import { TargetApps } from '../src/types/state';
|
||||
import * as dbHelper from './lib/db-helper';
|
||||
import { withMockerode } from './lib/mockerode';
|
||||
|
||||
function getDefaultNetwork(appId: number) {
|
||||
return {
|
||||
@ -132,36 +131,32 @@ describe('db-format', () => {
|
||||
apiEndpoint,
|
||||
);
|
||||
|
||||
// getApp creates a new app instance which requires a docker instance
|
||||
// withMockerode mocks engine
|
||||
await withMockerode(async () => {
|
||||
const app = await dbFormat.getApp(1);
|
||||
expect(app).to.be.an.instanceOf(App);
|
||||
expect(app).to.have.property('appId').that.equals(1);
|
||||
expect(app).to.have.property('commit').that.equals('one');
|
||||
expect(app).to.have.property('appName').that.equals('test-app');
|
||||
expect(app).to.have.property('source').that.equals(apiEndpoint);
|
||||
expect(app).to.have.property('services').that.has.lengthOf(1);
|
||||
expect(app).to.have.property('volumes').that.deep.equals({});
|
||||
expect(app)
|
||||
.to.have.property('networks')
|
||||
.that.deep.equals(getDefaultNetwork(1));
|
||||
const app = await dbFormat.getApp(1);
|
||||
expect(app).to.be.an.instanceOf(App);
|
||||
expect(app).to.have.property('appId').that.equals(1);
|
||||
expect(app).to.have.property('commit').that.equals('one');
|
||||
expect(app).to.have.property('appName').that.equals('test-app');
|
||||
expect(app).to.have.property('source').that.equals(apiEndpoint);
|
||||
expect(app).to.have.property('services').that.has.lengthOf(1);
|
||||
expect(app).to.have.property('volumes').that.deep.equals({});
|
||||
expect(app)
|
||||
.to.have.property('networks')
|
||||
.that.deep.equals(getDefaultNetwork(1));
|
||||
|
||||
const [service] = app.services;
|
||||
expect(service).to.have.property('appId').that.equals(1);
|
||||
expect(service).to.have.property('serviceId').that.equals(1);
|
||||
expect(service).to.have.property('imageId').that.equals(1);
|
||||
expect(service).to.have.property('releaseId').that.equals(1);
|
||||
expect(service.config)
|
||||
.to.have.property('image')
|
||||
.that.equals('ubuntu:latest');
|
||||
expect(service.config)
|
||||
.to.have.property('labels')
|
||||
.that.deep.includes({ 'my-label': 'true' });
|
||||
expect(service.config)
|
||||
.to.have.property('command')
|
||||
.that.deep.equals(['sleep', 'infinity']);
|
||||
});
|
||||
const [service] = app.services;
|
||||
expect(service).to.have.property('appId').that.equals(1);
|
||||
expect(service).to.have.property('serviceId').that.equals(1);
|
||||
expect(service).to.have.property('imageId').that.equals(1);
|
||||
expect(service).to.have.property('releaseId').that.equals(1);
|
||||
expect(service.config)
|
||||
.to.have.property('image')
|
||||
.that.equals('ubuntu:latest');
|
||||
expect(service.config)
|
||||
.to.have.property('labels')
|
||||
.that.deep.includes({ 'my-label': 'true' });
|
||||
expect(service.config)
|
||||
.to.have.property('command')
|
||||
.that.deep.equals(['sleep', 'infinity']);
|
||||
});
|
||||
|
||||
it('should retrieve multiple apps from the database', async () => {
|
||||
@ -208,26 +203,133 @@ describe('db-format', () => {
|
||||
apiEndpoint,
|
||||
);
|
||||
|
||||
await withMockerode(async () => {
|
||||
const apps = Object.values(await dbFormat.getApps());
|
||||
expect(apps).to.have.lengthOf(2);
|
||||
const apps = Object.values(await dbFormat.getApps());
|
||||
expect(apps).to.have.lengthOf(2);
|
||||
|
||||
const [app, otherapp] = apps;
|
||||
expect(app).to.be.an.instanceOf(App);
|
||||
expect(app).to.have.property('appId').that.equals(1);
|
||||
expect(app).to.have.property('commit').that.equals('one');
|
||||
expect(app).to.have.property('appName').that.equals('test-app');
|
||||
expect(app).to.have.property('source').that.equals(apiEndpoint);
|
||||
expect(app).to.have.property('services').that.has.lengthOf(1);
|
||||
expect(app).to.have.property('volumes').that.deep.equals({});
|
||||
expect(app)
|
||||
.to.have.property('networks')
|
||||
.that.deep.equals(getDefaultNetwork(1));
|
||||
const [app, otherapp] = apps;
|
||||
expect(app).to.be.an.instanceOf(App);
|
||||
expect(app).to.have.property('appId').that.equals(1);
|
||||
expect(app).to.have.property('commit').that.equals('one');
|
||||
expect(app).to.have.property('appName').that.equals('test-app');
|
||||
expect(app).to.have.property('source').that.equals(apiEndpoint);
|
||||
expect(app).to.have.property('services').that.has.lengthOf(1);
|
||||
expect(app).to.have.property('volumes').that.deep.equals({});
|
||||
expect(app)
|
||||
.to.have.property('networks')
|
||||
.that.deep.equals(getDefaultNetwork(1));
|
||||
|
||||
expect(otherapp).to.have.property('appId').that.equals(2);
|
||||
expect(otherapp).to.have.property('commit').that.equals('two');
|
||||
expect(otherapp).to.have.property('appName').that.equals('other-app');
|
||||
});
|
||||
expect(otherapp).to.have.property('appId').that.equals(2);
|
||||
expect(otherapp).to.have.property('commit').that.equals('two');
|
||||
expect(otherapp).to.have.property('appName').that.equals('other-app');
|
||||
});
|
||||
|
||||
it('should retrieve non-fleet apps from the database if local mode is set', async () => {
|
||||
await dbFormat.setApps(
|
||||
{
|
||||
deadbeef: {
|
||||
id: 1,
|
||||
name: 'test-app',
|
||||
class: 'fleet',
|
||||
releases: {
|
||||
one: {
|
||||
id: 1,
|
||||
services: {
|
||||
ubuntu: {
|
||||
id: 1,
|
||||
image_id: 1,
|
||||
image: 'ubuntu:latest',
|
||||
environment: {},
|
||||
labels: {},
|
||||
composition: {
|
||||
command: ['sleep', 'infinity'],
|
||||
},
|
||||
},
|
||||
},
|
||||
volumes: {},
|
||||
networks: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
deadc0de: {
|
||||
id: 2,
|
||||
name: 'other-app',
|
||||
class: 'app',
|
||||
releases: {
|
||||
two: {
|
||||
id: 2,
|
||||
services: {},
|
||||
volumes: {},
|
||||
networks: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apiEndpoint,
|
||||
);
|
||||
|
||||
// Once local mode is set to true, only 'other-app' should be returned
|
||||
// as part of the target
|
||||
await config.set({ localMode: true });
|
||||
|
||||
const apps = Object.values(await dbFormat.getApps());
|
||||
expect(apps).to.have.lengthOf(1);
|
||||
|
||||
const [app] = apps;
|
||||
expect(app).to.be.an.instanceOf(App);
|
||||
expect(app).to.have.property('appId').that.equals(2);
|
||||
expect(app).to.have.property('commit').that.equals('two');
|
||||
expect(app).to.have.property('appName').that.equals('other-app');
|
||||
|
||||
// Set the app as local now
|
||||
await dbFormat.setApps(
|
||||
{
|
||||
deadbeef: {
|
||||
id: 1,
|
||||
name: 'test-app',
|
||||
class: 'fleet',
|
||||
releases: {
|
||||
one: {
|
||||
id: 1,
|
||||
services: {
|
||||
ubuntu: {
|
||||
id: 1,
|
||||
image_id: 1,
|
||||
image: 'ubuntu:latest',
|
||||
environment: {},
|
||||
labels: {},
|
||||
composition: {
|
||||
command: ['sleep', 'infinity'],
|
||||
},
|
||||
},
|
||||
},
|
||||
volumes: {},
|
||||
networks: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
'local',
|
||||
);
|
||||
|
||||
// Now both apps should be returned
|
||||
const newapps = Object.values(await dbFormat.getApps());
|
||||
expect(newapps).to.have.lengthOf(2);
|
||||
|
||||
const [newapp, otherapp] = newapps;
|
||||
expect(newapp).to.be.an.instanceOf(App);
|
||||
expect(newapp).to.have.property('appId').that.equals(1);
|
||||
expect(newapp).to.have.property('commit').that.equals('one');
|
||||
expect(newapp).to.have.property('appName').that.equals('test-app');
|
||||
expect(newapp).to.have.property('source').that.equals('local');
|
||||
expect(newapp).to.have.property('services').that.has.lengthOf(1);
|
||||
expect(newapp).to.have.property('volumes').that.deep.equals({});
|
||||
expect(newapp)
|
||||
.to.have.property('networks')
|
||||
.that.deep.equals(getDefaultNetwork(1));
|
||||
|
||||
expect(otherapp).to.have.property('appId').that.equals(2);
|
||||
expect(otherapp).to.have.property('commit').that.equals('two');
|
||||
expect(otherapp).to.have.property('appName').that.equals('other-app');
|
||||
});
|
||||
|
||||
it('should retrieve app target state from database', async () => {
|
||||
@ -272,16 +374,11 @@ describe('db-format', () => {
|
||||
};
|
||||
|
||||
await dbFormat.setApps(srcApps, apiEndpoint);
|
||||
|
||||
// getApp creates a new app instance which requires a docker instance
|
||||
// withMockerode mocks engine
|
||||
await withMockerode(async () => {
|
||||
const result = await dbFormat.getTargetJson();
|
||||
expect(
|
||||
isRight(TargetApps.decode(result)),
|
||||
'resulting target apps is a valid TargetApps object',
|
||||
);
|
||||
expect(result).to.deep.equal(srcApps);
|
||||
});
|
||||
const result = await dbFormat.getTargetJson();
|
||||
expect(
|
||||
isRight(TargetApps.decode(result)),
|
||||
'resulting target apps is a valid TargetApps object',
|
||||
);
|
||||
expect(result).to.deep.equal(srcApps);
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user