Merge branch 'feat-1807-service-network-management' of github.com:portainer/portainer into develop

pull/3546/head
itsconquest 2020-02-06 19:08:56 +13:00
commit e4254cb634
3 changed files with 77 additions and 14 deletions

View File

@ -1,4 +1,5 @@
import moment from 'moment';
import _ from 'lodash-es';
angular.module('portainer.docker')
.factory('ServiceHelper', [function ServiceHelperFactory() {
@ -21,6 +22,22 @@ angular.module('portainer.docker')
tasks = otherServicesTasks;
};
function findAssociatedNetwork(serviceNetwork, networks) {
return _.find(networks, function(network) {
return network.Id === serviceNetwork.NetworkID;
});
}
helper.mapNetworkNameToServiceNetwork = function(service, networks) {
for (var i = 0; i < service.ServiceNetworks.length; i++) {
var serviceNetwork = service.ServiceNetworks[i];
var network = findAssociatedNetwork(serviceNetwork, networks);
if (network) {
serviceNetwork.Name = network.Name;
}
}
};
helper.serviceToConfig = function(service) {
return {
Name: service.Spec.Name,

View File

@ -1,26 +1,52 @@
<div id="service-network-specs">
<rd-widget>
<rd-widget-header icon="fa-tasks" title-text="Networks"></rd-widget-header>
<rd-widget-body ng-if="!service.VirtualIPs || service.VirtualIPs.length === 0">
<p>This service is not connected to any networks.</p>
</rd-widget-body>
<rd-widget-body ng-if="service.VirtualIPs && service.VirtualIPs.length > 0" classes="no-padding">
<table class="table" >
<div class="form-inline" style="padding: 10px;" authorization="DockerServiceUpdate">
Add a network:
<select class="form-control" ng-options="network.Name for network in availableNetworks | orderBy: 'Id'" ng-model="newNetwork">
<option selected disabled hidden value="">Select a network</option>
</select>
<a class="btn btn-default btn-sm" ng-click="addNetwork(service, newNetwork)">
<i class="fa fa-plus-circle" aria-hidden="true"></i> add network
</a>
</div>
<p style="padding: 10px;" ng-if="!service.ServiceNetworks || service.ServiceNetworks.length === 0">This service is not connected to any networks.</p>
<table class="table" style="margin-top: 5px;" ng-if="service.ServiceNetworks && service.ServiceNetworks.length > 0">
<thead>
<tr>
<th>ID</th>
<th>Network</th>
<th>IP address</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="network in service.VirtualIPs">
<tr ng-repeat="network in service.ServiceNetworks">
<td>
<a ui-sref="docker.networks.network({id: network.NetworkID})">{{ network.NetworkID }}</a>
<a ui-sref="docker.networks.network({id: network.NetworkID})">{{ network.Name }}</a>
</td>
<td>{{ network.Addr }}</td>
<td authorization="DockerServiceUpdate">
<button type="button" class="btn btn-xs btn-danger" ng-click="removeNetwork(service, $index)" ng-disabled="isUpdating">
<i class="fa fa-trash" aria-hidden="true"></i> Remove network
</button>
</td>
</tr>
</tbody>
</table>
</rd-widget-body>
<rd-widget-footer>
<div class="btn-toolbar" role="toolbar">
<div class="btn-group" role="group">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="!hasChanges(service, ['ServiceNetworks'])" ng-click="updateService(service)">Apply changes</button>
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a ng-click="cancelChanges(service, ['ServiceNetworks'])"">Reset changes</a></li>
<li><a ng-click="cancelChanges(service)">Reset all changes</a></li>
</ul>
</div>
</div>
</rd-widget-footer>
</rd-widget>
</div>

View File

@ -18,10 +18,11 @@ require('./includes/tasks.html')
require('./includes/updateconfig.html')
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
import _ from 'lodash-es';
angular.module('portainer.docker')
.controller('ServiceController', ['$q', '$scope', '$transition$', '$state', '$location', '$timeout', '$anchorScroll', 'ServiceService', 'ConfigService', 'ConfigHelper', 'SecretService', 'ImageService', 'SecretHelper', 'Service', 'ServiceHelper', 'LabelHelper', 'TaskService', 'NodeService', 'ContainerService', 'TaskHelper', 'Notifications', 'ModalService', 'PluginService', 'Authentication', 'SettingsService', 'VolumeService', 'ImageHelper', 'WebhookService', 'EndpointProvider', 'clipboard','WebhookHelper',
function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll, ServiceService, ConfigService, ConfigHelper, SecretService, ImageService, SecretHelper, Service, ServiceHelper, LabelHelper, TaskService, NodeService, ContainerService, TaskHelper, Notifications, ModalService, PluginService, Authentication, SettingsService, VolumeService, ImageHelper, WebhookService, EndpointProvider, clipboard, WebhookHelper) {
.controller('ServiceController', ['$q', '$scope', '$transition$', '$state', '$location', '$timeout', '$anchorScroll', 'ServiceService', 'ConfigService', 'ConfigHelper', 'SecretService', 'ImageService', 'SecretHelper', 'Service', 'ServiceHelper', 'LabelHelper', 'TaskService', 'NodeService', 'NetworkService', 'ContainerService', 'TaskHelper', 'Notifications', 'ModalService', 'PluginService', 'Authentication', 'SettingsService', 'VolumeService', 'ImageHelper', 'WebhookService', 'EndpointProvider', 'clipboard','WebhookHelper',
function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll, ServiceService, ConfigService, ConfigHelper, SecretService, ImageService, SecretHelper, Service, ServiceHelper, LabelHelper, TaskService, NodeService, NetworkService, ContainerService, TaskHelper, Notifications, ModalService, PluginService, Authentication, SettingsService, VolumeService, ImageHelper, WebhookService, EndpointProvider, clipboard, WebhookHelper) {
$scope.state = {
updateInProgress: false,
@ -167,7 +168,19 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
$scope.updatePlacementPreference = function(service) {
updateServiceArray(service, 'ServicePreferences', service.ServicePreferences);
};
$scope.addNetwork = function addNetwork(service, network) {
if (network && !_.find(service.ServiceNetworks, {'NetworkID': network.Id})) {
service.ServiceNetworks.push({NetworkID: network.Id})
updateServiceArray(service, 'ServiceNetworks', service.ServiceNetworks);
ServiceHelper.mapNetworkNameToServiceNetwork(service, $scope.networks);
}
};
$scope.removeNetwork = function removeNetwork(service, index) {
var removedElement = service.ServiceNetworks.splice(index, 1);
if (removedElement !== null) {
updateServiceArray(service, 'ServiceNetworks', service.ServiceNetworks);
}
};
$scope.addPublishedPort = function addPublishedPort(service) {
if (!service.Ports) {
service.Ports = [];
@ -297,7 +310,9 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
} else {
config.TaskTemplate.ContainerSpec.Image = service.Image;
}
if ($scope.hasChanges(service, ["ServiceNetworks"])) {
config.TaskTemplate.Networks = _.map(service.ServiceNetworks, ({NetworkID}) => ({ Target: NetworkID}));
}
config.TaskTemplate.ContainerSpec.Secrets = service.ServiceSecrets ? service.ServiceSecrets.map(SecretHelper.secretConfig) : [];
config.TaskTemplate.ContainerSpec.Configs = service.ServiceConfigs ? service.ServiceConfigs.map(ConfigHelper.configConfig) : [];
config.TaskTemplate.ContainerSpec.Hosts = service.Hosts ? ServiceHelper.translateHostnameIPToHostsEntries(service.Hosts) : [];
@ -508,6 +523,7 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
service.ServiceMounts = angular.copy(service.Mounts);
service.ServiceConstraints = ServiceHelper.translateConstraintsToKeyValue(service.Constraints);
service.ServicePreferences = ServiceHelper.translatePreferencesToKeyValue(service.Preferences);
service.ServiceNetworks = service.VirtualIPs ? angular.copy(service.VirtualIPs) : [];
service.Hosts = ServiceHelper.translateHostsEntriesToHostnameIP(service.Hosts);
}
@ -549,6 +565,8 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
tasks: TaskService.tasks({ service: [service.Name] }),
containers: agentProxy ? ContainerService.containers() : [],
nodes: NodeService.nodes(),
networks: NetworkService.networks(true, true, true),
availableNetworks: NetworkService.networks(true, true, true),
secrets: apiVersion >= 1.25 ? SecretService.secrets() : [],
configs: apiVersion >= 1.30 ? ConfigService.configs() : [],
availableImages: ImageService.images(),
@ -566,7 +584,8 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
$scope.availableVolumes = data.volumes;
$scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers;
$scope.isAdmin = Authentication.isAdmin();
$scope.networks = data.networks;
$scope.availableNetworks = data.availableNetworks;
if (data.webhooks.length > 0) {
var webhook = data.webhooks[0];
$scope.WebhookExists = true;
@ -588,7 +607,8 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
$scope.tasks = data.tasks;
ServiceHelper.mapNetworkNameToServiceNetwork(service, data.networks);
// Set max cpu value
var maxCpus = 0;
for (var n in data.nodes) {