mirror of
https://github.com/portainer/portainer.git
synced 2025-07-23 15:29:42 +02:00
feat(services): add the ability to pull latest image when updating a … (#1984)
* feat(services): add the ability to pull latest image when updating a service * feat(services): update version header value * refactor(services): remove TODO * feat(services): rollback version header value to 1.29
This commit is contained in:
parent
0da9e564b9
commit
61c74e22f0
6 changed files with 65 additions and 24 deletions
|
@ -1,6 +1,6 @@
|
||||||
angular.module('portainer.docker')
|
angular.module('portainer.docker')
|
||||||
.controller('ServicesDatatableActionsController', ['$state', 'ServiceService', 'ServiceHelper', 'Notifications', 'ModalService',
|
.controller('ServicesDatatableActionsController', ['$state', 'ServiceService', 'ServiceHelper', 'Notifications', 'ModalService', 'ImageHelper',
|
||||||
function ($state, ServiceService, ServiceHelper, Notifications, ModalService) {
|
function ($state, ServiceService, ServiceHelper, Notifications, ModalService, ImageHelper) {
|
||||||
|
|
||||||
this.scaleAction = function scaleService(service) {
|
this.scaleAction = function scaleService(service) {
|
||||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
var config = ServiceHelper.serviceToConfig(service.Model);
|
||||||
|
@ -17,16 +17,6 @@ function ($state, ServiceService, ServiceHelper, Notifications, ModalService) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateAction = function(selectedItems) {
|
|
||||||
ModalService.confirmServiceForceUpdate(
|
|
||||||
'Do you want to force update of selected service(s)? All the tasks associated to the selected service(s) will be recreated.',
|
|
||||||
function onConfirm(confirmed) {
|
|
||||||
if(!confirmed) { return; }
|
|
||||||
forceUpdateServices(selectedItems);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.removeAction = function(selectedItems) {
|
this.removeAction = function(selectedItems) {
|
||||||
ModalService.confirmDeletion(
|
ModalService.confirmDeletion(
|
||||||
'Do you want to remove the selected service(s)? All the containers associated to the selected service(s) will be removed too.',
|
'Do you want to remove the selected service(s)? All the containers associated to the selected service(s) will be removed too.',
|
||||||
|
@ -37,10 +27,28 @@ function ($state, ServiceService, ServiceHelper, Notifications, ModalService) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function forceUpdateServices(services) {
|
this.updateAction = function(selectedItems) {
|
||||||
|
ModalService.confirmServiceForceUpdate(
|
||||||
|
'Do you want to force an update of the selected service(s)? All the tasks associated to the selected service(s) will be recreated.',
|
||||||
|
function (result) {
|
||||||
|
if(!result) { return; }
|
||||||
|
var pullImage = false;
|
||||||
|
if (result[0]) {
|
||||||
|
pullImage = true;
|
||||||
|
}
|
||||||
|
forceUpdateServices(selectedItems, pullImage);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
function forceUpdateServices(services, pullImage) {
|
||||||
var actionCount = services.length;
|
var actionCount = services.length;
|
||||||
angular.forEach(services, function (service) {
|
angular.forEach(services, function (service) {
|
||||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
var config = ServiceHelper.serviceToConfig(service.Model);
|
||||||
|
if (pullImage) {
|
||||||
|
config.TaskTemplate.ContainerSpec.Image = ImageHelper.removeDigestFromRepository(config.TaskTemplate.ContainerSpec.Image);
|
||||||
|
}
|
||||||
|
|
||||||
// As explained in https://github.com/docker/swarmkit/issues/2364 ForceUpdate can accept a random
|
// 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.
|
// value or an increment of the counter value to force an update.
|
||||||
config.TaskTemplate.ForceUpdate++;
|
config.TaskTemplate.ForceUpdate++;
|
||||||
|
|
|
@ -55,5 +55,9 @@ angular.module('portainer.docker')
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helper.removeDigestFromRepository = function(repository) {
|
||||||
|
return repository.split('@sha')[0];
|
||||||
|
};
|
||||||
|
|
||||||
return helper;
|
return helper;
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -49,7 +49,7 @@ function ServiceViewModel(data, runningTasks, allTasks, nodes) {
|
||||||
this.LogDriverName = '';
|
this.LogDriverName = '';
|
||||||
this.LogDriverOpts = [];
|
this.LogDriverOpts = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Constraints = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Constraints || [] : [];
|
this.Constraints = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Constraints || [] : [];
|
||||||
this.Preferences = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Preferences || [] : [];
|
this.Preferences = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Preferences || [] : [];
|
||||||
this.Platforms = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Platforms || [] : [];
|
this.Platforms = data.Spec.TaskTemplate.Placement ? data.Spec.TaskTemplate.Placement.Platforms || [] : [];
|
||||||
|
|
|
@ -10,10 +10,24 @@ function ServiceFactory($resource, API_ENDPOINT_ENDPOINTS, EndpointProvider, Htt
|
||||||
query: { method: 'GET', isArray: true, params: {filters: '@filters'} },
|
query: { method: 'GET', isArray: true, params: {filters: '@filters'} },
|
||||||
create: {
|
create: {
|
||||||
method: 'POST', params: {action: 'create'},
|
method: 'POST', params: {action: 'create'},
|
||||||
headers: { 'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader },
|
headers: {
|
||||||
|
'X-Registry-Auth': HttpRequestHelper.registryAuthenticationHeader,
|
||||||
|
// TODO: This is a temporary work-around that allows us to leverage digest pinning on
|
||||||
|
// the Docker daemon side. It has been moved client-side since Docker API version > 1.29.
|
||||||
|
// We should introduce digest pinning in Portainer as well.
|
||||||
|
'version': '1.29'
|
||||||
|
},
|
||||||
ignoreLoadingBar: true
|
ignoreLoadingBar: true
|
||||||
},
|
},
|
||||||
update: { method: 'POST', params: {id: '@id', action: 'update', version: '@version'} },
|
update: {
|
||||||
|
method: 'POST', params: { id: '@id', action: 'update', version: '@version' },
|
||||||
|
headers: {
|
||||||
|
// TODO: This is a temporary work-around that allows us to leverage digest pinning on
|
||||||
|
// the Docker daemon side. It has been moved client-side since Docker API version > 1.29.
|
||||||
|
// We should introduce digest pinning in Portainer as well.
|
||||||
|
'version': '1.29'
|
||||||
|
}
|
||||||
|
},
|
||||||
remove: { method: 'DELETE', params: {id: '@id'} },
|
remove: { method: 'DELETE', params: {id: '@id'} },
|
||||||
logs: {
|
logs: {
|
||||||
method: 'GET', params: { id: '@id', action: 'logs' },
|
method: 'GET', params: { id: '@id', action: 'logs' },
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('portainer.docker')
|
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',
|
.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',
|
||||||
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) {
|
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) {
|
||||||
|
|
||||||
$scope.state = {
|
$scope.state = {
|
||||||
updateInProgress: false,
|
updateInProgress: false,
|
||||||
|
@ -354,16 +354,24 @@ function ($q, $scope, $transition$, $state, $location, $timeout, $anchorScroll,
|
||||||
|
|
||||||
$scope.forceUpdateService = function(service) {
|
$scope.forceUpdateService = function(service) {
|
||||||
ModalService.confirmServiceForceUpdate(
|
ModalService.confirmServiceForceUpdate(
|
||||||
'Do you want to force update this service? All the tasks associated to the selected service(s) will be recreated.',
|
'Do you want to force an update of the service? All the tasks associated to the service will be recreated.',
|
||||||
function onConfirm(confirmed) {
|
function (result) {
|
||||||
if(!confirmed) { return; }
|
if(!result) { return; }
|
||||||
forceUpdateService(service);
|
var pullImage = false;
|
||||||
|
if (result[0]) {
|
||||||
|
pullImage = true;
|
||||||
|
}
|
||||||
|
forceUpdateService(service, pullImage);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function forceUpdateService(service) {
|
function forceUpdateService(service, pullImage) {
|
||||||
var config = ServiceHelper.serviceToConfig(service.Model);
|
var config = ServiceHelper.serviceToConfig(service.Model);
|
||||||
|
if (pullImage) {
|
||||||
|
config.TaskTemplate.ContainerSpec.Image = config.TaskTemplate.ContainerSpec.Image = ImageHelper.removeDigestFromRepository(config.TaskTemplate.ContainerSpec.Image);
|
||||||
|
}
|
||||||
|
|
||||||
// As explained in https://github.com/docker/swarmkit/issues/2364 ForceUpdate can accept a random
|
// 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.
|
// value or an increment of the counter value to force an update.
|
||||||
config.TaskTemplate.ForceUpdate++;
|
config.TaskTemplate.ForceUpdate++;
|
||||||
|
|
|
@ -157,9 +157,16 @@ angular.module('portainer.app')
|
||||||
};
|
};
|
||||||
|
|
||||||
service.confirmServiceForceUpdate = function(message, callback) {
|
service.confirmServiceForceUpdate = function(message, callback) {
|
||||||
service.confirm({
|
service.customPrompt({
|
||||||
title: 'Are you sure ?',
|
title: 'Are you sure ?',
|
||||||
message: message,
|
message: message,
|
||||||
|
inputType: 'checkbox',
|
||||||
|
inputOptions: [
|
||||||
|
{
|
||||||
|
text: 'Pull latest image version<i></i>',
|
||||||
|
value: '1'
|
||||||
|
}
|
||||||
|
],
|
||||||
buttons: {
|
buttons: {
|
||||||
confirm: {
|
confirm: {
|
||||||
label: 'Update',
|
label: 'Update',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue