2018-02-01 12:27:52 +00:00
|
|
|
angular.module('portainer.docker')
|
2018-09-03 10:08:03 +00:00
|
|
|
.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) {
|
2016-09-23 04:54:58 +00:00
|
|
|
|
2018-01-09 09:40:30 +00:00
|
|
|
$scope.state = {
|
|
|
|
updateInProgress: false,
|
|
|
|
deletionInProgress: false
|
|
|
|
};
|
|
|
|
|
2016-09-23 04:54:58 +00:00
|
|
|
$scope.tasks = [];
|
2017-11-20 13:34:14 +00:00
|
|
|
$scope.availableImages = [];
|
2016-09-23 04:54:58 +00:00
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.lastVersion = 0;
|
|
|
|
|
|
|
|
var originalService = {};
|
|
|
|
var previousServiceValues = [];
|
2016-11-09 00:23:56 +00:00
|
|
|
|
2016-09-23 04:54:58 +00:00
|
|
|
$scope.renameService = function renameService(service) {
|
2016-11-09 00:23:56 +00:00
|
|
|
updateServiceAttribute(service, 'Name', service.newServiceName || service.name);
|
|
|
|
service.EditName = false;
|
|
|
|
};
|
|
|
|
$scope.changeServiceImage = function changeServiceImage(service) {
|
|
|
|
updateServiceAttribute(service, 'Image', service.newServiceImage || service.image);
|
|
|
|
service.EditImage = false;
|
|
|
|
};
|
|
|
|
$scope.scaleService = function scaleService(service) {
|
2016-12-30 23:59:20 +00:00
|
|
|
var replicas = service.newServiceReplicas === null || isNaN(service.newServiceReplicas) ? service.Replicas : service.newServiceReplicas;
|
|
|
|
updateServiceAttribute(service, 'Replicas', replicas);
|
2016-11-09 00:23:56 +00:00
|
|
|
service.EditReplicas = false;
|
|
|
|
};
|
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.goToItem = function(hash) {
|
2017-06-20 10:54:27 +00:00
|
|
|
if ($location.hash() !== hash) {
|
|
|
|
$location.hash(hash);
|
|
|
|
} else {
|
|
|
|
$anchorScroll();
|
|
|
|
}
|
2017-03-20 20:28:09 +00:00
|
|
|
};
|
|
|
|
|
2016-11-09 00:23:56 +00:00
|
|
|
$scope.addEnvironmentVariable = function addEnvironmentVariable(service) {
|
|
|
|
service.EnvironmentVariables.push({ key: '', value: '', originalValue: '' });
|
2017-03-20 20:28:09 +00:00
|
|
|
updateServiceArray(service, 'EnvironmentVariables', service.EnvironmentVariables);
|
2016-11-09 00:23:56 +00:00
|
|
|
};
|
|
|
|
$scope.removeEnvironmentVariable = function removeEnvironmentVariable(service, index) {
|
|
|
|
var removedElement = service.EnvironmentVariables.splice(index, 1);
|
2017-03-20 20:28:09 +00:00
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'EnvironmentVariables', service.EnvironmentVariables);
|
|
|
|
}
|
2016-11-09 00:23:56 +00:00
|
|
|
};
|
|
|
|
$scope.updateEnvironmentVariable = function updateEnvironmentVariable(service, variable) {
|
2017-03-20 20:28:09 +00:00
|
|
|
if (variable.value !== variable.originalValue || variable.key !== variable.originalKey) {
|
|
|
|
updateServiceArray(service, 'EnvironmentVariables', service.EnvironmentVariables);
|
|
|
|
}
|
2016-11-09 00:23:56 +00:00
|
|
|
};
|
2017-11-06 08:47:31 +00:00
|
|
|
$scope.addConfig = function addConfig(service, config) {
|
|
|
|
if (config && service.ServiceConfigs.filter(function(serviceConfig) { return serviceConfig.Id === config.Id;}).length === 0) {
|
|
|
|
service.ServiceConfigs.push({ Id: config.Id, Name: config.Name, FileName: config.Name, Uid: '0', Gid: '0', Mode: 292 });
|
|
|
|
updateServiceArray(service, 'ServiceConfigs', service.ServiceConfigs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
$scope.removeConfig = function removeSecret(service, index) {
|
|
|
|
var removedElement = service.ServiceConfigs.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'ServiceConfigs', service.ServiceConfigs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
$scope.updateConfig = function updateConfig(service) {
|
|
|
|
updateServiceArray(service, 'ServiceConfigs', service.ServiceConfigs);
|
|
|
|
};
|
2017-11-20 13:44:23 +00:00
|
|
|
$scope.addSecret = function addSecret(service, newSecret) {
|
|
|
|
if (newSecret.secret) {
|
|
|
|
var filename = newSecret.secret.Name;
|
|
|
|
if (newSecret.override) {
|
|
|
|
filename = newSecret.target;
|
|
|
|
}
|
|
|
|
if (service.ServiceSecrets.filter(function(serviceSecret) { return serviceSecret.Id === newSecret.secret.Id && serviceSecret.FileName === filename;}).length === 0) {
|
|
|
|
service.ServiceSecrets.push({ Id: newSecret.secret.Id, Name: newSecret.secret.Name, FileName: filename, Uid: '0', Gid: '0', Mode: 444 });
|
|
|
|
updateServiceArray(service, 'ServiceSecrets', service.ServiceSecrets);
|
|
|
|
}
|
2017-05-27 07:23:49 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
$scope.removeSecret = function removeSecret(service, index) {
|
|
|
|
var removedElement = service.ServiceSecrets.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'ServiceSecrets', service.ServiceSecrets);
|
|
|
|
}
|
|
|
|
};
|
2016-11-10 02:38:49 +00:00
|
|
|
$scope.addLabel = function addLabel(service) {
|
|
|
|
service.ServiceLabels.push({ key: '', value: '', originalValue: '' });
|
2017-03-20 20:28:09 +00:00
|
|
|
updateServiceArray(service, 'ServiceLabels', service.ServiceLabels);
|
2016-11-10 02:38:49 +00:00
|
|
|
};
|
|
|
|
$scope.removeLabel = function removeLabel(service, index) {
|
|
|
|
var removedElement = service.ServiceLabels.splice(index, 1);
|
2017-03-20 20:28:09 +00:00
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'ServiceLabels', service.ServiceLabels);
|
|
|
|
}
|
2016-11-10 02:38:49 +00:00
|
|
|
};
|
|
|
|
$scope.updateLabel = function updateLabel(service, label) {
|
2017-03-20 20:28:09 +00:00
|
|
|
if (label.value !== label.originalValue || label.key !== label.originalKey) {
|
|
|
|
updateServiceArray(service, 'ServiceLabels', service.ServiceLabels);
|
|
|
|
}
|
2016-11-10 02:38:49 +00:00
|
|
|
};
|
2016-11-25 06:21:06 +00:00
|
|
|
$scope.addContainerLabel = function addContainerLabel(service) {
|
|
|
|
service.ServiceContainerLabels.push({ key: '', value: '', originalValue: '' });
|
2017-03-20 20:28:09 +00:00
|
|
|
updateServiceArray(service, 'ServiceContainerLabels', service.ServiceContainerLabels);
|
2016-11-25 06:21:06 +00:00
|
|
|
};
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.removeContainerLabel = function removeLabel(service, index) {
|
2016-11-25 06:21:06 +00:00
|
|
|
var removedElement = service.ServiceContainerLabels.splice(index, 1);
|
2017-03-20 20:28:09 +00:00
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'ServiceContainerLabels', service.ServiceContainerLabels);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
$scope.updateContainerLabel = function updateLabel(service, label) {
|
|
|
|
if (label.value !== label.originalValue || label.key !== label.originalKey) {
|
|
|
|
updateServiceArray(service, 'ServiceContainerLabels', service.ServiceContainerLabels);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
$scope.addMount = function addMount(service) {
|
|
|
|
service.ServiceMounts.push({Type: 'volume', Source: '', Target: '', ReadOnly: false });
|
|
|
|
updateServiceArray(service, 'ServiceMounts', service.ServiceMounts);
|
|
|
|
};
|
|
|
|
$scope.removeMount = function removeMount(service, index) {
|
|
|
|
var removedElement = service.ServiceMounts.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'ServiceMounts', service.ServiceMounts);
|
|
|
|
}
|
|
|
|
};
|
2018-08-22 15:33:06 +00:00
|
|
|
$scope.updateMount = function updateMount(service) {
|
2017-03-20 20:28:09 +00:00
|
|
|
updateServiceArray(service, 'ServiceMounts', service.ServiceMounts);
|
|
|
|
};
|
|
|
|
$scope.addPlacementConstraint = function addPlacementConstraint(service) {
|
|
|
|
service.ServiceConstraints.push({ key: '', operator: '==', value: '' });
|
|
|
|
updateServiceArray(service, 'ServiceConstraints', service.ServiceConstraints);
|
|
|
|
};
|
|
|
|
$scope.removePlacementConstraint = function removePlacementConstraint(service, index) {
|
|
|
|
var removedElement = service.ServiceConstraints.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'ServiceConstraints', service.ServiceConstraints);
|
|
|
|
}
|
|
|
|
};
|
2018-08-22 15:33:06 +00:00
|
|
|
$scope.updatePlacementConstraint = function(service) {
|
2017-03-20 20:28:09 +00:00
|
|
|
updateServiceArray(service, 'ServiceConstraints', service.ServiceConstraints);
|
2016-11-25 06:21:06 +00:00
|
|
|
};
|
2016-11-09 00:23:56 +00:00
|
|
|
|
2017-07-10 07:33:09 +00:00
|
|
|
$scope.addPlacementPreference = function(service) {
|
|
|
|
service.ServicePreferences.push({ strategy: 'spread', value: '' });
|
|
|
|
updateServiceArray(service, 'ServicePreferences', service.ServicePreferences);
|
|
|
|
};
|
|
|
|
$scope.removePlacementPreference = function(service, index) {
|
|
|
|
var removedElement = service.ServicePreferences.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'ServicePreferences', service.ServicePreferences);
|
|
|
|
}
|
|
|
|
};
|
2018-08-22 15:33:06 +00:00
|
|
|
$scope.updatePlacementPreference = function(service) {
|
2017-07-10 07:33:09 +00:00
|
|
|
updateServiceArray(service, 'ServicePreferences', service.ServicePreferences);
|
|
|
|
};
|
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.addPublishedPort = function addPublishedPort(service) {
|
|
|
|
if (!service.Ports) {
|
|
|
|
service.Ports = [];
|
|
|
|
}
|
2017-05-04 07:43:20 +00:00
|
|
|
service.Ports.push({ PublishedPort: '', TargetPort: '', Protocol: 'tcp', PublishMode: 'ingress' });
|
2016-12-25 20:31:22 +00:00
|
|
|
};
|
2018-08-22 15:33:06 +00:00
|
|
|
$scope.updatePublishedPort = function updatePublishedPort(service) {
|
2017-03-20 20:28:09 +00:00
|
|
|
updateServiceArray(service, 'Ports', service.Ports);
|
2016-12-25 20:31:22 +00:00
|
|
|
};
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.removePortPublishedBinding = function removePortPublishedBinding(service, index) {
|
|
|
|
var removedElement = service.Ports.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'Ports', service.Ports);
|
|
|
|
}
|
2016-12-25 20:31:22 +00:00
|
|
|
};
|
|
|
|
|
2018-01-08 21:06:56 +00:00
|
|
|
$scope.addLogDriverOpt = function addLogDriverOpt(service) {
|
2017-12-22 09:05:31 +00:00
|
|
|
service.LogDriverOpts.push({ key: '', value: '', originalValue: '' });
|
|
|
|
updateServiceArray(service, 'LogDriverOpts', service.LogDriverOpts);
|
|
|
|
};
|
|
|
|
$scope.removeLogDriverOpt = function removeLogDriverOpt(service, index) {
|
|
|
|
var removedElement = service.LogDriverOpts.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'LogDriverOpts', service.LogDriverOpts);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
$scope.updateLogDriverOpt = function updateLogDriverOpt(service, variable) {
|
|
|
|
if (variable.value !== variable.originalValue || variable.key !== variable.originalKey) {
|
|
|
|
updateServiceArray(service, 'LogDriverOpts', service.LogDriverOpts);
|
|
|
|
}
|
2018-01-08 21:06:56 +00:00
|
|
|
};
|
|
|
|
$scope.updateLogDriverName = function updateLogDriverName(service) {
|
|
|
|
updateServiceArray(service, 'LogDriverName', service.LogDriverName);
|
|
|
|
};
|
2017-12-22 09:05:31 +00:00
|
|
|
|
2017-12-21 08:53:34 +00:00
|
|
|
$scope.addHostsEntry = function (service) {
|
|
|
|
if (!service.Hosts) {
|
|
|
|
service.Hosts = [];
|
|
|
|
}
|
2018-01-08 21:06:56 +00:00
|
|
|
service.Hosts.push({ hostname: '', ip: '' });
|
2017-12-21 08:53:34 +00:00
|
|
|
};
|
|
|
|
$scope.removeHostsEntry = function(service, index) {
|
|
|
|
var removedElement = service.Hosts.splice(index, 1);
|
|
|
|
if (removedElement !== null) {
|
|
|
|
updateServiceArray(service, 'Hosts', service.Hosts);
|
|
|
|
}
|
|
|
|
};
|
2018-08-22 15:33:06 +00:00
|
|
|
$scope.updateHostsEntry = function(service) {
|
2017-12-21 08:53:34 +00:00
|
|
|
updateServiceArray(service, 'Hosts', service.Hosts);
|
2018-01-08 21:06:56 +00:00
|
|
|
};
|
2017-12-21 08:53:34 +00:00
|
|
|
|
2018-09-03 10:08:03 +00:00
|
|
|
$scope.updateWebhook = function updateWebhook(service){
|
|
|
|
if ($scope.WebhookExists) {
|
|
|
|
WebhookService.deleteWebhook($scope.webhookID)
|
|
|
|
.then(function success() {
|
|
|
|
$scope.webhookURL = null;
|
|
|
|
$scope.webhookID = null;
|
|
|
|
$scope.WebhookExists = false;
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
Notifications.error('Failure', err, 'Unable to delete webhook');
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
WebhookService.createServiceWebhook(service.Id,EndpointProvider.endpointID())
|
|
|
|
.then(function success(data) {
|
|
|
|
$scope.WebhookExists = true;
|
|
|
|
$scope.webhookID = data.Id;
|
|
|
|
$scope.webhookURL = WebhookHelper.returnWebhookUrl(data.Token);
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
Notifications.error('Failure', err, 'Unable to create webhook');
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.copyWebhook = function copyWebhook(){
|
|
|
|
clipboard.copyText($scope.webhookURL);
|
|
|
|
$('#copyNotification').show();
|
|
|
|
$('#copyNotification').fadeOut(2000);
|
|
|
|
};
|
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.cancelChanges = function cancelChanges(service, keys) {
|
|
|
|
if (keys) { // clean out the keys only from the list of modified keys
|
|
|
|
keys.forEach(function(key) {
|
|
|
|
var index = previousServiceValues.indexOf(key);
|
|
|
|
if (index >= 0) {
|
|
|
|
previousServiceValues.splice(index, 1);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else { // clean out all changes
|
|
|
|
keys = Object.keys(service);
|
|
|
|
previousServiceValues = [];
|
|
|
|
}
|
|
|
|
keys.forEach(function(attribute) {
|
|
|
|
service[attribute] = originalService[attribute]; // reset service values
|
2016-09-23 04:54:58 +00:00
|
|
|
});
|
2016-11-09 00:23:56 +00:00
|
|
|
service.hasChanges = false;
|
2016-09-23 04:54:58 +00:00
|
|
|
};
|
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.hasChanges = function(service, elements) {
|
|
|
|
var hasChanges = false;
|
|
|
|
elements.forEach(function(key) {
|
|
|
|
hasChanges = hasChanges || (previousServiceValues.indexOf(key) >= 0);
|
|
|
|
});
|
|
|
|
return hasChanges;
|
|
|
|
};
|
|
|
|
|
2016-11-09 00:23:56 +00:00
|
|
|
$scope.updateService = function updateService(service) {
|
2016-09-23 04:54:58 +00:00
|
|
|
var config = ServiceHelper.serviceToConfig(service.Model);
|
2017-03-20 20:28:09 +00:00
|
|
|
config.Name = service.Name;
|
2017-07-10 07:33:09 +00:00
|
|
|
config.Labels = LabelHelper.fromKeyValueToLabelHash(service.ServiceLabels);
|
|
|
|
config.TaskTemplate.ContainerSpec.Env = ServiceHelper.translateEnvironmentVariablesToEnv(service.EnvironmentVariables);
|
|
|
|
config.TaskTemplate.ContainerSpec.Labels = LabelHelper.fromKeyValueToLabelHash(service.ServiceContainerLabels);
|
2017-03-20 20:28:09 +00:00
|
|
|
config.TaskTemplate.ContainerSpec.Image = service.Image;
|
2017-05-27 07:23:49 +00:00
|
|
|
config.TaskTemplate.ContainerSpec.Secrets = service.ServiceSecrets ? service.ServiceSecrets.map(SecretHelper.secretConfig) : [];
|
2017-11-06 08:47:31 +00:00
|
|
|
config.TaskTemplate.ContainerSpec.Configs = service.ServiceConfigs ? service.ServiceConfigs.map(ConfigHelper.configConfig) : [];
|
2017-12-21 08:53:34 +00:00
|
|
|
config.TaskTemplate.ContainerSpec.Hosts = service.Hosts ? ServiceHelper.translateHostnameIPToHostsEntries(service.Hosts) : [];
|
2018-01-08 21:06:56 +00:00
|
|
|
|
2016-11-11 02:26:19 +00:00
|
|
|
if (service.Mode === 'replicated') {
|
|
|
|
config.Mode.Replicated.Replicas = service.Replicas;
|
|
|
|
}
|
2017-03-20 20:28:09 +00:00
|
|
|
config.TaskTemplate.ContainerSpec.Mounts = service.ServiceMounts;
|
|
|
|
if (typeof config.TaskTemplate.Placement === 'undefined') {
|
|
|
|
config.TaskTemplate.Placement = {};
|
|
|
|
}
|
2017-05-04 06:57:08 +00:00
|
|
|
config.TaskTemplate.Placement.Constraints = ServiceHelper.translateKeyValueToPlacementConstraints(service.ServiceConstraints);
|
2017-07-10 07:33:09 +00:00
|
|
|
config.TaskTemplate.Placement.Preferences = ServiceHelper.translateKeyValueToPlacementPreferences(service.ServicePreferences);
|
2017-03-20 20:28:09 +00:00
|
|
|
|
2018-05-10 07:54:22 +00:00
|
|
|
if ($scope.hasChanges(service, ['LimitNanoCPUs', 'LimitMemoryBytes', 'ReservationNanoCPUs', 'ReservationMemoryBytes'])) {
|
|
|
|
// Round memory values to 0.125 and convert MB to B
|
|
|
|
var memoryLimit = (Math.round(service.LimitMemoryBytes * 8) / 8).toFixed(3);
|
|
|
|
memoryLimit *= 1024 * 1024;
|
|
|
|
var memoryReservation = (Math.round(service.ReservationMemoryBytes * 8) / 8).toFixed(3);
|
|
|
|
memoryReservation *= 1024 * 1024;
|
|
|
|
config.TaskTemplate.Resources = {
|
|
|
|
Limits: {
|
|
|
|
NanoCPUs: service.LimitNanoCPUs * 1000000000,
|
|
|
|
MemoryBytes: memoryLimit
|
|
|
|
},
|
|
|
|
Reservations: {
|
|
|
|
NanoCPUs: service.ReservationNanoCPUs * 1000000000,
|
|
|
|
MemoryBytes: memoryReservation
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2016-11-09 00:23:56 +00:00
|
|
|
|
2018-05-10 07:54:22 +00:00
|
|
|
if($scope.hasChanges(service, ['UpdateFailureAction', 'UpdateDelay', 'UpdateParallelism', 'UpdateOrder'])) {
|
|
|
|
config.UpdateConfig = {
|
|
|
|
Parallelism: service.UpdateParallelism,
|
|
|
|
Delay: ServiceHelper.translateHumanDurationToNanos(service.UpdateDelay) || 0,
|
|
|
|
FailureAction: service.UpdateFailureAction,
|
|
|
|
Order: service.UpdateOrder
|
|
|
|
};
|
|
|
|
}
|
2017-08-09 13:30:50 +00:00
|
|
|
|
2018-01-23 09:06:58 +00:00
|
|
|
if ($scope.hasChanges(service, ['RestartCondition', 'RestartDelay', 'RestartMaxAttempts', 'RestartWindow'])){
|
|
|
|
config.TaskTemplate.RestartPolicy = {
|
|
|
|
Condition: service.RestartCondition,
|
|
|
|
Delay: ServiceHelper.translateHumanDurationToNanos(service.RestartDelay) || 5000000000,
|
|
|
|
MaxAttempts: service.RestartMaxAttempts,
|
|
|
|
Window: ServiceHelper.translateHumanDurationToNanos(service.RestartWindow) || 0
|
|
|
|
};
|
|
|
|
}
|
2018-01-08 21:06:56 +00:00
|
|
|
|
2017-12-22 09:05:31 +00:00
|
|
|
config.TaskTemplate.LogDriver = null;
|
2018-01-08 21:06:56 +00:00
|
|
|
if (service.LogDriverName) {
|
2017-12-22 09:05:31 +00:00
|
|
|
config.TaskTemplate.LogDriver = { Name: service.LogDriverName };
|
|
|
|
if (service.LogDriverName !== 'none') {
|
|
|
|
var logOpts = ServiceHelper.translateKeyValueToLogDriverOpts(service.LogDriverOpts);
|
|
|
|
if (Object.keys(logOpts).length !== 0 && logOpts.constructor === Object) {
|
|
|
|
config.TaskTemplate.LogDriver.Options = logOpts;
|
|
|
|
}
|
2018-01-08 21:06:56 +00:00
|
|
|
}
|
|
|
|
}
|
2017-03-30 10:00:16 +00:00
|
|
|
|
2017-04-06 08:35:01 +00:00
|
|
|
if (service.Ports) {
|
|
|
|
service.Ports.forEach(function (binding) {
|
|
|
|
if (binding.PublishedPort === null || binding.PublishedPort === '') {
|
|
|
|
delete binding.PublishedPort;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2017-03-30 10:00:16 +00:00
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
config.EndpointSpec = {
|
2018-01-05 13:49:41 +00:00
|
|
|
Mode: (config.EndpointSpec && config.EndpointSpec.Mode) || 'vip',
|
2017-03-20 20:28:09 +00:00
|
|
|
Ports: service.Ports
|
2016-12-25 20:31:22 +00:00
|
|
|
};
|
|
|
|
|
2016-09-23 04:54:58 +00:00
|
|
|
Service.update({ id: service.Id, version: service.Version }, config, function (data) {
|
2017-09-20 06:32:19 +00:00
|
|
|
if (data.message && data.message.match(/^rpc error:/)) {
|
|
|
|
Notifications.error(data.message, 'Error');
|
|
|
|
} else {
|
|
|
|
Notifications.success('Service successfully updated', 'Service updated');
|
|
|
|
}
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.cancelChanges({});
|
2017-05-23 18:56:10 +00:00
|
|
|
initView();
|
2016-09-23 04:54:58 +00:00
|
|
|
}, function (e) {
|
2017-05-23 18:56:10 +00:00
|
|
|
Notifications.error('Failure', e, 'Unable to update service');
|
2016-09-23 04:54:58 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2017-03-30 09:22:59 +00:00
|
|
|
$scope.removeService = function() {
|
|
|
|
ModalService.confirmDeletion(
|
2017-04-25 08:20:57 +00:00
|
|
|
'Do you want to remove this service? All the containers associated to this service will be removed too.',
|
2017-03-30 09:22:59 +00:00
|
|
|
function onConfirm(confirmed) {
|
|
|
|
if(!confirmed) { return; }
|
|
|
|
removeService();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
2016-11-09 00:23:56 +00:00
|
|
|
|
2017-03-30 09:22:59 +00:00
|
|
|
function removeService() {
|
2018-01-09 09:40:30 +00:00
|
|
|
$scope.state.deletionInProgress = true;
|
2017-05-23 18:56:10 +00:00
|
|
|
ServiceService.remove($scope.service)
|
2018-09-03 10:08:03 +00:00
|
|
|
.then(function success() {
|
|
|
|
return $q.when($scope.webhookID && WebhookService.deleteWebhook($scope.webhookID));
|
|
|
|
})
|
2018-08-22 15:33:06 +00:00
|
|
|
.then(function success() {
|
2017-05-23 18:56:10 +00:00
|
|
|
Notifications.success('Service successfully deleted');
|
2018-02-01 12:27:52 +00:00
|
|
|
$state.go('docker.services', {});
|
2017-05-23 18:56:10 +00:00
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
Notifications.error('Failure', err, 'Unable to remove service');
|
2018-01-09 09:40:30 +00:00
|
|
|
})
|
|
|
|
.finally(function final() {
|
|
|
|
$scope.state.deletionInProgress = false;
|
2016-09-23 04:54:58 +00:00
|
|
|
});
|
2017-03-30 09:22:59 +00:00
|
|
|
}
|
2016-09-23 04:54:58 +00:00
|
|
|
|
2018-01-08 21:06:56 +00:00
|
|
|
$scope.forceUpdateService = function(service) {
|
|
|
|
ModalService.confirmServiceForceUpdate(
|
2018-06-20 13:53:58 +00:00
|
|
|
'Do you want to force an update of the service? All the tasks associated to the service will be recreated.',
|
|
|
|
function (result) {
|
|
|
|
if(!result) { return; }
|
|
|
|
var pullImage = false;
|
|
|
|
if (result[0]) {
|
|
|
|
pullImage = true;
|
|
|
|
}
|
|
|
|
forceUpdateService(service, pullImage);
|
2018-01-08 21:06:56 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2018-06-20 13:53:58 +00:00
|
|
|
function forceUpdateService(service, pullImage) {
|
2018-01-08 21:06:56 +00:00
|
|
|
var config = ServiceHelper.serviceToConfig(service.Model);
|
2018-06-20 13:53:58 +00:00
|
|
|
if (pullImage) {
|
|
|
|
config.TaskTemplate.ContainerSpec.Image = config.TaskTemplate.ContainerSpec.Image = ImageHelper.removeDigestFromRepository(config.TaskTemplate.ContainerSpec.Image);
|
|
|
|
}
|
|
|
|
|
2018-01-08 21:06:56 +00:00
|
|
|
// As explained in https://github.com/docker/swarmkit/issues/2364 ForceUpdate can accept a random
|
|
|
|
// value or an increment of the counter value to force an update.
|
|
|
|
config.TaskTemplate.ForceUpdate++;
|
2018-01-09 09:40:30 +00:00
|
|
|
$scope.state.updateInProgress = true;
|
2018-01-08 21:06:56 +00:00
|
|
|
ServiceService.update(service, config)
|
2018-08-22 15:33:06 +00:00
|
|
|
.then(function success() {
|
2018-01-08 21:06:56 +00:00
|
|
|
Notifications.success('Service successfully updated', service.Name);
|
|
|
|
$scope.cancelChanges({});
|
|
|
|
initView();
|
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
|
|
|
Notifications.error('Failure', err, 'Unable to force update service', service.Name);
|
2018-01-09 09:40:30 +00:00
|
|
|
})
|
|
|
|
.finally(function final() {
|
|
|
|
$scope.state.updateInProgress = false;
|
2018-01-08 21:06:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
function translateServiceArrays(service) {
|
2017-05-27 07:23:49 +00:00
|
|
|
service.ServiceSecrets = service.Secrets ? service.Secrets.map(SecretHelper.flattenSecret) : [];
|
2017-11-06 08:47:31 +00:00
|
|
|
service.ServiceConfigs = service.Configs ? service.Configs.map(ConfigHelper.flattenConfig) : [];
|
2017-07-10 07:33:09 +00:00
|
|
|
service.EnvironmentVariables = ServiceHelper.translateEnvironmentVariables(service.Env);
|
2017-12-22 09:05:31 +00:00
|
|
|
service.LogDriverOpts = ServiceHelper.translateLogDriverOptsToKeyValue(service.LogDriverOpts);
|
2017-07-10 07:33:09 +00:00
|
|
|
service.ServiceLabels = LabelHelper.fromLabelHashToKeyValue(service.Labels);
|
|
|
|
service.ServiceContainerLabels = LabelHelper.fromLabelHashToKeyValue(service.ContainerLabels);
|
2017-03-20 20:28:09 +00:00
|
|
|
service.ServiceMounts = angular.copy(service.Mounts);
|
2017-07-10 07:33:09 +00:00
|
|
|
service.ServiceConstraints = ServiceHelper.translateConstraintsToKeyValue(service.Constraints);
|
|
|
|
service.ServicePreferences = ServiceHelper.translatePreferencesToKeyValue(service.Preferences);
|
2017-12-21 08:53:34 +00:00
|
|
|
service.Hosts = ServiceHelper.translateHostsEntriesToHostnameIP(service.Hosts);
|
2017-03-20 20:28:09 +00:00
|
|
|
}
|
|
|
|
|
2017-09-20 06:32:19 +00:00
|
|
|
function transformResources(service) {
|
|
|
|
service.LimitNanoCPUs = service.LimitNanoCPUs / 1000000000 || 0;
|
|
|
|
service.ReservationNanoCPUs = service.ReservationNanoCPUs / 1000000000 || 0;
|
|
|
|
service.LimitMemoryBytes = service.LimitMemoryBytes / 1024 / 1024 || 0;
|
|
|
|
service.ReservationMemoryBytes = service.ReservationMemoryBytes / 1024 / 1024 || 0;
|
|
|
|
}
|
2017-12-06 11:04:02 +00:00
|
|
|
|
2017-11-23 09:47:39 +00:00
|
|
|
function transformDurations(service) {
|
2017-12-07 20:05:45 +00:00
|
|
|
service.RestartDelay = ServiceHelper.translateNanosToHumanDuration(service.RestartDelay) || '5s';
|
|
|
|
service.RestartWindow = ServiceHelper.translateNanosToHumanDuration(service.RestartWindow) || '0s';
|
2017-12-05 19:12:54 +00:00
|
|
|
service.UpdateDelay = ServiceHelper.translateNanosToHumanDuration(service.UpdateDelay) || '0s';
|
2018-03-27 21:05:01 +00:00
|
|
|
service.StopGracePeriod = service.StopGracePeriod ? ServiceHelper.translateNanosToHumanDuration(service.StopGracePeriod) : '';
|
2017-11-23 09:47:39 +00:00
|
|
|
}
|
2017-09-20 06:32:19 +00:00
|
|
|
|
2017-05-23 18:56:10 +00:00
|
|
|
function initView() {
|
2018-01-08 21:06:56 +00:00
|
|
|
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
2018-05-06 07:15:57 +00:00
|
|
|
var agentProxy = $scope.applicationState.endpoint.mode.agentProxy;
|
2017-12-22 09:05:31 +00:00
|
|
|
|
2018-05-10 15:17:53 +00:00
|
|
|
var service = null;
|
2017-09-21 14:00:53 +00:00
|
|
|
ServiceService.service($transition$.params().id)
|
2017-05-23 18:56:10 +00:00
|
|
|
.then(function success(data) {
|
2018-05-10 15:17:53 +00:00
|
|
|
service = data;
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.isUpdating = $scope.lastVersion >= service.Version;
|
|
|
|
if (!$scope.isUpdating) {
|
|
|
|
$scope.lastVersion = service.Version;
|
|
|
|
}
|
2016-11-09 00:23:56 +00:00
|
|
|
|
2017-09-20 06:32:19 +00:00
|
|
|
transformResources(service);
|
2017-03-20 20:28:09 +00:00
|
|
|
translateServiceArrays(service);
|
2017-11-23 09:47:39 +00:00
|
|
|
transformDurations(service);
|
2016-09-23 04:54:58 +00:00
|
|
|
$scope.service = service;
|
2017-03-20 20:28:09 +00:00
|
|
|
originalService = angular.copy(service);
|
|
|
|
|
2017-05-23 18:56:10 +00:00
|
|
|
return $q.all({
|
2018-03-29 07:41:47 +00:00
|
|
|
volumes: VolumeService.volumes(),
|
2017-10-15 17:24:40 +00:00
|
|
|
tasks: TaskService.tasks({ service: [service.Name] }),
|
2018-05-06 07:15:57 +00:00
|
|
|
containers: agentProxy ? ContainerService.containers() : [],
|
2017-05-27 07:23:49 +00:00
|
|
|
nodes: NodeService.nodes(),
|
2017-11-06 08:47:31 +00:00
|
|
|
secrets: apiVersion >= 1.25 ? SecretService.secrets() : [],
|
2017-11-20 13:34:14 +00:00
|
|
|
configs: apiVersion >= 1.30 ? ConfigService.configs() : [],
|
2017-12-22 09:05:31 +00:00
|
|
|
availableImages: ImageService.images(),
|
2018-03-29 07:41:47 +00:00
|
|
|
availableLoggingDrivers: PluginService.loggingPlugins(apiVersion < 1.25),
|
2018-09-03 10:08:03 +00:00
|
|
|
settings: SettingsService.publicSettings(),
|
|
|
|
webhooks: WebhookService.webhooks(service.Id, EndpointProvider.endpointID())
|
2016-09-23 04:54:58 +00:00
|
|
|
});
|
2017-05-23 18:56:10 +00:00
|
|
|
})
|
|
|
|
.then(function success(data) {
|
|
|
|
$scope.nodes = data.nodes;
|
2017-11-06 08:47:31 +00:00
|
|
|
$scope.configs = data.configs;
|
2017-07-24 09:59:09 +00:00
|
|
|
$scope.secrets = data.secrets;
|
2017-11-20 13:34:14 +00:00
|
|
|
$scope.availableImages = ImageService.getUniqueTagListFromImages(data.availableImages);
|
2017-12-22 09:05:31 +00:00
|
|
|
$scope.availableLoggingDrivers = data.availableLoggingDrivers;
|
2018-03-29 07:41:47 +00:00
|
|
|
$scope.availableVolumes = data.volumes;
|
|
|
|
$scope.allowBindMounts = data.settings.AllowBindMountsForRegularUsers;
|
|
|
|
var userDetails = Authentication.getUserDetails();
|
|
|
|
$scope.isAdmin = userDetails.role === 1;
|
2017-06-20 10:54:27 +00:00
|
|
|
|
2018-09-03 10:08:03 +00:00
|
|
|
if (data.webhooks.length > 0) {
|
|
|
|
var webhook = data.webhooks[0];
|
|
|
|
$scope.WebhookExists = true;
|
|
|
|
$scope.webhookID = webhook.Id;
|
|
|
|
$scope.webhookURL = WebhookHelper.returnWebhookUrl(webhook.Token);
|
|
|
|
}
|
|
|
|
|
2018-05-06 07:15:57 +00:00
|
|
|
var tasks = data.tasks;
|
|
|
|
|
|
|
|
if (agentProxy) {
|
|
|
|
var containers = data.containers;
|
|
|
|
for (var i = 0; i < tasks.length; i++) {
|
|
|
|
var task = tasks[i];
|
|
|
|
TaskHelper.associateContainerToTask(task, containers);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-10 15:17:53 +00:00
|
|
|
ServiceHelper.associateTasksToService(service, tasks);
|
|
|
|
|
2018-05-06 07:15:57 +00:00
|
|
|
$scope.tasks = data.tasks;
|
|
|
|
|
|
|
|
|
2017-09-20 06:32:19 +00:00
|
|
|
// Set max cpu value
|
|
|
|
var maxCpus = 0;
|
|
|
|
for (var n in data.nodes) {
|
|
|
|
if (data.nodes[n].CPUs && data.nodes[n].CPUs > maxCpus) {
|
|
|
|
maxCpus = data.nodes[n].CPUs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (maxCpus > 0) {
|
|
|
|
$scope.state.sliderMaxCpu = maxCpus / 1000000000;
|
|
|
|
} else {
|
|
|
|
$scope.state.sliderMaxCpu = 32;
|
|
|
|
}
|
|
|
|
|
2017-11-20 13:44:23 +00:00
|
|
|
// Default values
|
|
|
|
$scope.state.addSecret = {override: false};
|
|
|
|
|
2017-06-20 10:54:27 +00:00
|
|
|
$timeout(function() {
|
|
|
|
$anchorScroll();
|
|
|
|
});
|
2017-05-23 18:56:10 +00:00
|
|
|
})
|
|
|
|
.catch(function error(err) {
|
2017-05-27 07:23:49 +00:00
|
|
|
$scope.secrets = [];
|
2017-11-06 08:47:31 +00:00
|
|
|
$scope.configs = [];
|
2017-05-23 18:56:10 +00:00
|
|
|
Notifications.error('Failure', err, 'Unable to retrieve service details');
|
2016-09-23 04:54:58 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-20 20:28:09 +00:00
|
|
|
$scope.updateServiceAttribute = function updateServiceAttribute(service, name) {
|
|
|
|
if (service[name] !== originalService[name] || !(name in originalService)) {
|
|
|
|
service.hasChanges = true;
|
2016-11-09 00:23:56 +00:00
|
|
|
}
|
2017-03-20 20:28:09 +00:00
|
|
|
previousServiceValues.push(name);
|
|
|
|
};
|
|
|
|
|
|
|
|
function updateServiceArray(service, name) {
|
|
|
|
previousServiceValues.push(name);
|
2016-11-09 00:23:56 +00:00
|
|
|
service.hasChanges = true;
|
|
|
|
}
|
|
|
|
|
2017-05-23 18:56:10 +00:00
|
|
|
initView();
|
2016-09-23 04:54:58 +00:00
|
|
|
}]);
|