From 0dd6ee317535dcd726aed1c0edd9a8c0c8af978e Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Mon, 29 Mar 2021 10:31:02 -0400 Subject: [PATCH 01/18] support static ip --- lib/backends/sdc/networks.js | 69 ++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index 74ec05a2..c252c664 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -29,6 +29,8 @@ var ADMIN_NIC_TAG = 'admin'; // Label name used to set the external (public) network for a container. var TRITON_PUBLIC_NETWORK_LABEL = 'triton.network.public'; +var TRITON_PUBLIC_NETWORK_IPV4_LABEL = 'triton.network.public_ipv4'; + var _napiClientCache; // set in `getNapiClient` @@ -623,6 +625,8 @@ function externalNetworkByName(opts, container, payload, callback) { assert.func(callback, 'callback'); var externalNetworkName; + var externalNetworkIP; + var labels = container.Labels || {}; var log = opts.log; @@ -632,6 +636,12 @@ function externalNetworkByName(opts, container, payload, callback) { externalNetworkName = labels[TRITON_PUBLIC_NETWORK_LABEL]; } + if (Object.prototype.hasOwnProperty.call(labels, + TRITON_PUBLIC_NETWORK_IPV4_LABEL)) + { + externalNetworkIP = labels[TRITON_PUBLIC_NETWORK_IPV4_LABEL]; + } + if (!payload.hasOwnProperty('networks')) { payload.networks = []; } else { @@ -698,7 +708,12 @@ function externalNetworkByName(opts, container, payload, callback) { return; } - payload.networks.push({uuid: networks[0].uuid, primary: true}); + var network = {ipv4_uuid: networks[0].uuid, primary: true}; + if (externalNetworkIP) { + network.ipv4_ips = [ externalNetworkIP ]; + } + + payload.networks.push(network); callback(); return; @@ -774,7 +789,13 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { next(findErr); return; } - payload.networks = [ {uuid: network.uuid, primary: true} ]; + // payload.networks = [ {uuid: network.uuid, primary: true} ]; + payload.networks = [ {ipv4_uuid: network.uuid, primary: true} ]; + var ipv4Addr = container.NetworkingConfig.EndpointsConfig[networkMode].IPAMConfig.IPv4Address; + if (ipv4Addr) { + payload.networks[0].ipv4_ips = [ ipv4Addr ]; + } + next(); }); } @@ -800,6 +821,50 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { externalNetworkByName(opts, container, payload, next); }, + /* + * We need to verify that if a user passed in networks with IPs that none + * of the IPs are considered "managed". NAPI will handle other validations + * for us. + */ + function verifyNetworkIPs(_, next) { + var pipeline = []; + var napi = getNapiClient(opts.config.napi); + var networksWithIps = []; + payload.networks.forEach(function forEachNetwork(net) { + // Today we only support passing in ipv4 addrs, + // but this should be extended to support ipv6 addrs + if (net.ipv4_ips && net.ipv4_ips.length > 0) { + networksWithIps.push(net); + } + }); + + vasync.forEachPipeline({ + 'func': function validateIp(network, done) { + napi.getIP(network.ipv4_uuid, network.ipv4_ips[0], + function napiGetIp(err, ip) { + if (err) { + done(err); + return; + } + if (ip.belongs_to_type === 'other' || + ip.owner_uuid === opts.config.adminUuid) { + done(new errors.InternalError('Cannot use Managed IP')); + return; + } + done(null, ip); + }); + }, + 'inputs': networksWithIps + }, function (err) { + if (err) { + next(err); + return; + } + next() + return + }); + }, + function runModifyProvisionNetworksPlugins(_, next) { opts.app.plugins.modifyProvisionNetworks({ account: opts.account, From 353e1971011b4c4f1e0c5099ca66f1ea4ca719f7 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Tue, 30 Mar 2021 11:21:10 -0400 Subject: [PATCH 02/18] IPAM Config only exists when IP is given --- lib/backends/sdc/networks.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index c252c664..84c3947d 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -789,11 +789,12 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { next(findErr); return; } - // payload.networks = [ {uuid: network.uuid, primary: true} ]; payload.networks = [ {ipv4_uuid: network.uuid, primary: true} ]; - var ipv4Addr = container.NetworkingConfig.EndpointsConfig[networkMode].IPAMConfig.IPv4Address; - if (ipv4Addr) { - payload.networks[0].ipv4_ips = [ ipv4Addr ]; + if (container.NetworkingConfig.EndpointsConfig[networkMode] != undefined) { + var ipv4Addr = container.NetworkingConfig.EndpointsConfig[networkMode].IPAMConfig.IPv4Address; + if (ipv4Addr) { + payload.networks[0].ipv4_ips = [ ipv4Addr ]; + } } next(); From 73bed195c81138c2177071905ac4fb01d0d4fa03 Mon Sep 17 00:00:00 2001 From: teutat3s <10206665+teutat3s@users.noreply.github.com> Date: Tue, 16 Nov 2021 13:03:03 +0100 Subject: [PATCH 03/18] Fix make check --- lib/backends/sdc/networks.js | 72 +++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index 84c3947d..e5ef7168 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2017, Joyent, Inc. + * Copyright 2021 Joyent, Inc. */ /* @@ -789,11 +789,16 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { next(findErr); return; } - payload.networks = [ {ipv4_uuid: network.uuid, primary: true} ]; - if (container.NetworkingConfig.EndpointsConfig[networkMode] != undefined) { - var ipv4Addr = container.NetworkingConfig.EndpointsConfig[networkMode].IPAMConfig.IPv4Address; + payload.networks = + [ {ipv4_uuid: network.uuid, primary: true} ]; + if (container.NetworkingConfig.EndpointsConfig[networkMode] + != undefined) { + var ipv4Addr = + container.NetworkingConfig. + EndpointsConfig[networkMode].IPAMConfig. + IPv4Address; if (ipv4Addr) { - payload.networks[0].ipv4_ips = [ ipv4Addr ]; + payload.networks[0].ipv4_ips = [ ipv4Addr ]; } } @@ -824,11 +829,10 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { /* * We need to verify that if a user passed in networks with IPs that none - * of the IPs are considered "managed". NAPI will handle other validations - * for us. + * of the IPs are considered "managed". NAPI will handle other + * validations for us. */ function verifyNetworkIPs(_, next) { - var pipeline = []; var napi = getNapiClient(opts.config.napi); var networksWithIps = []; payload.networks.forEach(function forEachNetwork(net) { @@ -839,31 +843,33 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { } }); - vasync.forEachPipeline({ - 'func': function validateIp(network, done) { - napi.getIP(network.ipv4_uuid, network.ipv4_ips[0], - function napiGetIp(err, ip) { - if (err) { - done(err); - return; - } - if (ip.belongs_to_type === 'other' || - ip.owner_uuid === opts.config.adminUuid) { - done(new errors.InternalError('Cannot use Managed IP')); - return; - } - done(null, ip); - }); - }, - 'inputs': networksWithIps - }, function (err) { - if (err) { - next(err); - return; - } - next() - return - }); + vasync.forEachPipeline({ + 'func': function validateIp(network, done) { + napi.getIP(network.ipv4_uuid, network.ipv4_ips[0], + function napiGetIp(err, ip) + { + if (err) { + done(err); + return; + } + if (ip.belongs_to_type === 'other' + || ip.owner_uuid === opts.config.adminUuid) { + done(new errors.InternalError( + 'Cannot use Managed IP')); + return; + } + done(null, ip); + }); + }, + 'inputs': networksWithIps + }, function (err) { + if (err) { + next(err); + return; + } + next(); + return; + }); }, function runModifyProvisionNetworksPlugins(_, next) { From 5a0a6eb1ab9674136a1959d23599d67b39ac81ac Mon Sep 17 00:00:00 2001 From: teutat3s <10206665+teutat3s@users.noreply.github.com> Date: Tue, 14 Dec 2021 18:48:12 +0100 Subject: [PATCH 04/18] Use changes from joyent/node-triton-tags#5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1bc49e3e..44cbeeda 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "strsplit": "1.0.0", "tape": "^4.4.0", "trace-event": "1.2.0", - "triton-tags": "1.4.0", + "triton-tags": "git+https://github.com/Smithx10/node-triton-tags#ed3272116c846473c3fceee4c630dde1f40589f5", "ufds": "1.2.0", "vasync": "2.1.0", "verror": "1.9.0", From f1ee7ad8dc063162aa8ceb0013a9f23246020bac Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Tue, 12 Aug 2025 19:29:45 -0400 Subject: [PATCH 05/18] handle copy and possible null --- lib/backends/sdc/networks.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index e5ef7168..fb1c28b5 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -6,6 +6,7 @@ /* * Copyright 2021 Joyent, Inc. + * Copyright 2025 Bruce Smith */ /* @@ -791,7 +792,9 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { } payload.networks = [ {ipv4_uuid: network.uuid, primary: true} ]; - if (container.NetworkingConfig.EndpointsConfig[networkMode] + if (container.NetworkingConfig != null && + container.NetworkingConfig.EndpointsConfig != null && + container.NetworkingConfig.EndpointsConfig[networkMode] != undefined) { var ipv4Addr = container.NetworkingConfig. From 063037b70966b45e6a49344e6e8797a79bcee9a8 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Wed, 20 Aug 2025 15:19:16 -0400 Subject: [PATCH 06/18] bump tag version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2aaa1d1d..3de97f0b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "strsplit": "1.0.0", "tape": "^4.4.0", "trace-event": "1.2.0", - "triton-tags": "git+https://github.com/Smithx10/node-triton-tags#ed3272116c846473c3fceee4c630dde1f40589f5", + "triton-tags": "1.4.2", "ufds": "1.7.1", "vasync": "2.1.0", "verror": "1.9.0", @@ -44,4 +44,4 @@ "xtend": "^4.0.0" }, "license": "MPL-2.0" -} +} \ No newline at end of file From 0840a0f46cbfddfb67456ebe41aaf0c1afa51eef Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Wed, 20 Aug 2025 15:25:22 -0400 Subject: [PATCH 07/18] bump tag version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3de97f0b..6fd67650 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "strsplit": "1.0.0", "tape": "^4.4.0", "trace-event": "1.2.0", - "triton-tags": "1.4.2", + "triton-tags": "1.5.0", "ufds": "1.7.1", "vasync": "2.1.0", "verror": "1.9.0", From 3a9f69ef91fe54ca2d237a22416aa31b53fa9612 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Tue, 26 Aug 2025 14:14:09 -0400 Subject: [PATCH 08/18] WIP: add TRITON-2497 tests, enforce network ownership for assigning addrs --- lib/backends/sdc/networks.js | 14 ++ test/integration/api-create.test.js | 343 +++++++++++++++++++++++++++- test/integration/helpers.js | 5 +- 3 files changed, 360 insertions(+), 2 deletions(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index fb1c28b5..2aa11e6a 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -710,7 +710,21 @@ function externalNetworkByName(opts, container, payload, callback) { } var network = {ipv4_uuid: networks[0].uuid, primary: true}; + // We land here if triton.network.public_ipv4 was provided. if (externalNetworkIP) { + // We can only assign IPs to networks we are the owner on. + // Some networks can have no owner allowing us to provision + // but not assign addresses on them. + if ( + networks[0].owner_uuids == null || + networks[0].owner_uuids.indexOf(opts.account.uuid) === -1 + ) { + callback(new errors.ValidationError(util.format( + '%s label requires network ownership', + TRITON_PUBLIC_NETWORK_IPV4_LABEL))); + return; + } + network.ipv4_ips = [ externalNetworkIP ]; } diff --git a/test/integration/api-create.test.js b/test/integration/api-create.test.js index 5da952d7..9df4c61f 100644 --- a/test/integration/api-create.test.js +++ b/test/integration/api-create.test.js @@ -875,7 +875,6 @@ test('create with NetworkMode (docker run --net=)', function (tt) { }); }); - /* * Tests for `docker run --label triton.network.public=foo` * @@ -993,3 +992,345 @@ test('run external network (docker run --label triton.network.public=)', }); }); }); + +/* + * Tests for `docker run --label trtiton.network.public_ipv4` + * + * TRITON-2497 Add static addresses to public networks + */ + +test('run external network (docker run --label triton.network.public_ipv4=)', + function (tt) { + var externalNetworkNoOwner; + var externalNetworkOwner; + var anotherExternalNetworkOwner; + var externalNetworkWrongOwner; + // This network will have no owner. + tt.test('add external network with no owner', function (t) { + // create a new one. + var nwUuid = libuuid.create(); + var nwParams = { + name: 'sdcdockertest_apicreate_external_no_owner', + nic_tag: 'external', + subnet: '10.0.11.0/24', + provision_start_ip: '10.0.11.2', + provision_end_ip: '10.0.11.254', + uuid: nwUuid, + vlan_id: 5, + gateway: '10.0.11.1', + resolvers: ['8.8.8.8', '8.8.4.4'] + }; + h.getOrCreateExternalNetwork(NAPI, nwParams, function (err, network) { + t.ifErr(err, 'getOrCreateExternalNetwork'); + externalNetworkNoOwner = network; + t.end(); + }); + }); + + // This network will have the correct owner. + tt.test('add external network with correct alice owner', function (t) { + // create a new one. + var nwUuid = libuuid.create(); + var nwParams = { + name: 'sdcdockertest_apicreate_external_alice0', + nic_tag: 'external', + subnet: '10.0.21.0/24', + provision_start_ip: '10.0.21.2', + provision_end_ip: '10.0.21.254', + uuid: nwUuid, + vlan_id: 5, + gateway: '10.0.21.1', + resolvers: ['8.8.8.8', '8.8.4.4'], + owner_uuids: [ALICE.account.uuid] + }; + h.getOrCreateExternalNetwork(NAPI, nwParams, function (err, network) { + t.ifErr(err, 'getOrCreateExternalNetwork'); + externalNetworkOwner = network; + t.end(); + }); + }); + + // This network will have the correct owner + tt.test('add another external network with correct alice owner', function (t) { + // create a new one. + var nwUuid = libuuid.create(); + var nwParams = { + name: 'sdcdockertest_apicreate_external_alice1', + nic_tag: 'external', + subnet: '10.0.31.0/24', + provision_start_ip: '10.0.31.2', + provision_end_ip: '10.0.31.254', + uuid: nwUuid, + vlan_id: 5, + gateway: '10.0.31.1', + resolvers: ['8.8.8.8', '8.8.4.4'], + owner_uuids: [ALICE.account.uuid] + }; + h.getOrCreateExternalNetwork(NAPI, nwParams, function (err, network) { + t.ifErr(err, 'getOrCreateExternalNetwork'); + anotherExternalNetworkOwner = network; + t.end(); + }); + }); + // This network will have the incorrect owner + tt.test('add another external network with incorrect bob owner', function (t) { + // create a new one. + var nwUuid = libuuid.create(); + var nwParams = { + name: 'sdcdockertest_apicreate_external_bob0', + nic_tag: 'external', + subnet: '10.0.41.0/24', + provision_start_ip: '10.0.41.2', + provision_end_ip: '10.0.41.254', + uuid: nwUuid, + vlan_id: 5, + gateway: '10.0.41.1', + resolvers: ['8.8.8.8', '8.8.4.4'], + owner_uuids: [BOB.account.uuid] + }; + h.getOrCreateExternalNetwork(NAPI, nwParams, function (err, network) { + t.ifErr(err, 'getOrCreateExternalNetwork'); + externalNetworkWrongOwner = network; + t.end(); + }); + }); + + // Fail to privision when there is no owner + tt.test('run with assigned ipv4 address no owner', function (t) { + var expectedErr = '(Validation) triton.network.public_ipv4 label ' + + 'requires network ownership'; + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + expectedErr: expectedErr, + extra: { + 'HostConfig.PublishAllPorts': true, + Labels: { + 'triton.network.public': externalNetworkNoOwner.name, + 'triton.network.public_ipv4': '10.0.11.200' + } + }, + start: true + }, oncreate); + + function oncreate(err, result) { + // Note: Error is already checked in createDockerContainer + assert.object(err, 'err'); + t.end(); + } + }); + + // privision when there is correct owner + tt.test('run with assigned ipv4 address with correct owner', function (t) { + var assignedAddr = '10.0.21.200'; + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + extra: { + 'HostConfig.PublishAllPorts': true, + Labels: { + 'triton.network.public': externalNetworkOwner.name, + 'triton.network.public_ipv4': assignedAddr + } + }, + start: true + }, oncreate); + + function oncreate(err, result) { + assert.strictEqual(err, null); + var extNic; + var nics = result.vm.nics; + t.equal(nics.length, 2, 'two nics'); + extNic = (nics[0].nic_tag === 'external' ? nics[0] : nics[1]); + t.equal(extNic.ip, assignedAddr, 'correct external ip') + DOCKER_ALICE.del('/containers/' + result.id + '?force=1', ondelete); + } + + function ondelete(err) { + t.ifErr(err, 'delete external triton.network.public_ipv4 testing container'); + t.end(); + } + }); + + // fail to privision when there is incorrect owner + tt.test('run with assigned ipv4 address with incorrect owner', function (t) { + var assignedAddr = '10.0.41.200'; + var expectedErr = '(Error) network sdcdockertest_apicreate_external_bob0 ' + + 'not found'; + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + expectedErr: expectedErr, + extra: { + 'HostConfig.PublishAllPorts': true, + Labels: { + 'triton.network.public': externalNetworkWrongOwner.name, + 'triton.network.public_ipv4': assignedAddr + } + }, + start: true + }, oncreate); + + function oncreate(err, result) { + // Note: Error is already checked in createDockerContainer + assert.object(err, 'err'); + t.end(); + } + + }); + + // privision when there is multiple ip on same network + // with correct owner + tt.test('run with assigned ipv4 address with multiple ip ' + + 'on same network with correct owner', function (t) { + var assignedAddrLabel = '10.0.21.200'; + var assignedAddrClient = '10.0.21.201'; + var EndpointsConfig = {}; + EndpointsConfig[externalNetworkOwner.name] = { + IPAMConfig: { + IPv4Address: assignedAddrClient + } + } + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + extra: { + 'HostConfig.PublishAllPorts': true, + 'HostConfig.NetworkMode': externalNetworkOwner.name, + Labels: { + 'triton.network.public': externalNetworkOwner.name, + 'triton.network.public_ipv4': assignedAddrLabel + }, + 'NetworkingConfig.EndpointsConfig': EndpointsConfig + }, + start: true + }, oncreate); + + function oncreate(err, result) { + assert.strictEqual(err, null); + var nics = result.vm.nics; + t.equal(nics.length, 2, 'two nics'); + nics.forEach(function(nic){ + if (nic.primary) { + t.equal(nic.ip, assignedAddrLabel) + } else { + t.equal(nic.ip, assignedAddrClient) + } + }); + DOCKER_ALICE.del('/containers/' + result.id + '?force=1', ondelete); + } + + function ondelete(err) { + t.ifErr(err, 'delete external triton.network.public_ipv4 testing container'); + t.end(); + } + }); + + // privision when there is multiple ip on different networks + // with correct owner + tt.test('run with assigned ipv4 address with multiple ip ' + + 'on different networks with correct owners', function (t) { + var assignedAddrLabel = '10.0.21.200'; + var assignedAddrClient = '10.0.31.200'; + var EndpointsConfig = {}; + EndpointsConfig[anotherExternalNetworkOwner.name] = { + IPAMConfig: { + IPv4Address: assignedAddrClient + } + } + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + extra: { + 'HostConfig.PublishAllPorts': true, + 'HostConfig.NetworkMode': anotherExternalNetworkOwner.name, + Labels: { + 'triton.network.public': externalNetworkOwner.name, + 'triton.network.public_ipv4': assignedAddrLabel + }, + 'NetworkingConfig.EndpointsConfig': EndpointsConfig + }, + start: true + }, oncreate); + + function oncreate(err, result) { + assert.strictEqual(err, null); + var nics = result.vm.nics; + t.equal(nics.length, 2, 'two nics'); + nics.forEach(function(nic){ + if (nic.primary) { + t.equal(nic.ip, assignedAddrLabel) + } else { + t.equal(nic.ip, assignedAddrClient) + } + }); + DOCKER_ALICE.del('/containers/' + result.id + '?force=1', ondelete); + } + + function ondelete(err) { + t.ifErr(err, 'delete external triton.network.public_ipv4 testing container'); + t.end(); + } + }); + + // fail to privision when there is multiple ip on different networks + // with incorrect owners + tt.test('fail to run with assigned ipv4 address with multiple ip ' + + 'on different networks with incorrect owner and correct owner', function (t) { + var expectedErr = '(Error) network sdcdockertest_apicreate_external_bob0 ' + + 'not found'; + var assignedAddrLabel = '10.0.21.200'; + var assignedAddrClient = '10.0.41.200'; + var EndpointsConfig = {}; + EndpointsConfig[anotherExternalNetworkOwner.name] = { + IPAMConfig: { + IPv4Address: assignedAddrClient + } + } + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + expectedErr: expectedErr, + extra: { + 'HostConfig.PublishAllPorts': true, + 'HostConfig.NetworkMode': externalNetworkWrongOwner.name, + Labels: { + 'triton.network.public': externalNetworkOwner.name, + 'triton.network.public_ipv4': assignedAddrLabel + }, + 'NetworkingConfig.EndpointsConfig': EndpointsConfig + }, + start: true + }, oncreate); + + function oncreate(err, result) { + // Note: Error is already checked in createDockerContainer + assert.object(err, 'err'); + t.end(); + } + }); + + // These 4 networks are not cleaned up in the container creation + // so clean them all up here. + tt.test('TRITON-2497 external networks cleanup', function (t) { + var cleanupNetworks = [ + externalNetworkNoOwner, + externalNetworkOwner, + externalNetworkWrongOwner, + anotherExternalNetworkOwner + ]; + + cleanupNetworks.forEach(function(network){ + NAPI.deleteNetwork(network.uuid, function (err) { + t.ifErr(err, 'external network deletion'); + }); + }); + t.end(); + }); +}); diff --git a/test/integration/helpers.js b/test/integration/helpers.js index e19e6db1..9d95999b 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -1771,7 +1771,10 @@ function createDockerContainer(opts, callback) { 'RestartPolicy': { 'Name': '', 'MaximumRetryCount': 0 - } + }, + }, + 'NetworkingConfig': { + 'EndpointsConfig': {} } }; From 03446fd7a906aa9ab6aa41e6b50a4d1ffa7605f8 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Wed, 27 Aug 2025 00:05:08 -0400 Subject: [PATCH 09/18] handle fabric and non fabric test cases, updated docs to include public_ipv4 --- docs/api/divergence.md | 2 ++ docs/api/features/networks.md | 5 +++++ test/integration/api-create.test.js | 26 ++++++++++++++++++++++---- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/api/divergence.md b/docs/api/divergence.md index 07e08290..86d9c257 100644 --- a/docs/api/divergence.md +++ b/docs/api/divergence.md @@ -154,6 +154,8 @@ names are currently defined: Used by the CNS service. * `triton.network.public` (string): Set on a container, used to specify the external network name the instance will use. +* `triton.network.public_ipv4` (string): Set on a container, used to specify the + external network ip address the instance will use. The `com.joyent.*` namespace is reserved for Triton specific use cases, these label names are currently defined: diff --git a/docs/api/features/networks.md b/docs/api/features/networks.md index 18abcbd0..56eec5fd 100644 --- a/docs/api/features/networks.md +++ b/docs/api/features/networks.md @@ -53,6 +53,11 @@ Note that this this only overrides the default public network selection. This means that when fabric networks are enabled you will still need to specify one of `-p` or `-P` to get the public NIC. +The external network ipv4 address used by a container can be changed by setting +the `triton.network.public_ipv4` label to the desired ipv4 address that is +available in the `triton.network.public` network. The account must be set +as an owner on `triton.network.public` network. + ## Related * [`sdc-fabric vlan`](https://apidocs.tritondatacenter.com/cloudapi/#CreateFabricVLAN) and `POST /my/fabrics/default/vlans` in CloudAPI diff --git a/test/integration/api-create.test.js b/test/integration/api-create.test.js index 9df4c61f..9b39c853 100644 --- a/test/integration/api-create.test.js +++ b/test/integration/api-create.test.js @@ -1140,10 +1140,14 @@ test('run external network (docker run --label triton.network.public_ipv4=)', function oncreate(err, result) { assert.strictEqual(err, null); - var extNic; var nics = result.vm.nics; - t.equal(nics.length, 2, 'two nics'); - extNic = (nics[0].nic_tag === 'external' ? nics[0] : nics[1]); + var extNic = nics[0]; + if (FABRICS) { + extNic = (nics[0].primary === true ? nics[0] : nics[1]); + t.equal(nics.length, 2, 'one nics'); + } else { + t.equal(nics.length, 1, 'one nic'); + } t.equal(extNic.ip, assignedAddr, 'correct external ip') DOCKER_ALICE.del('/containers/' + result.id + '?force=1', ondelete); } @@ -1179,13 +1183,17 @@ test('run external network (docker run --label triton.network.public_ipv4=)', assert.object(err, 'err'); t.end(); } - }); // privision when there is multiple ip on same network // with correct owner tt.test('run with assigned ipv4 address with multiple ip ' + 'on same network with correct owner', function (t) { + if (!FABRICS) { + t.skip('sdc-docker without fabrics currently do ' + + 'not support multiple networks') + return t.end() + } var assignedAddrLabel = '10.0.21.200'; var assignedAddrClient = '10.0.21.201'; var EndpointsConfig = {}; @@ -1234,6 +1242,11 @@ test('run external network (docker run --label triton.network.public_ipv4=)', // with correct owner tt.test('run with assigned ipv4 address with multiple ip ' + 'on different networks with correct owners', function (t) { + if (!FABRICS) { + t.skip('sdc-docker without fabrics currently do ' + + 'not support multiple networks') + return t.end() + } var assignedAddrLabel = '10.0.21.200'; var assignedAddrClient = '10.0.31.200'; var EndpointsConfig = {}; @@ -1282,6 +1295,11 @@ test('run external network (docker run --label triton.network.public_ipv4=)', // with incorrect owners tt.test('fail to run with assigned ipv4 address with multiple ip ' + 'on different networks with incorrect owner and correct owner', function (t) { + if (!FABRICS) { + t.skip('sdc-docker without fabrics currently do ' + + 'not support multiple networks') + return t.end() + } var expectedErr = '(Error) network sdcdockertest_apicreate_external_bob0 ' + 'not found'; var assignedAddrLabel = '10.0.21.200'; From fce9cb5adcdfa5528f12aa54f6444f02d4923242 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Wed, 27 Aug 2025 00:09:34 -0400 Subject: [PATCH 10/18] missing the --- docs/api/features/networks.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/features/networks.md b/docs/api/features/networks.md index 56eec5fd..4ce0b799 100644 --- a/docs/api/features/networks.md +++ b/docs/api/features/networks.md @@ -55,8 +55,8 @@ of `-p` or `-P` to get the public NIC. The external network ipv4 address used by a container can be changed by setting the `triton.network.public_ipv4` label to the desired ipv4 address that is -available in the `triton.network.public` network. The account must be set -as an owner on `triton.network.public` network. +available in the `triton.network.public` network. The account must +be set as an owner on the `triton.network.public` network. ## Related From 6663538353e3d992611ec6e43a68fd4c73d31d98 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Wed, 27 Aug 2025 12:49:03 -0400 Subject: [PATCH 11/18] typo privison --- test/integration/api-create.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/integration/api-create.test.js b/test/integration/api-create.test.js index 9b39c853..2c3feb6d 100644 --- a/test/integration/api-create.test.js +++ b/test/integration/api-create.test.js @@ -1095,7 +1095,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', }); }); - // Fail to privision when there is no owner + // Fail to provision when there is no owner tt.test('run with assigned ipv4 address no owner', function (t) { var expectedErr = '(Validation) triton.network.public_ipv4 label ' + 'requires network ownership'; @@ -1121,7 +1121,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } }); - // privision when there is correct owner + // provision when there is correct owner tt.test('run with assigned ipv4 address with correct owner', function (t) { var assignedAddr = '10.0.21.200'; h.createDockerContainer({ @@ -1158,7 +1158,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } }); - // fail to privision when there is incorrect owner + // fail to provision when there is incorrect owner tt.test('run with assigned ipv4 address with incorrect owner', function (t) { var assignedAddr = '10.0.41.200'; var expectedErr = '(Error) network sdcdockertest_apicreate_external_bob0 ' @@ -1185,7 +1185,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } }); - // privision when there is multiple ip on same network + // provision when there is multiple ip on same network // with correct owner tt.test('run with assigned ipv4 address with multiple ip ' + 'on same network with correct owner', function (t) { @@ -1238,7 +1238,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } }); - // privision when there is multiple ip on different networks + // provision when there is multiple ip on different networks // with correct owner tt.test('run with assigned ipv4 address with multiple ip ' + 'on different networks with correct owners', function (t) { @@ -1291,7 +1291,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } }); - // fail to privision when there is multiple ip on different networks + // fail to provision when there is multiple ip on different networks // with incorrect owners tt.test('fail to run with assigned ipv4 address with multiple ip ' + 'on different networks with incorrect owner and correct owner', function (t) { From 60d82c2ca21f3bf79be18a273f411922cbbd7299 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Wed, 27 Aug 2025 12:49:41 -0400 Subject: [PATCH 12/18] typo plural --- test/integration/api-create.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/api-create.test.js b/test/integration/api-create.test.js index 2c3feb6d..74c9231a 100644 --- a/test/integration/api-create.test.js +++ b/test/integration/api-create.test.js @@ -1144,7 +1144,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', var extNic = nics[0]; if (FABRICS) { extNic = (nics[0].primary === true ? nics[0] : nics[1]); - t.equal(nics.length, 2, 'one nics'); + t.equal(nics.length, 2, 'two nics'); } else { t.equal(nics.length, 1, 'one nic'); } From be3a525b602bf8c8a4fe6552c9e34c63bb61a168 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Tue, 2 Sep 2025 12:24:12 -0400 Subject: [PATCH 13/18] add tests / pass tests for fabrics and no fabrics --- lib/backends/sdc/networks.js | 70 ++++++-- test/integration/api-create.test.js | 243 ++++++++++++++++++---------- 2 files changed, 210 insertions(+), 103 deletions(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index 2aa11e6a..cd0debbf 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -716,8 +716,8 @@ function externalNetworkByName(opts, container, payload, callback) { // Some networks can have no owner allowing us to provision // but not assign addresses on them. if ( - networks[0].owner_uuids == null || - networks[0].owner_uuids.indexOf(opts.account.uuid) === -1 + networks[0].owner_uuids == null + || networks[0].owner_uuids.indexOf(opts.account.uuid) === -1 ) { callback(new errors.ValidationError(util.format( '%s label requires network ownership', @@ -782,13 +782,13 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { vasync.pipeline({ funcs: [ function addFabricNetworks(_, next) { - if (!opts.config.overlay.enabled) { - next(); - return; - } networkMode = container.HostConfig.NetworkMode; - if (!networkMode || networkMode === 'bridge' - || networkMode === 'default') { + var overlayEnabled = opts.config.overlay.enabled + var defaultNetworkMode = !networkMode || networkMode === 'bridge' + || networkMode === 'default' + + // Handle Fabrics + if (overlayEnabled && defaultNetworkMode) { getDefaultFabricNetwork(opts, function onGetDefaultFabricNet(getDefaultFabricNetErr, defaultFabricNet) { @@ -796,9 +796,10 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { [ {uuid: defaultFabricNet, primary: true} ]; next(getDefaultFabricNetErr); }); - } else { - findNetworkOrPoolByNameOrId(networkMode, opts, - function (findErr, network) + // Handle Non Fabrics + } else if (!defaultNetworkMode) { + findNetworkOrPoolByNameOrId(networkMode, opts, + function (findErr, network) { if (findErr) { next(findErr); @@ -806,10 +807,11 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { } payload.networks = [ {ipv4_uuid: network.uuid, primary: true} ]; - if (container.NetworkingConfig != null && - container.NetworkingConfig.EndpointsConfig != null && - container.NetworkingConfig.EndpointsConfig[networkMode] - != undefined) { + netCfg = container.NetworkingConfig + if (netCfg != null + && netCfg.EndpointsConfig != null + && netCfg.EndpointsConfig[networkMode] + != undefined) { var ipv4Addr = container.NetworkingConfig. EndpointsConfig[networkMode].IPAMConfig. @@ -818,9 +820,10 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { payload.networks[0].ipv4_ips = [ ipv4Addr ]; } } - next(); }); + } else { + next(); } }, @@ -844,6 +847,41 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { externalNetworkByName(opts, container, payload, next); }, + // Enforce 2 distinct networks + function enforceDistinctNetworks(_, next) { + if (payload.networks.length === 2) { + var prevUUID; + for (var i = 0; i < payload.networks.length; i++) { + var nw = payload.networks[i]; + // Handle both network and network obj + var netUUID = nw.ipv4_uuid || nw.uuid; + if (prevUUID === netUUID) { + next(new errors.ValidationError(util.format( + 'both networks are of uuid: %s, networks must be ' + + 'distinct', + netUUID))); + return; + } + prevUUID = netUUID; + } + } + next(); + }, + + // Enforce Publishing Ports for Non Fabric with > 1 network + function enforcePublishingPorts(_, next) { + // Handle publishing ports for non fabrics + if (payload.networks.length === 2 + && !containers.publishingPorts(container)) { + next(new errors.ValidationError(util.format( + 'non fabrics with 2 networks requires a container with ' + + 'published ports' + ))); + return; + } + next(); + }, + /* * We need to verify that if a user passed in networks with IPs that none * of the IPs are considered "managed". NAPI will handle other diff --git a/test/integration/api-create.test.js b/test/integration/api-create.test.js index 74c9231a..90a7df06 100644 --- a/test/integration/api-create.test.js +++ b/test/integration/api-create.test.js @@ -6,6 +6,7 @@ /* * Copyright 2017, Joyent, Inc. + * Copyright 2025, Bruce Smith */ /* @@ -44,8 +45,6 @@ var FABRICS = false; // --- Tests - - test('setup', function (tt) { tt.test('docker env', function (t) { @@ -1051,54 +1050,58 @@ test('run external network (docker run --label triton.network.public_ipv4=)', }); // This network will have the correct owner - tt.test('add another external network with correct alice owner', function (t) { - // create a new one. - var nwUuid = libuuid.create(); - var nwParams = { - name: 'sdcdockertest_apicreate_external_alice1', - nic_tag: 'external', - subnet: '10.0.31.0/24', - provision_start_ip: '10.0.31.2', - provision_end_ip: '10.0.31.254', - uuid: nwUuid, - vlan_id: 5, - gateway: '10.0.31.1', - resolvers: ['8.8.8.8', '8.8.4.4'], - owner_uuids: [ALICE.account.uuid] - }; - h.getOrCreateExternalNetwork(NAPI, nwParams, function (err, network) { - t.ifErr(err, 'getOrCreateExternalNetwork'); - anotherExternalNetworkOwner = network; - t.end(); - }); + tt.test('add another external network with correct alice owner', + function (t) { + // create a new one. + var nwUuid = libuuid.create(); + var nwParams = { + name: 'sdcdockertest_apicreate_external_alice1', + nic_tag: 'external', + subnet: '10.0.31.0/24', + provision_start_ip: '10.0.31.2', + provision_end_ip: '10.0.31.254', + uuid: nwUuid, + vlan_id: 5, + gateway: '10.0.31.1', + resolvers: ['8.8.8.8', '8.8.4.4'], + owner_uuids: [ALICE.account.uuid] + }; + h.getOrCreateExternalNetwork(NAPI, nwParams, + function (err, network) { + t.ifErr(err, 'getOrCreateExternalNetwork'); + anotherExternalNetworkOwner = network; + t.end(); + }); }); // This network will have the incorrect owner - tt.test('add another external network with incorrect bob owner', function (t) { - // create a new one. - var nwUuid = libuuid.create(); - var nwParams = { - name: 'sdcdockertest_apicreate_external_bob0', - nic_tag: 'external', - subnet: '10.0.41.0/24', - provision_start_ip: '10.0.41.2', - provision_end_ip: '10.0.41.254', - uuid: nwUuid, - vlan_id: 5, - gateway: '10.0.41.1', - resolvers: ['8.8.8.8', '8.8.4.4'], - owner_uuids: [BOB.account.uuid] - }; - h.getOrCreateExternalNetwork(NAPI, nwParams, function (err, network) { - t.ifErr(err, 'getOrCreateExternalNetwork'); - externalNetworkWrongOwner = network; - t.end(); - }); + tt.test('add another external network with incorrect bob owner', + function (t) { + // create a new one. + var nwUuid = libuuid.create(); + var nwParams = { + name: 'sdcdockertest_apicreate_external_bob0', + nic_tag: 'external', + subnet: '10.0.41.0/24', + provision_start_ip: '10.0.41.2', + provision_end_ip: '10.0.41.254', + uuid: nwUuid, + vlan_id: 5, + gateway: '10.0.41.1', + resolvers: ['8.8.8.8', '8.8.4.4'], + owner_uuids: [BOB.account.uuid] + }; + h.getOrCreateExternalNetwork(NAPI, nwParams, + function (err, network) { + t.ifErr(err, 'getOrCreateExternalNetwork'); + externalNetworkWrongOwner = network; + t.end(); + }); }); // Fail to provision when there is no owner tt.test('run with assigned ipv4 address no owner', function (t) { var expectedErr = '(Validation) triton.network.public_ipv4 label ' - + 'requires network ownership'; + + 'requires network ownership'; h.createDockerContainer({ vmapiClient: VMAPI, dockerClient: DOCKER_ALICE, @@ -1153,16 +1156,64 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } function ondelete(err) { - t.ifErr(err, 'delete external triton.network.public_ipv4 testing container'); + t.ifErr(err, 'delete external triton.network.public_ipv4 ' + + 'testing container'); + t.end(); + } + }); + + // provision when there is correct owner publish false single network + tt.test('run with assigned ipv4 address with correct owner', function (t) { + var assignedAddr = '10.0.21.200'; + // With Non Fabrics this will deploy a single network dictated by + // the triton.network.public without exposed ports + var expectedErr = null; + // With Fabrics this is an error due to DOCKER-1045. + if (FABRICS) { + expectedErr = '(Validation) triton.network.public label requires a ' + + 'container with published ports' + } + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + expectedErr: expectedErr, + extra: { + 'HostConfig.PublishAllPorts': false, + Labels: { + 'triton.network.public': externalNetworkOwner.name, + 'triton.network.public_ipv4': assignedAddr + } + }, + start: true + }, oncreate); + + function oncreate(err, result) { + if (FABRICS) { + assert.object(err, 'err'); + t.end(); + return; + } + assert.strictEqual(err, null); + var nics = result.vm.nics; + var extNic = nics[0]; + t.equal(extNic.ip, assignedAddr, 'correct external ip') + DOCKER_ALICE.del('/containers/' + result.id + '?force=1', ondelete); + } + + function ondelete(err) { + t.ifErr(err, 'delete external triton.network.public_ipv4 ' + + 'testing container'); t.end(); } }); // fail to provision when there is incorrect owner - tt.test('run with assigned ipv4 address with incorrect owner', function (t) { + tt.test('fail to run with assigned ipv4 address with incorrect owner', + function (t) { var assignedAddr = '10.0.41.200'; - var expectedErr = '(Error) network sdcdockertest_apicreate_external_bob0 ' - + 'not found'; + var expectedErr = '(Error) network ' + + 'sdcdockertest_apicreate_external_bob0 not found'; h.createDockerContainer({ vmapiClient: VMAPI, dockerClient: DOCKER_ALICE, @@ -1185,17 +1236,14 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } }); - // provision when there is multiple ip on same network + // fail to provision when there is multiple ip on same network // with correct owner - tt.test('run with assigned ipv4 address with multiple ip ' + - 'on same network with correct owner', function (t) { - if (!FABRICS) { - t.skip('sdc-docker without fabrics currently do ' + - 'not support multiple networks') - return t.end() - } + tt.test('fail run with assigned ipv4 address with multiple ip ' + + 'on same network with correct owner', function (t) { var assignedAddrLabel = '10.0.21.200'; var assignedAddrClient = '10.0.21.201'; + var expectedErr = format('(Validation) both networks are of uuid: %s, ' + + 'networks must be distinct', externalNetworkOwner.uuid); var EndpointsConfig = {}; EndpointsConfig[externalNetworkOwner.name] = { IPAMConfig: { @@ -1206,6 +1254,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', vmapiClient: VMAPI, dockerClient: DOCKER_ALICE, test: t, + expectedErr: expectedErr, extra: { 'HostConfig.PublishAllPorts': true, 'HostConfig.NetworkMode': externalNetworkOwner.name, @@ -1219,34 +1268,57 @@ test('run external network (docker run --label triton.network.public_ipv4=)', }, oncreate); function oncreate(err, result) { - assert.strictEqual(err, null); - var nics = result.vm.nics; - t.equal(nics.length, 2, 'two nics'); - nics.forEach(function(nic){ - if (nic.primary) { - t.equal(nic.ip, assignedAddrLabel) - } else { - t.equal(nic.ip, assignedAddrClient) - } - }); - DOCKER_ALICE.del('/containers/' + result.id + '?force=1', ondelete); + assert.object(err, 'err'); + t.end(); } + }); - function ondelete(err) { - t.ifErr(err, 'delete external triton.network.public_ipv4 testing container'); + // fail to provision when there is multiple ip on different networks + // with correct owner without published ports + tt.test('fail to run with assigned ipv4 address with multiple ip ' + + 'on different networks with correct owners without published ' + + 'ports', function (t) { + var assignedAddrLabel = '10.0.21.200'; + var assignedAddrClient = '10.0.31.200'; + var expectedErr = format('(Validation) non fabrics with 2 ' + + 'networks requires a container with published ports'); + if (FABRICS) { + var expectedErr = format('(Validation) triton.network.' + + 'public label requires a container with published ports'); + } + var EndpointsConfig = {}; + EndpointsConfig[anotherExternalNetworkOwner.name] = { + IPAMConfig: { + IPv4Address: assignedAddrClient + } + } + h.createDockerContainer({ + vmapiClient: VMAPI, + dockerClient: DOCKER_ALICE, + test: t, + expectedErr: expectedErr, + extra: { + 'HostConfig.PublishAllPorts': false, + 'HostConfig.NetworkMode': anotherExternalNetworkOwner.name, + Labels: { + 'triton.network.public': externalNetworkOwner.name, + 'triton.network.public_ipv4': assignedAddrLabel + }, + 'NetworkingConfig.EndpointsConfig': EndpointsConfig + }, + start: true + }, oncreate); + + function oncreate(err, result) { + assert.object(err, 'err'); t.end(); } }); // provision when there is multiple ip on different networks // with correct owner - tt.test('run with assigned ipv4 address with multiple ip ' + - 'on different networks with correct owners', function (t) { - if (!FABRICS) { - t.skip('sdc-docker without fabrics currently do ' + - 'not support multiple networks') - return t.end() - } + tt.test('run with assigned ipv4 address with multiple ip ' + + 'on different networks with correct owners', function (t) { var assignedAddrLabel = '10.0.21.200'; var assignedAddrClient = '10.0.31.200'; var EndpointsConfig = {}; @@ -1275,7 +1347,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', assert.strictEqual(err, null); var nics = result.vm.nics; t.equal(nics.length, 2, 'two nics'); - nics.forEach(function(nic){ + nics.forEach(function (nic) { if (nic.primary) { t.equal(nic.ip, assignedAddrLabel) } else { @@ -1286,22 +1358,19 @@ test('run external network (docker run --label triton.network.public_ipv4=)', } function ondelete(err) { - t.ifErr(err, 'delete external triton.network.public_ipv4 testing container'); + t.ifErr(err, 'delete external triton.network.public_ipv4 testing' + + 'container'); t.end(); } }); // fail to provision when there is multiple ip on different networks // with incorrect owners - tt.test('fail to run with assigned ipv4 address with multiple ip ' + - 'on different networks with incorrect owner and correct owner', function (t) { - if (!FABRICS) { - t.skip('sdc-docker without fabrics currently do ' + - 'not support multiple networks') - return t.end() - } - var expectedErr = '(Error) network sdcdockertest_apicreate_external_bob0 ' - + 'not found'; + tt.test('fail to run with assigned ipv4 address with multiple ip ' + + 'on different networks with incorrect owner and correct owner', + function (t) { + var expectedErr = '(Error) network ' + + 'sdcdockertest_apicreate_external_bob0 not found'; var assignedAddrLabel = '10.0.21.200'; var assignedAddrClient = '10.0.41.200'; var EndpointsConfig = {}; @@ -1344,7 +1413,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', anotherExternalNetworkOwner ]; - cleanupNetworks.forEach(function(network){ + cleanupNetworks.forEach(function (network) { NAPI.deleteNetwork(network.uuid, function (err) { t.ifErr(err, 'external network deletion'); }); From e06d615f14583dd3e6577b094588dc58b6d1dbb3 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Thu, 4 Sep 2025 12:10:48 -0400 Subject: [PATCH 14/18] bump eng and fix typo --- deps/eng | 2 +- test/integration/api-create.test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps/eng b/deps/eng index 34cbcb43..abf5ffdb 160000 --- a/deps/eng +++ b/deps/eng @@ -1 +1 @@ -Subproject commit 34cbcb436d57ba17538b34592d121c856e03c736 +Subproject commit abf5ffdb7a0637c032ee81efe76b8f3859c17699 diff --git a/test/integration/api-create.test.js b/test/integration/api-create.test.js index 90a7df06..c8f6f52d 100644 --- a/test/integration/api-create.test.js +++ b/test/integration/api-create.test.js @@ -993,7 +993,7 @@ test('run external network (docker run --label triton.network.public=)', }); /* - * Tests for `docker run --label trtiton.network.public_ipv4` + * Tests for `docker run --label triton.network.public_ipv4` * * TRITON-2497 Add static addresses to public networks */ @@ -1099,7 +1099,7 @@ test('run external network (docker run --label triton.network.public_ipv4=)', }); // Fail to provision when there is no owner - tt.test('run with assigned ipv4 address no owner', function (t) { + tt.test('fail to run with assigned ipv4 address no owner', function (t) { var expectedErr = '(Validation) triton.network.public_ipv4 label ' + 'requires network ownership'; h.createDockerContainer({ From 85561bfd3f6d910fde7209bf6bbd23d1602ed082 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Thu, 4 Sep 2025 16:02:54 -0400 Subject: [PATCH 15/18] json trailing , --- test/integration/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/helpers.js b/test/integration/helpers.js index 9d95999b..0bc48463 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -1771,7 +1771,7 @@ function createDockerContainer(opts, callback) { 'RestartPolicy': { 'Name': '', 'MaximumRetryCount': 0 - }, + } }, 'NetworkingConfig': { 'EndpointsConfig': {} From f6a571b35bd200f4f3668debd49579bb9763c4bf Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Thu, 4 Sep 2025 16:20:00 -0400 Subject: [PATCH 16/18] fix copyright --- lib/backends/sdc/networks.js | 2 +- test/integration/helpers.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index cd0debbf..eaf9250a 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -6,7 +6,7 @@ /* * Copyright 2021 Joyent, Inc. - * Copyright 2025 Bruce Smith + * Copyright 2025, Bruce Smith */ /* diff --git a/test/integration/helpers.js b/test/integration/helpers.js index 0bc48463..02908ed0 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -7,6 +7,7 @@ /* * Copyright (c) 2018, Joyent, Inc. * Copyright 2022 MNX Cloud, Inc. + * Copyright 2025, Bruce Smith */ /* From 794be7e2bb7d6de241996b14d92b809a56b161d0 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Thu, 4 Sep 2025 16:49:37 -0400 Subject: [PATCH 17/18] eng copyright workaround --- lib/backends/sdc/networks.js | 2 +- test/integration/api-create.test.js | 2 +- test/integration/helpers.js | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index eaf9250a..cd0debbf 100644 --- a/lib/backends/sdc/networks.js +++ b/lib/backends/sdc/networks.js @@ -6,7 +6,7 @@ /* * Copyright 2021 Joyent, Inc. - * Copyright 2025, Bruce Smith + * Copyright 2025 Bruce Smith */ /* diff --git a/test/integration/api-create.test.js b/test/integration/api-create.test.js index c8f6f52d..2743f115 100644 --- a/test/integration/api-create.test.js +++ b/test/integration/api-create.test.js @@ -6,7 +6,7 @@ /* * Copyright 2017, Joyent, Inc. - * Copyright 2025, Bruce Smith + * Copyright 2025 Bruce Smith */ /* diff --git a/test/integration/helpers.js b/test/integration/helpers.js index 02908ed0..51de7427 100644 --- a/test/integration/helpers.js +++ b/test/integration/helpers.js @@ -7,7 +7,8 @@ /* * Copyright (c) 2018, Joyent, Inc. * Copyright 2022 MNX Cloud, Inc. - * Copyright 2025, Bruce Smith + * Copyright 2025 Edgecast Cloud LLC. + * Copyright 2025 Bruce Smith */ /* From b9bd128c04650a1c34b9ff448f3a0a8c95a645c7 Mon Sep 17 00:00:00 2001 From: Bruce Smith Date: Fri, 5 Sep 2025 12:00:42 -0400 Subject: [PATCH 18/18] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6fd67650..0fb95564 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sdc-docker", - "version": "0.7.11", + "version": "0.8.0", "author": "MNX Cloud (mnx.io)", "private": true, "dependencies": {