diff --git a/app/docker/models/network.js b/app/docker/models/network.js
index e3beb5e1f..32c145efa 100644
--- a/app/docker/models/network.js
+++ b/app/docker/models/network.js
@@ -10,6 +10,7 @@ export function NetworkViewModel(data) {
this.IPAM = data.IPAM;
this.Containers = data.Containers;
this.Options = data.Options;
+ this.Ingress = data.Ingress;
this.Labels = data.Labels;
if (this.Labels && this.Labels['com.docker.compose.project']) {
diff --git a/app/docker/services/networkService.js b/app/docker/services/networkService.js
index 3804aaeed..ad056ae48 100644
--- a/app/docker/services/networkService.js
+++ b/app/docker/services/networkService.js
@@ -41,7 +41,6 @@ angular.module('portainer.docker').factory('NetworkService', [
Network.query({ filters: filters })
.$promise.then(function success(data) {
var networks = data;
-
var filteredNetworks = networks
.filter(function (network) {
if (localNetworks && network.Scope === 'local') {
diff --git a/app/docker/views/services/edit/includes/networks.html b/app/docker/views/services/edit/includes/networks.html
index 40f4fed2d..aa3060c10 100644
--- a/app/docker/views/services/edit/includes/networks.html
+++ b/app/docker/views/services/edit/includes/networks.html
@@ -1,26 +1,74 @@
-
-
+
+
+
+
This service is not connected to any networks.
-
+
+
+
+
diff --git a/app/docker/views/services/edit/serviceController.js b/app/docker/views/services/edit/serviceController.js
index 2e5907ecf..ef6bd3f8f 100644
--- a/app/docker/views/services/edit/serviceController.js
+++ b/app/docker/views/services/edit/serviceController.js
@@ -17,6 +17,7 @@ require('./includes/servicelabels.html');
require('./includes/tasks.html');
require('./includes/updateconfig.html');
+import _ from 'lodash-es';
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
angular.module('portainer.docker').controller('ServiceController', [
@@ -51,6 +52,7 @@ angular.module('portainer.docker').controller('ServiceController', [
'EndpointProvider',
'clipboard',
'WebhookHelper',
+ 'NetworkService',
function (
$q,
$scope,
@@ -82,7 +84,8 @@ angular.module('portainer.docker').controller('ServiceController', [
WebhookService,
EndpointProvider,
clipboard,
- WebhookHelper
+ WebhookHelper,
+ NetworkService
) {
$scope.state = {
updateInProgress: false,
@@ -210,6 +213,25 @@ angular.module('portainer.docker').controller('ServiceController', [
$scope.updateMount = function updateMount(service) {
updateServiceArray(service, 'ServiceMounts', service.ServiceMounts);
};
+
+ $scope.addNetwork = function addNetwork(service) {
+ if (!service.Networks) {
+ service.Networks = [];
+ }
+ service.Networks.push({ Editable: true });
+ };
+
+ $scope.removeNetwork = function removeNetwork(service, index) {
+ var removedElement = service.Networks.splice(index, 1);
+ if (removedElement && removedElement.length && removedElement[0].Id) {
+ updateServiceArray(service, 'Networks', service.Networks);
+ }
+ };
+
+ $scope.updateNetwork = function updateNetwork(service) {
+ updateServiceArray(service, 'Networks', service.Networks);
+ };
+
$scope.addPlacementConstraint = function addPlacementConstraint(service) {
service.ServiceConstraints.push({ key: '', operator: '==', value: '' });
updateServiceArray(service, 'ServiceConstraints', service.ServiceConstraints);
@@ -370,6 +392,14 @@ angular.module('portainer.docker').controller('ServiceController', [
config.TaskTemplate.ContainerSpec.Image = service.Image;
}
+ if ($scope.hasChanges(service, ['Networks'])) {
+ config.Networks = _.map(
+ _.filter(service.Networks, (item) => item.Id && item.Editable),
+ (item) => ({ Target: item.Id })
+ );
+ config.TaskTemplate.Networks = config.Networks;
+ }
+
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) : [];
@@ -629,11 +659,12 @@ angular.module('portainer.docker').controller('ServiceController', [
configs: apiVersion >= 1.3 ? ConfigService.configs() : [],
availableImages: ImageService.images(),
availableLoggingDrivers: PluginService.loggingPlugins(apiVersion < 1.25),
+ availableNetworks: NetworkService.networks(true, true, apiVersion >= 1.25),
settings: SettingsService.publicSettings(),
webhooks: WebhookService.webhooks(service.Id, EndpointProvider.endpointID()),
});
})
- .then(function success(data) {
+ .then(async function success(data) {
$scope.nodes = data.nodes;
$scope.configs = data.configs;
$scope.secrets = data.secrets;
@@ -642,6 +673,36 @@ angular.module('portainer.docker').controller('ServiceController', [
$scope.availableVolumes = data.volumes;
$scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers;
$scope.isAdmin = Authentication.isAdmin();
+ $scope.availableNetworks = data.availableNetworks;
+ $scope.swarmNetworks = _.filter($scope.availableNetworks, (network) => network.Scope === 'swarm');
+
+ const serviceNetworks = _.uniqBy(_.concat($scope.service.Model.Spec.Networks || [], $scope.service.Model.Spec.TaskTemplate.Networks || []), 'Target');
+ const networks = _.filter(
+ _.map(serviceNetworks, ({ Target }) => _.find(data.availableNetworks, { Id: Target })),
+ Boolean
+ );
+
+ if (_.some($scope.service.Ports, (port) => port.PublishMode === 'ingress')) {
+ const ingressNetwork = _.find($scope.availableNetworks, (network) => network.Ingress);
+ if (ingressNetwork) {
+ networks.unshift(ingressNetwork);
+ }
+ }
+
+ $scope.service.Networks = await Promise.all(
+ _.map(networks, async (item) => {
+ let addr = '';
+ if (item.IPAM.Config.length) {
+ addr = item.IPAM.Config[0].Subnet;
+ } else {
+ const network = await NetworkService.network(item.Id);
+ addr = (network && network.IPAM && network.IPAM.Config && network.IPAM.Config.length && network.IPAM.Config[0].Subnet) || '';
+ }
+ return { Id: item.Id, Name: item.Name, Addr: addr, Editable: !item.Ingress };
+ })
+ );
+
+ originalService.Networks = angular.copy($scope.service.Networks);
if (data.webhooks.length > 0) {
var webhook = data.webhooks[0];
@@ -699,6 +760,11 @@ angular.module('portainer.docker').controller('ServiceController', [
previousServiceValues.push(name);
}
+ $scope.filterNetworks = filterNetworks;
+ function filterNetworks(networks, current) {
+ return networks.filter((network) => !network.Ingress && (network.Id === current.Id || $scope.service.Networks.every((serviceNetwork) => network.Id !== serviceNetwork.Id)));
+ }
+
function updateServiceArray(service, name) {
previousServiceValues.push(name);
service.hasChanges = true;