diff --git a/lib/backends/sdc/networks.js b/lib/backends/sdc/networks.js index 74ec05a2..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. */ /* @@ -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,19 @@ function addNetworksToContainerPayload(opts, container, payload, callback) { next(findErr); return; } - payload.networks = [ {uuid: network.uuid, primary: true} ]; + 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 ]; + } + } + next(); }); } @@ -800,6 +827,51 @@ 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 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, 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",