feat(networks): Support multiple excluded IPs for MACVLAN networks (#3962)

* feat(networks): Support multiple excluded IPs for MACVLAN networks

* feat(networks): add a generated name

* feat(networks): prevent create macvlan network where exclude ip is the same as gateway

* feat(networks): remove auxaddresses validation on submit

* feat(networks): check exclude ip validation on change

* feat(networks): check form validation on change

* feat(networks): clean checkAuxiliaryAddress function
pull/4016/merge
Maxime Bajeux 2020-07-08 03:35:52 +02:00 committed by GitHub
parent 08095913a6
commit c778ef6404
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 112 additions and 13 deletions

View File

@ -21,13 +21,13 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
Subnet: '',
Gateway: '',
IPRange: '',
AuxAddress: '',
AuxiliaryAddresses: [],
},
IPV6: {
Subnet: '',
Gateway: '',
IPRange: '',
AuxAddress: '',
AuxiliaryAddresses: [],
},
Labels: [],
AccessControlData: new AccessControlFormData(),
@ -79,6 +79,59 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
$scope.formValues.Labels.splice(index, 1);
};
$scope.addIPV4AuxAddress = function () {
$scope.formValues.IPV4.AuxiliaryAddresses.push('');
};
$scope.addIPV6AuxAddress = function () {
$scope.formValues.IPV6.AuxiliaryAddresses.push('');
};
$scope.removeIPV4AuxAddress = function (index) {
$scope.formValues.IPV4.AuxiliaryAddresses.splice(index, 1);
$scope.state.IPV4AuxiliaryAddressesError.splice(index, 1);
};
$scope.removeIPV6AuxAddress = function (index) {
$scope.formValues.IPV6.AuxiliaryAddresses.splice(index, 1);
$scope.state.IPV6AuxiliaryAddressesError.splice(index, 1);
};
function checkAuxiliaryAddress(excludedIP, gateway) {
const split = _.split(excludedIP, '=');
if (split.length === 2) {
return split[1] === gateway;
}
return excludedIP === gateway;
}
$scope.checkIPV4AuxiliaryAddress = function (index) {
$scope.state.IPV4AuxiliaryAddressesError[index] = checkAuxiliaryAddress($scope.formValues.IPV4.AuxiliaryAddresses[index], $scope.formValues.IPV4.Gateway);
};
$scope.checkIPV6AuxiliaryAddress = function (index) {
$scope.state.IPV6AuxiliaryAddressesError[index] = checkAuxiliaryAddress($scope.formValues.IPV6.AuxiliaryAddresses[index], $scope.formValues.IPV6.Gateway);
};
$scope.isValid = function () {
const validIPV4 = !_.reduce($scope.state.IPV4AuxiliaryAddressesError, (acc, item) => acc || item, false);
const validIPV6 = !_.reduce($scope.state.IPV6AuxiliaryAddressesError, (acc, item) => acc || item, false);
return validIPV4 && validIPV6;
};
function prepareAuxiliaryAddresses(ipamConfig, ipFormValues) {
ipamConfig.AuxiliaryAddresses = {};
_.forEach(ipFormValues.AuxiliaryAddresses, (auxAddress, index) => {
const split = _.split(auxAddress, '=');
if (split.length === 2) {
ipamConfig.AuxiliaryAddresses[split[0]] = split[1];
} else {
ipamConfig.AuxiliaryAddresses['device' + index] = auxAddress;
}
});
}
function prepareIPAMConfiguration(config) {
if ($scope.formValues.IPV4.Subnet) {
let ipamConfig = {};
@ -89,8 +142,8 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
if ($scope.formValues.IPV4.IPRange) {
ipamConfig.IPRange = $scope.formValues.IPV4.IPRange;
}
if ($scope.formValues.IPV4.AuxAddress) {
ipamConfig.AuxAddress = $scope.formValues.IPV4.AuxAddress;
if ($scope.formValues.IPV4.AuxiliaryAddresses.length) {
prepareAuxiliaryAddresses(ipamConfig, $scope.formValues.IPV4);
}
config.IPAM.Config.push(ipamConfig);
}
@ -103,8 +156,8 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
if ($scope.formValues.IPV6.IPRange) {
ipamConfig.IPRange = $scope.formValues.IPV6.IPRange;
}
if ($scope.formValues.IPV6.AuxAddress) {
ipamConfig.AuxAddress = $scope.formValues.IPV6.AuxAddress;
if ($scope.formValues.IPV6.AuxiliaryAddresses.length) {
prepareAuxiliaryAddresses(ipamConfig, $scope.formValues.IPV6);
}
config.EnableIPv6 = true;
config.IPAM.Config.push(ipamConfig);
@ -245,6 +298,8 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
function initView() {
var apiVersion = $scope.applicationState.endpoint.apiVersion;
$scope.state.IPV4AuxiliaryAddressesError = [];
$scope.state.IPV6AuxiliaryAddressesError = [];
PluginService.networkPlugins(apiVersion < 1.25)
.then(function success(data) {

View File

@ -88,12 +88,32 @@
<div class="col-sm-4 col-lg-5">
<input type="text" class="form-control" ng-model="formValues.IPV4.IPRange" id="ipv4_network_iprange" placeholder="e.g. 172.20.10.128/25" />
</div>
<label for="ipv4_network_auxaddr" class="col-sm-2 col-lg-1 control-label text-left">Exclude IPs</label>
</div>
<div ng-repeat="auxAddress in formValues.IPV4.AuxiliaryAddresses track by $index" class="form-group">
<label for="ipv4_network_auxaddr_{{ $index }}" class="col-sm-2 col-lg-1 control-label text-left">Exclude IP</label>
<div class="col-sm-4 col-lg-5">
<input type="text" class="form-control" ng-model="formValues.IPV4.AuxAddress" id="ipv4_network_auxaddr" placeholder="e.g. my-router=172.20.10.129" />
<input
type="text"
class="form-control"
ng-model="formValues.IPV4.AuxiliaryAddresses[$index]"
ng-change="checkIPV4AuxiliaryAddress($index)"
id="ipv4_network_auxaddr_{{ $index }}"
placeholder="e.g. my-router=172.20.10.129"
/>
</div>
<button class="btn btn-sm btn-danger" type="button" ng-click="removeIPV4AuxAddress($index)">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
<div class="col-sm-12 small text-warning" ng-show="state.IPV4AuxiliaryAddressesError[$index]">
<p><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Exclude ip cannot be the same as gateway.</p>
</div>
</div>
<!-- !iprange-auxaddr-inputs -->
<div class="form-group">
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="addIPV4AuxAddress()">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add excluded IP
</span>
</div>
</div>
<div ng-show="config.Driver === 'bridge' || (config.Driver === 'macvlan' && formValues.Macvlan.Scope !== 'swarm')">
<div class="col-sm-12 form-section-title">
@ -117,12 +137,32 @@
<div class="col-sm-4 col-lg-5">
<input type="text" class="form-control" ng-model="formValues.IPV6.IPRange" id="ipv6_network_iprange" placeholder="e.g. 2001:db8::/64" />
</div>
<label for="ipv6_network_auxaddr" class="col-sm-2 col-lg-1 control-label text-left">Exclude IPs</label>
</div>
<div ng-repeat="auxAddress in formValues.IPV6.AuxiliaryAddresses track by $index" class="form-group">
<label for="ipv6_network_auxaddr_{{ $index }}" class="col-sm-2 col-lg-1 control-label text-left">Exclude IP</label>
<div class="col-sm-4 col-lg-5">
<input type="text" class="form-control" ng-model="formValues.IPV6.AuxAddress" id="ipv6_network_auxaddr" placeholder="e.g. my-router=2001:db8::1" />
<input
type="text"
class="form-control"
ng-model="formValues.IPV6.AuxiliaryAddresses[$index]"
ng-change="checkIPV6AuxiliaryAddress($index)"
id="ipv6_network_auxaddr_{{ $index }}"
placeholder="e.g. my-router=2001:db8::1"
/>
</div>
<button class="btn btn-sm btn-danger" type="button" ng-click="removeIPV6AuxAddress($index)">
<i class="fa fa-trash" aria-hidden="true"></i>
</button>
<div class="col-sm-12 small text-warning" ng-show="state.IPV6AuxiliaryAddressesError[$index]">
<p><i class="fa fa-exclamation-triangle" aria-hidden="true"></i> Exclude ip cannot be the same as gateway.</p>
</div>
</div>
<!-- !iprange-auxaddr-inputs -->
<div class="form-group">
<span class="label label-default interactive" style="margin-left: 10px;" ng-click="addIPV6AuxAddress()">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add excluded IP
</span>
</div>
</div>
<div class="col-sm-12 form-section-title">
Advanced configuration
@ -205,7 +245,7 @@
<button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="state.actionInProgress || !config.Name || (config.Driver === 'macvlan' && networkCreationForm.$invalid)"
ng-disabled="state.actionInProgress || !config.Name || (config.Driver === 'macvlan' && networkCreationForm.$invalid) || !isValid()"
ng-click="create()"
button-spinner="state.actionInProgress"
>

View File

@ -47,7 +47,9 @@
</tr>
<tr ng-if="network.IPAM.IPV4Configs.length > 0" ng-repeat-end>
<td>IPV4 IP range - {{ config.IPRange }}</td>
<td>IPV4 Excluded Ips - {{ config.AuxAddress }}</td>
<td
>IPV4 Excluded Ips<span ng-repeat="auxAddress in config.AuxiliaryAddresses"> - {{ auxAddress }}</span></td
>
</tr>
<tr ng-if="network.IPAM.IPV6Configs.length > 0" ng-repeat-start="config in network.IPAM.IPV6Configs">
<td>IPV6 Subnet - {{ config.Subnet }}</td>
@ -55,7 +57,9 @@
</tr>
<tr ng-if="network.IPAM.IPV6Configs.length > 0" ng-repeat-end>
<td>IPV6 IP range - {{ config.IPRange }}</td>
<td>IPV6 Excluded Ips - {{ config.AuxAddress }}</td>
<td
>IPV6 Excluded Ips<span ng-repeat="auxAddress in config.AuxiliaryAddresses"> - {{ auxAddress }}</span></td
>
</tr>
</tbody>
</table>