mirror of https://github.com/portainer/portainer
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 functionpull/4016/merge
parent
08095913a6
commit
c778ef6404
|
@ -21,13 +21,13 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
|
||||||
Subnet: '',
|
Subnet: '',
|
||||||
Gateway: '',
|
Gateway: '',
|
||||||
IPRange: '',
|
IPRange: '',
|
||||||
AuxAddress: '',
|
AuxiliaryAddresses: [],
|
||||||
},
|
},
|
||||||
IPV6: {
|
IPV6: {
|
||||||
Subnet: '',
|
Subnet: '',
|
||||||
Gateway: '',
|
Gateway: '',
|
||||||
IPRange: '',
|
IPRange: '',
|
||||||
AuxAddress: '',
|
AuxiliaryAddresses: [],
|
||||||
},
|
},
|
||||||
Labels: [],
|
Labels: [],
|
||||||
AccessControlData: new AccessControlFormData(),
|
AccessControlData: new AccessControlFormData(),
|
||||||
|
@ -79,6 +79,59 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
|
||||||
$scope.formValues.Labels.splice(index, 1);
|
$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) {
|
function prepareIPAMConfiguration(config) {
|
||||||
if ($scope.formValues.IPV4.Subnet) {
|
if ($scope.formValues.IPV4.Subnet) {
|
||||||
let ipamConfig = {};
|
let ipamConfig = {};
|
||||||
|
@ -89,8 +142,8 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
|
||||||
if ($scope.formValues.IPV4.IPRange) {
|
if ($scope.formValues.IPV4.IPRange) {
|
||||||
ipamConfig.IPRange = $scope.formValues.IPV4.IPRange;
|
ipamConfig.IPRange = $scope.formValues.IPV4.IPRange;
|
||||||
}
|
}
|
||||||
if ($scope.formValues.IPV4.AuxAddress) {
|
if ($scope.formValues.IPV4.AuxiliaryAddresses.length) {
|
||||||
ipamConfig.AuxAddress = $scope.formValues.IPV4.AuxAddress;
|
prepareAuxiliaryAddresses(ipamConfig, $scope.formValues.IPV4);
|
||||||
}
|
}
|
||||||
config.IPAM.Config.push(ipamConfig);
|
config.IPAM.Config.push(ipamConfig);
|
||||||
}
|
}
|
||||||
|
@ -103,8 +156,8 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
|
||||||
if ($scope.formValues.IPV6.IPRange) {
|
if ($scope.formValues.IPV6.IPRange) {
|
||||||
ipamConfig.IPRange = $scope.formValues.IPV6.IPRange;
|
ipamConfig.IPRange = $scope.formValues.IPV6.IPRange;
|
||||||
}
|
}
|
||||||
if ($scope.formValues.IPV6.AuxAddress) {
|
if ($scope.formValues.IPV6.AuxiliaryAddresses.length) {
|
||||||
ipamConfig.AuxAddress = $scope.formValues.IPV6.AuxAddress;
|
prepareAuxiliaryAddresses(ipamConfig, $scope.formValues.IPV6);
|
||||||
}
|
}
|
||||||
config.EnableIPv6 = true;
|
config.EnableIPv6 = true;
|
||||||
config.IPAM.Config.push(ipamConfig);
|
config.IPAM.Config.push(ipamConfig);
|
||||||
|
@ -245,6 +298,8 @@ angular.module('portainer.docker').controller('CreateNetworkController', [
|
||||||
|
|
||||||
function initView() {
|
function initView() {
|
||||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||||
|
$scope.state.IPV4AuxiliaryAddressesError = [];
|
||||||
|
$scope.state.IPV6AuxiliaryAddressesError = [];
|
||||||
|
|
||||||
PluginService.networkPlugins(apiVersion < 1.25)
|
PluginService.networkPlugins(apiVersion < 1.25)
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
|
|
|
@ -88,12 +88,32 @@
|
||||||
<div class="col-sm-4 col-lg-5">
|
<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" />
|
<input type="text" class="form-control" ng-model="formValues.IPV4.IPRange" id="ipv4_network_iprange" placeholder="e.g. 172.20.10.128/25" />
|
||||||
</div>
|
</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">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<!-- !iprange-auxaddr-inputs -->
|
<!-- !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>
|
||||||
<div ng-show="config.Driver === 'bridge' || (config.Driver === 'macvlan' && formValues.Macvlan.Scope !== 'swarm')">
|
<div ng-show="config.Driver === 'bridge' || (config.Driver === 'macvlan' && formValues.Macvlan.Scope !== 'swarm')">
|
||||||
<div class="col-sm-12 form-section-title">
|
<div class="col-sm-12 form-section-title">
|
||||||
|
@ -117,12 +137,32 @@
|
||||||
<div class="col-sm-4 col-lg-5">
|
<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" />
|
<input type="text" class="form-control" ng-model="formValues.IPV6.IPRange" id="ipv6_network_iprange" placeholder="e.g. 2001:db8::/64" />
|
||||||
</div>
|
</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">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<!-- !iprange-auxaddr-inputs -->
|
<!-- !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>
|
||||||
<div class="col-sm-12 form-section-title">
|
<div class="col-sm-12 form-section-title">
|
||||||
Advanced configuration
|
Advanced configuration
|
||||||
|
@ -205,7 +245,7 @@
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-primary btn-sm"
|
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()"
|
ng-click="create()"
|
||||||
button-spinner="state.actionInProgress"
|
button-spinner="state.actionInProgress"
|
||||||
>
|
>
|
||||||
|
|
|
@ -47,7 +47,9 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="network.IPAM.IPV4Configs.length > 0" ng-repeat-end>
|
<tr ng-if="network.IPAM.IPV4Configs.length > 0" ng-repeat-end>
|
||||||
<td>IPV4 IP range - {{ config.IPRange }}</td>
|
<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>
|
||||||
<tr ng-if="network.IPAM.IPV6Configs.length > 0" ng-repeat-start="config in network.IPAM.IPV6Configs">
|
<tr ng-if="network.IPAM.IPV6Configs.length > 0" ng-repeat-start="config in network.IPAM.IPV6Configs">
|
||||||
<td>IPV6 Subnet - {{ config.Subnet }}</td>
|
<td>IPV6 Subnet - {{ config.Subnet }}</td>
|
||||||
|
@ -55,7 +57,9 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-if="network.IPAM.IPV6Configs.length > 0" ng-repeat-end>
|
<tr ng-if="network.IPAM.IPV6Configs.length > 0" ng-repeat-end>
|
||||||
<td>IPV6 IP range - {{ config.IPRange }}</td>
|
<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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Reference in New Issue