From 3de533042d5625eef585fd8dfdb6e9040108aa32 Mon Sep 17 00:00:00 2001 From: Maxime Bajeux Date: Tue, 28 Apr 2020 02:34:54 +0200 Subject: [PATCH] feat(networks): add ipv6 support (#3717) * feat(portainer-core): add ipv6 support * feat(networks): add few changes * refacto(networks): write regex once * fix(networks): fix indentation * refacto(networks): use foreach instead map and pluralize ipvxconfig * refacto(networks): pluralize ipvxconfig * feat(networks): support ipv6 with ports * feat(networks): add an explicit error message * fix(networks): hide ipv6 configuration when creating macvlan --- .../containerNetworksDatatable.html | 27 +++++-- .../containerNetworksDatatable.js | 2 +- .../containerNetworksDatatableController.js | 81 +++++++++++++++++++ .../containersDatatable.html | 8 -- .../networkRowContent.html | 8 +- .../networks-datatable/networksDatatable.html | 44 +++++----- app/docker/helpers/containerHelper.js | 17 +++- app/docker/helpers/networkHelper.js | 13 +++ .../containers/create/createcontainer.html | 4 +- .../views/containers/edit/container.html | 1 + .../create/createNetworkController.js | 50 +++++++++--- .../views/networks/create/createnetwork.html | 47 ++++++++--- app/docker/views/networks/edit/network.html | 18 ++++- .../views/networks/edit/networkController.js | 4 + .../views/networks/networksController.js | 6 ++ .../create/createServiceController.js | 4 +- 16 files changed, 262 insertions(+), 72 deletions(-) create mode 100644 app/docker/components/datatables/container-networks-datatable/containerNetworksDatatableController.js create mode 100644 app/docker/helpers/networkHelper.js diff --git a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html index 001d61885..63354222e 100644 --- a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html +++ b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.html @@ -34,17 +34,25 @@ Network - IP Address + + IP Address + + + + Gateway MAC Address Actions - - {{ key }} + + + + + + {{ key }} + {{ value.IPAddress || '-' }} {{ value.Gateway || '-' }} {{ value.MacAddress || '-' }} @@ -61,6 +69,15 @@ + + + + {{ value.GlobalIPv6Address }} + + + {{ value.IPv6Gateway || '-' }} + + Loading... diff --git a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js index 501f86c46..570f93e16 100644 --- a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js +++ b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatable.js @@ -1,6 +1,6 @@ angular.module('portainer.docker').component('containerNetworksDatatable', { templateUrl: './containerNetworksDatatable.html', - controller: 'GenericDatatableController', + controller: 'ContainerNetworksDatatableController', bindings: { titleText: '@', titleIcon: '@', diff --git a/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatableController.js b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatableController.js new file mode 100644 index 000000000..82839c40f --- /dev/null +++ b/app/docker/components/datatables/container-networks-datatable/containerNetworksDatatableController.js @@ -0,0 +1,81 @@ +import _ from 'lodash-es'; + +angular.module('portainer.docker') + .controller('ContainerNetworksDatatableController', ['$scope', '$controller', 'DatatableService', + function ($scope, $controller, DatatableService) { + + angular.extend(this, $controller('GenericDatatableController', { $scope: $scope })); + this.state = Object.assign(this.state, { + expandedItems: [], + expandAll: true + }); + + this.expandItem = function (item, expanded) { + if (!this.itemCanExpand(item)) { + return; + } + + item.Expanded = expanded; + if (!expanded) { + item.Highlighted = false; + } + if (!item.Expanded) { + this.state.expandAll = false; + } + }; + + this.itemCanExpand = function (item) { + return item.GlobalIPv6Address !== ''; + } + + this.hasExpandableItems = function () { + return _.filter(this.dataset, (item) => this.itemCanExpand(item)).length; + }; + + this.expandAll = function () { + this.state.expandAll = !this.state.expandAll; + _.forEach(this.dataset, (item) => { + if (this.itemCanExpand(item)) { + this.expandItem(item, this.state.expandAll); + } + }); + }; + + this.$onInit = function () { + this.setDefaults(); + this.prepareTableFromDataset(); + + this.state.orderBy = this.orderBy; + var storedOrder = DatatableService.getDataTableOrder(this.tableKey); + if (storedOrder !== null) { + this.state.reverseOrder = storedOrder.reverse; + this.state.orderBy = storedOrder.orderBy; + } + + var textFilter = DatatableService.getDataTableTextFilters(this.tableKey); + if (textFilter !== null) { + this.state.textFilter = textFilter; + this.onTextFilterChange(); + } + + var storedFilters = DatatableService.getDataTableFilters(this.tableKey); + if (storedFilters !== null) { + this.filters = storedFilters; + } + if (this.filters && this.filters.state) { + this.filters.state.open = false; + } + + var storedSettings = DatatableService.getDataTableSettings(this.tableKey); + if (storedSettings !== null) { + this.settings = storedSettings; + this.settings.open = false; + } + + _.forEach(this.dataset, (item) => { + item.Expanded = true; + item.Highlighted = true; + }); + }; + } + ]); \ No newline at end of file diff --git a/app/docker/components/datatables/containers-datatable/containersDatatable.html b/app/docker/components/datatables/containers-datatable/containersDatatable.html index 638b45e72..44aa27c7e 100644 --- a/app/docker/components/datatables/containers-datatable/containersDatatable.html +++ b/app/docker/components/datatables/containers-datatable/containersDatatable.html @@ -232,13 +232,6 @@ Created - - - IP Address - - - - Host @@ -313,7 +306,6 @@ {{ item.Created | getisodatefromtimestamp }} - {{ item.IP ? item.IP : '-' }} {{ item.NodeName ? item.NodeName : '-' }} System {{ item.StackName ? item.StackName : '-' }} -{{ item.Scope }} {{ item.Driver }} {{ item.Attachable }} -{{ item.Internal }} {{ item.IPAM.Driver }} -{{ item.IPAM.Config[0].Subnet ? item.IPAM.Config[0].Subnet : '-' }} -{{ item.IPAM.Config[0].Gateway ? item.IPAM.Config[0].Gateway : '-' }} +{{ item.IPAM.IPV4Configs[0].Subnet ? item.IPAM.IPV4Configs[0].Subnet : '-' }} +{{ item.IPAM.IPV4Configs[0].Gateway ? item.IPAM.IPV4Configs[0].Gateway : '-' }} +{{ item.IPAM.IPV6Configs[0].Subnet ? item.IPAM.IPV6Configs[0].Subnet : '-' }} +{{ item.IPAM.IPV6Configs[0].Gateway ? item.IPAM.IPV6Configs[0].Gateway : '-' }} {{ item.NodeName ? item.NodeName : '-' }} diff --git a/app/docker/components/datatables/networks-datatable/networksDatatable.html b/app/docker/components/datatables/networks-datatable/networksDatatable.html index 4a72cc550..0c8f1e905 100644 --- a/app/docker/components/datatables/networks-datatable/networksDatatable.html +++ b/app/docker/components/datatables/networks-datatable/networksDatatable.html @@ -95,13 +95,6 @@ - - - Scope - - - - Driver @@ -116,13 +109,6 @@ - - - Internal - - - - IPAM Driver @@ -131,17 +117,31 @@ - - IPAM Subnet - - + + IPV4 IPAM Subnet + + - - IPAM Gateway - - + + IPV4 IPAM Gateway + + + + + + + IPV6 IPAM Subnet + + + + + + + IPV6 IPAM Gateway + + diff --git a/app/docker/helpers/containerHelper.js b/app/docker/helpers/containerHelper.js index e047676b7..8ee1bb9ed 100644 --- a/app/docker/helpers/containerHelper.js +++ b/app/docker/helpers/containerHelper.js @@ -135,10 +135,21 @@ angular.module('portainer.docker').factory('ContainerHelper', [ let startHostPort = 0; let endHostPort = 0; if (hostPort) { - if (hostPort.indexOf(':') > -1) { - const hostAndPort = _.split(hostPort, ':'); - hostIp = hostAndPort[0]; + if (hostPort.indexOf('[') > -1) { + const hostAndPort = _.split(hostPort, ']:'); + + if (hostAndPort.length < 2) { + throw new Error('Invalid port specification: ' + portBinding.containerPort); + } + + hostIp = hostAndPort[0].replace('[', ''); hostPort = hostAndPort[1]; + } else { + if (hostPort.indexOf(':') > -1) { + const hostAndPort = _.split(hostPort, ':'); + hostIp = hostAndPort[0]; + hostPort = hostAndPort[1]; + } } const hostPortRange = parsePortRange(hostPort); diff --git a/app/docker/helpers/networkHelper.js b/app/docker/helpers/networkHelper.js new file mode 100644 index 000000000..09e4abe68 --- /dev/null +++ b/app/docker/helpers/networkHelper.js @@ -0,0 +1,13 @@ +import _ from 'lodash-es'; + +class DockerNetworkHelper { + static getIPV4Configs(configs) { + return _.filter(configs, (config) => /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/.test(config.Subnet)); + } + + static getIPV6Configs(configs) { + return _.without(configs, ...DockerNetworkHelper.getIPV4Configs(configs)); + } +} + +export default DockerNetworkHelper; diff --git a/app/docker/views/containers/create/createcontainer.html b/app/docker/views/containers/create/createcontainer.html index de370e11b..f339a9090 100644 --- a/app/docker/views/containers/create/createcontainer.html +++ b/app/docker/views/containers/create/createcontainer.html @@ -459,7 +459,7 @@
- +
@@ -467,7 +467,7 @@
- +
diff --git a/app/docker/views/containers/edit/container.html b/app/docker/views/containers/edit/container.html index 2d7e9fadb..b8e9ff0a2 100644 --- a/app/docker/views/containers/edit/container.html +++ b/app/docker/views/containers/edit/container.html @@ -317,6 +317,7 @@
- Network configuration + IPV4 Network configuration
- +
- +
- +
- +
- +
- +
- +
- + +
+
+ +
+
+
+ IPV6 Network configuration +
+ +
+ +
+ +
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
diff --git a/app/docker/views/networks/edit/network.html b/app/docker/views/networks/edit/network.html index b0be069f4..9adcba96b 100644 --- a/app/docker/views/networks/edit/network.html +++ b/app/docker/views/networks/edit/network.html @@ -41,9 +41,21 @@ Internal {{ network.Internal }} - - Subnet - {{ config.Subnet }} - Gateway - {{ config.Gateway }} + + IPV4 Subnet - {{ config.Subnet }} + IPV4 Gateway - {{ config.Gateway }} + + + IPV4 IP range - {{ config.IPRange }} + IPV4 Excluded Ips - {{ config.AuxAddress }} + + + IPV6 Subnet - {{ config.Subnet }} + IPV6 Gateway - {{ config.Gateway }} + + + IPV6 IP range - {{ config.IPRange }} + IPV6 Excluded Ips - {{ config.AuxAddress }} diff --git a/app/docker/views/networks/edit/networkController.js b/app/docker/views/networks/edit/networkController.js index 06431ad1a..fb99dae4c 100644 --- a/app/docker/views/networks/edit/networkController.js +++ b/app/docker/views/networks/edit/networkController.js @@ -1,3 +1,5 @@ +import DockerNetworkHelper from 'Docker/helpers/networkHelper'; + angular.module('portainer.docker').controller('NetworkController', [ '$scope', '$state', @@ -101,6 +103,8 @@ angular.module('portainer.docker').controller('NetworkController', [ if (endpointProvider !== 'VMWARE_VIC') { getContainersInNetwork(data); } + $scope.network.IPAM.IPV4Configs = DockerNetworkHelper.getIPV4Configs($scope.network.IPAM.Config); + $scope.network.IPAM.IPV6Configs = DockerNetworkHelper.getIPV6Configs($scope.network.IPAM.Config); }) .catch(function error(err) { Notifications.error('Failure', err, 'Unable to retrieve network info'); diff --git a/app/docker/views/networks/networksController.js b/app/docker/views/networks/networksController.js index be66b64b9..2b193e425 100644 --- a/app/docker/views/networks/networksController.js +++ b/app/docker/views/networks/networksController.js @@ -1,4 +1,5 @@ import _ from 'lodash-es'; +import DockerNetworkHelper from 'Docker/helpers/networkHelper'; angular.module('portainer.docker').controller('NetworksController', [ '$q', @@ -71,6 +72,11 @@ angular.module('portainer.docker').controller('NetworksController', [ } else { $scope.networks = networks; } + + _.forEach($scope.networks, (network) => { + network.IPAM.IPV4Configs = DockerNetworkHelper.getIPV4Configs(network.IPAM.Config); + network.IPAM.IPV6Configs = DockerNetworkHelper.getIPV6Configs(network.IPAM.Config); + }); }) .catch((err) => { $scope.networks = []; diff --git a/app/docker/views/services/create/createServiceController.js b/app/docker/views/services/create/createServiceController.js index 173dcfeda..7500f5371 100644 --- a/app/docker/views/services/create/createServiceController.js +++ b/app/docker/views/services/create/createServiceController.js @@ -214,9 +214,9 @@ angular.module('portainer.docker').controller('CreateServiceController', [ } function preparePortsConfig(config, input) { - var ports = []; + let ports = []; input.Ports.forEach(function (binding) { - var port = { + const port = { Protocol: binding.Protocol, PublishMode: binding.PublishMode, };