Reference networks by Id instead of by name

We have seen a few times devices with duplicated network names for some
reason. While we don't know the cause the networks get duplicates,
this is disruptive of updates, as the supervisor usually queries
resource by name, resulting in a 400 error from the engine because of
the ambiguity.

This replaces those queries by name to queries by id. This includes
network removal. If a `removeNetwork` step is generated, the supervisor
opts to remove all instances of the network with the same name as it
cannot easily resolve the ambiguity.

This doesn't solve the problem of ambiguous networks, because even if
networks are referenced by id when creating a container, the engine will
throw an error (see https://github.com/balena-os/balena-supervisor/issues/590#issuecomment-1423557871)

Change-type: patch
Relates-to: #590
This commit is contained in:
Felipe Lalanne 2023-02-10 14:13:12 -03:00 committed by Felipe Lalanne
parent e7aaae9db9
commit 180c4ff31a
2 changed files with 14 additions and 8 deletions

View File

@ -11,10 +11,10 @@ import * as logger from '../logger';
import { Network } from './network';
import { ResourceRecreationAttemptError } from './errors';
export function getAll(): Bluebird<Network[]> {
return getWithBothLabels().map((network: { Name: string }) => {
export async function getAll(): Promise<Network[]> {
return getWithBothLabels().map(async (network: { Id: string }) => {
return docker
.getNetwork(network.Name)
.getNetwork(network.Id)
.inspect()
.then((net) => {
return Network.fromDockerNetwork(net);

View File

@ -205,8 +205,12 @@ export class Network {
network: { name: this.name, appUuid: this.appUuid },
});
// Find the network
const [networkName] = (await docker.listNetworks())
// Find the networks with the same name. While theoretically
// the network name is unique, because moby is not great with concurrency
// it's possible to have multiple networks with the same name
// https://github.com/moby/moby/issues/20648
// For this reason we need to delete them all
const networkIds = (await docker.listNetworks())
.filter((network) => {
try {
const { appId, appUuid, name } = Network.deconstructDockerName(
@ -220,14 +224,16 @@ export class Network {
return false;
}
})
.map((network) => network.Name);
.map((network) => network.Id);
if (!networkName) {
if (networkIds.length === 0) {
return;
}
try {
await docker.getNetwork(networkName).remove();
await Promise.all(
networkIds.map((networkId) => docker.getNetwork(networkId).remove()),
);
} catch (error) {
logger.logSystemEvent(logTypes.removeNetworkError, {
network: { name: this.name, appUuid: this.appUuid },