mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-04-16 15:28:52 +00:00
Fix network composition parsing, and correctly report compose config
Change-type: patch Signed-off-by: Cameron Diver <cameron@balena.io>
This commit is contained in:
parent
286ba58069
commit
89807c21fa
32
package-lock.json
generated
32
package-lock.json
generated
@ -1811,7 +1811,7 @@
|
||||
},
|
||||
"cacache": {
|
||||
"version": "10.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz",
|
||||
"resolved": "http://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz",
|
||||
"integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@ -2499,7 +2499,7 @@
|
||||
},
|
||||
"dbus-native": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/dbus-native/-/dbus-native-0.2.5.tgz",
|
||||
"resolved": "http://registry.npmjs.org/dbus-native/-/dbus-native-0.2.5.tgz",
|
||||
"integrity": "sha512-ocxMKCV7QdiNhzhFSeEMhj258OGtvpANSb3oWGiotmI5h1ZIse0TMPcSLiXSpqvbYvQz2Y5RsYPMNYLWhg9eBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@ -2655,7 +2655,7 @@
|
||||
"dependencies": {
|
||||
"globby": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
|
||||
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@ -3025,7 +3025,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
|
||||
"dev": true
|
||||
}
|
||||
@ -6630,9 +6630,9 @@
|
||||
}
|
||||
},
|
||||
"livepush": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/livepush/-/livepush-2.0.1.tgz",
|
||||
"integrity": "sha512-0UWr6T/AR4NpkcdStfOs1Ii3K2yBoX5Ipo25b56Xfuj/ytyNgByd+UUk2SB0uZEHj/QONwgbhmE64mE3oYFoOw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/livepush/-/livepush-2.0.2.tgz",
|
||||
"integrity": "sha512-esIy95BpYr5EUXtJhntu6lrRZEF7rhSebmbQnnSrouQAFIvIhk7USOEky2VOXs49ot9/KG5grxtWoiTyUlg8bg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.5.1",
|
||||
@ -7446,7 +7446,7 @@
|
||||
},
|
||||
"next-tick": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
|
||||
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
|
||||
"dev": true
|
||||
},
|
||||
@ -7835,7 +7835,7 @@
|
||||
},
|
||||
"os-homedir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
|
||||
},
|
||||
"os-locale": {
|
||||
@ -7885,7 +7885,7 @@
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
|
||||
},
|
||||
"osenv": {
|
||||
@ -8040,7 +8040,7 @@
|
||||
},
|
||||
"path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||
},
|
||||
"path-is-inside": {
|
||||
@ -8670,7 +8670,7 @@
|
||||
},
|
||||
"require-npm4-to-publish": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "http://registry.npmjs.org/require-npm4-to-publish/-/require-npm4-to-publish-1.0.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/require-npm4-to-publish/-/require-npm4-to-publish-1.0.0.tgz",
|
||||
"integrity": "sha1-5Z7D5ikQFT3Fu90MpA20IrLE2ec=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@ -9436,7 +9436,7 @@
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
|
||||
"resolved": "http://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
|
||||
"integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@ -9661,7 +9661,7 @@
|
||||
},
|
||||
"stream-browserify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
|
||||
"integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
@ -9757,7 +9757,7 @@
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
@ -10076,7 +10076,7 @@
|
||||
},
|
||||
"thunky": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "http://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz",
|
||||
"resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz",
|
||||
"integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=",
|
||||
"dev": true
|
||||
},
|
||||
|
@ -85,7 +85,7 @@
|
||||
"json-mask": "^0.3.8",
|
||||
"knex": "~0.15.2",
|
||||
"lint-staged": "^8.1.0",
|
||||
"livepush": "^2.0.1",
|
||||
"livepush": "^2.0.2",
|
||||
"lockfile": "^1.0.1",
|
||||
"lodash": "^4.17.5",
|
||||
"log-timestamp": "^0.1.2",
|
||||
|
@ -9,6 +9,7 @@ import { Logger } from '../logger';
|
||||
import * as ComposeUtils from './utils';
|
||||
|
||||
import {
|
||||
ComposeNetworkConfig,
|
||||
DockerIPAMConfig,
|
||||
DockerNetworkConfig,
|
||||
NetworkConfig,
|
||||
@ -93,7 +94,7 @@ export class Network {
|
||||
public static fromComposeObject(
|
||||
name: string,
|
||||
appId: number,
|
||||
network: NetworkConfig,
|
||||
network: Partial<ComposeNetworkConfig>,
|
||||
opts: NetworkOptions,
|
||||
): Network {
|
||||
const net = new Network(opts);
|
||||
@ -102,25 +103,45 @@ export class Network {
|
||||
|
||||
Network.validateComposeConfig(network);
|
||||
|
||||
// Assign the default values for a network inspect,
|
||||
// so when we come to compare, it will match
|
||||
net.config = _.defaultsDeep(network, {
|
||||
driver: 'bridge',
|
||||
ipam: {
|
||||
driver: 'default',
|
||||
config: [],
|
||||
options: {},
|
||||
},
|
||||
enableIPv6: false,
|
||||
internal: false,
|
||||
labels: {},
|
||||
options: {},
|
||||
});
|
||||
const ipam =
|
||||
network.ipam != null
|
||||
? network.ipam
|
||||
: {
|
||||
driver: 'default',
|
||||
config: [],
|
||||
options: {},
|
||||
};
|
||||
if (ipam.config == null) {
|
||||
ipam.config = [];
|
||||
}
|
||||
if (ipam.options == null) {
|
||||
ipam.options = {};
|
||||
}
|
||||
net.config = {
|
||||
driver: network.driver || 'bridge',
|
||||
ipam,
|
||||
enableIPv6: network.enable_ipv6 || false,
|
||||
internal: network.internal || false,
|
||||
labels: network.labels || {},
|
||||
options: network.driver_opts || {},
|
||||
};
|
||||
|
||||
net.config.labels = ComposeUtils.normalizeLabels(net.config.labels);
|
||||
|
||||
return net;
|
||||
}
|
||||
|
||||
public toComposeObject(): ComposeNetworkConfig {
|
||||
return {
|
||||
driver: this.config.driver,
|
||||
driver_opts: this.config.options,
|
||||
enable_ipv6: this.config.enableIPv6,
|
||||
internal: this.config.internal,
|
||||
ipam: this.config.ipam,
|
||||
labels: this.config.labels,
|
||||
};
|
||||
}
|
||||
|
||||
public async create(): Promise<void> {
|
||||
this.logger.logSystemEvent(logTypes.createNetwork, {
|
||||
network: { name: this.name },
|
||||
@ -197,7 +218,9 @@ export class Network {
|
||||
return _.isEqual(configToCompare, network.config);
|
||||
}
|
||||
|
||||
private static validateComposeConfig(config: NetworkConfig): void {
|
||||
private static validateComposeConfig(
|
||||
config: Partial<ComposeNetworkConfig>,
|
||||
): void {
|
||||
// Check if every ipam config entry has both a subnet and a gateway
|
||||
_.each(_.get(config, 'config.ipam.config', []), ({ subnet, gateway }) => {
|
||||
if (subnet == null || gateway == null) {
|
||||
|
@ -542,6 +542,13 @@ export class Service {
|
||||
return svc;
|
||||
}
|
||||
|
||||
public toComposeObject(): ServiceConfig {
|
||||
// This isn't techinically correct as we do some changes
|
||||
// to the configuration which we cannot reverse. We also
|
||||
// represent the ports as a class, which isn't ideal
|
||||
return this.config;
|
||||
}
|
||||
|
||||
public toDockerContainer(opts: {
|
||||
deviceName: string;
|
||||
}): Dockerode.ContainerCreateOptions {
|
||||
|
@ -34,6 +34,25 @@ export interface NetworkInspect {
|
||||
Labels: { [labelName: string]: string };
|
||||
}
|
||||
|
||||
export interface ComposeNetworkConfig {
|
||||
driver: string;
|
||||
driver_opts: Dictionary<string>;
|
||||
ipam: {
|
||||
driver: string;
|
||||
config: Array<
|
||||
Partial<{
|
||||
subnet: string;
|
||||
ip_range: string;
|
||||
gateway: string;
|
||||
aux_addresses: Dictionary<string>;
|
||||
}>
|
||||
>;
|
||||
options: Dictionary<string>;
|
||||
};
|
||||
enable_ipv6: boolean;
|
||||
internal: boolean;
|
||||
labels: Dictionary<string>;
|
||||
}
|
||||
export interface NetworkConfig {
|
||||
driver: string;
|
||||
ipam: {
|
||||
|
@ -19,6 +19,11 @@ export interface VolumeConfig {
|
||||
driverOpts: Docker.VolumeInspectInfo['Options'];
|
||||
}
|
||||
|
||||
export interface ComposeVolumeConfig {
|
||||
driver_opts: Dictionary<string>;
|
||||
labels: LabelObject;
|
||||
}
|
||||
|
||||
export class Volume {
|
||||
public appId: number;
|
||||
public name: string;
|
||||
@ -60,11 +65,11 @@ export class Volume {
|
||||
public static fromComposeObject(
|
||||
name: string,
|
||||
appId: number,
|
||||
config: Partial<VolumeConfig>,
|
||||
config: Partial<ComposeVolumeConfig>,
|
||||
opts: VolumeConstructOpts,
|
||||
) {
|
||||
const filledConfig: VolumeConfig = {
|
||||
driverOpts: config.driverOpts || {},
|
||||
driverOpts: config.driver_opts || {},
|
||||
labels: ComposeUtils.normalizeLabels(config.labels || {}),
|
||||
};
|
||||
|
||||
@ -75,6 +80,13 @@ export class Volume {
|
||||
return new Volume(name, appId, filledConfig, opts);
|
||||
}
|
||||
|
||||
public toComposeObject(): ComposeVolumeConfig {
|
||||
return {
|
||||
driver_opts: this.config.driverOpts!,
|
||||
labels: this.config.labels,
|
||||
};
|
||||
}
|
||||
|
||||
public isEqualConfig(volume: Volume): boolean {
|
||||
return (
|
||||
isEqual(this.config.driverOpts, volume.config.driverOpts) &&
|
||||
|
@ -244,9 +244,26 @@ export function createV2Api(router: Router, applications: ApplicationManager) {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: This should really return the config as it
|
||||
// is returned from the api, but currently that's not
|
||||
// the easiest thing due to the way their stored and
|
||||
// retrieved from the db - when all of the application
|
||||
// manager is strongly typed, revisit this. The best
|
||||
// thing to do would be to represent the input with
|
||||
// io-ts and make sure the below conforms to it
|
||||
const target = _.cloneDeep(await deviceState.getTarget());
|
||||
if (target.local != null && !_.isEmpty(target.local.apps)) {
|
||||
target.local.apps = _.mapValues(target.local.apps, app => {
|
||||
app.services = _.map(app.services, s => s.toComposeObject());
|
||||
app.volumes = _.mapValues(app.volumes, v => v.toComposeObject());
|
||||
app.networks = _.mapValues(app.networks, n => n.toComposeObject());
|
||||
return app;
|
||||
});
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
status: 'success',
|
||||
state: await deviceState.getTarget(),
|
||||
state: target,
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(503).send({
|
||||
@ -259,8 +276,6 @@ export function createV2Api(router: Router, applications: ApplicationManager) {
|
||||
router.post('/v2/local/target-state', async (req, res) => {
|
||||
// let's first ensure that we're in local mode, otherwise
|
||||
// this function should not do anything
|
||||
// TODO: We really should refactor the config module to provide bools
|
||||
// as bools etc
|
||||
try {
|
||||
const localMode = await deviceState.config.get('localMode');
|
||||
if (!localMode) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user