mirror of
https://github.com/portainer/portainer.git
synced 2025-07-23 07:19:41 +02:00
feat(stacks): migrate stack data from previous portainer version
This commit is contained in:
parent
5e73a49473
commit
e1345416b4
7 changed files with 81 additions and 17 deletions
|
@ -1,5 +1,7 @@
|
||||||
package bolt
|
package bolt
|
||||||
|
|
||||||
|
import "github.com/portainer/portainer"
|
||||||
|
|
||||||
func (m *Migrator) updateEndpointsToVersion12() error {
|
func (m *Migrator) updateEndpointsToVersion12() error {
|
||||||
legacyEndpoints, err := m.EndpointService.Endpoints()
|
legacyEndpoints, err := m.EndpointService.Endpoints()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -35,3 +37,21 @@ func (m *Migrator) updateEndpointGroupsToVersion12() error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Migrator) updateStacksToVersion12() error {
|
||||||
|
legacyStacks, err := m.StackService.Stacks()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, stack := range legacyStacks {
|
||||||
|
stack.Type = portainer.DockerSwarmStack
|
||||||
|
|
||||||
|
err = m.StackService.UpdateStack(stack.ID, &stack)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -4,27 +4,30 @@ import "github.com/portainer/portainer"
|
||||||
|
|
||||||
// Migrator defines a service to migrate data after a Portainer version update.
|
// Migrator defines a service to migrate data after a Portainer version update.
|
||||||
type Migrator struct {
|
type Migrator struct {
|
||||||
UserService *UserService
|
|
||||||
EndpointService *EndpointService
|
|
||||||
EndpointGroupService *EndpointGroupService
|
|
||||||
ResourceControlService *ResourceControlService
|
|
||||||
SettingsService *SettingsService
|
|
||||||
VersionService *VersionService
|
|
||||||
CurrentDBVersion int
|
CurrentDBVersion int
|
||||||
store *Store
|
store *Store
|
||||||
|
|
||||||
|
EndpointGroupService *EndpointGroupService
|
||||||
|
EndpointService *EndpointService
|
||||||
|
ResourceControlService *ResourceControlService
|
||||||
|
SettingsService *SettingsService
|
||||||
|
StackService *StackService
|
||||||
|
UserService *UserService
|
||||||
|
VersionService *VersionService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMigrator creates a new Migrator.
|
// NewMigrator creates a new Migrator.
|
||||||
func NewMigrator(store *Store, version int) *Migrator {
|
func NewMigrator(store *Store, version int) *Migrator {
|
||||||
return &Migrator{
|
return &Migrator{
|
||||||
UserService: store.UserService,
|
|
||||||
EndpointService: store.EndpointService,
|
|
||||||
EndpointGroupService: store.EndpointGroupService,
|
|
||||||
ResourceControlService: store.ResourceControlService,
|
|
||||||
SettingsService: store.SettingsService,
|
|
||||||
VersionService: store.VersionService,
|
|
||||||
CurrentDBVersion: version,
|
CurrentDBVersion: version,
|
||||||
store: store,
|
store: store,
|
||||||
|
EndpointGroupService: store.EndpointGroupService,
|
||||||
|
EndpointService: store.EndpointService,
|
||||||
|
ResourceControlService: store.ResourceControlService,
|
||||||
|
SettingsService: store.SettingsService,
|
||||||
|
StackService: store.StackService,
|
||||||
|
UserService: store.UserService,
|
||||||
|
VersionService: store.VersionService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +125,7 @@ func (m *Migrator) Migrate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Portainer 1.17.1-dev
|
||||||
if m.CurrentDBVersion < 12 {
|
if m.CurrentDBVersion < 12 {
|
||||||
err := m.updateEndpointsToVersion12()
|
err := m.updateEndpointsToVersion12()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -132,6 +136,11 @@ func (m *Migrator) Migrate() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = m.updateStacksToVersion12()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := m.VersionService.StoreDBVersion(portainer.DBVersion)
|
err := m.VersionService.StoreDBVersion(portainer.DBVersion)
|
||||||
|
|
|
@ -46,7 +46,20 @@ func (handler *Handler) stackDelete(w http.ResponseWriter, r *http.Request) *htt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
endpoint, err := handler.EndpointService.Endpoint(stack.EndpointID)
|
// TODO: this is a work-around for stacks created with Portainer version >= 1.17.1
|
||||||
|
// The EndpointID property is not available for these stacks, this API endpoint
|
||||||
|
// can use the optional EndpointID query parameter to set a valid endpoint identifier to be
|
||||||
|
// used in the context of this request.
|
||||||
|
endpointID, err := request.RetrieveNumericQueryParameter(r, "endpointId", true)
|
||||||
|
if err != nil {
|
||||||
|
return &httperror.HandlerError{http.StatusBadRequest, "Invalid query parameter: endpointId", err}
|
||||||
|
}
|
||||||
|
endpointIdentifier := stack.EndpointID
|
||||||
|
if endpointID != 0 {
|
||||||
|
endpointIdentifier = portainer.EndpointID(endpointID)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint, err := handler.EndpointService.Endpoint(endpointIdentifier)
|
||||||
if err == portainer.ErrEndpointNotFound {
|
if err == portainer.ErrEndpointNotFound {
|
||||||
return &httperror.HandlerError{http.StatusNotFound, "Unable to find the endpoint associated to the stack inside the database", err}
|
return &httperror.HandlerError{http.StatusNotFound, "Unable to find the endpoint associated to the stack inside the database", err}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (payload *updateSwarmStackPayload) Validate(r *http.Request) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT request on /api/stacks/:id
|
// PUT request on /api/stacks/:id?endpointId=<endpointId>
|
||||||
func (handler *Handler) stackUpdate(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
func (handler *Handler) stackUpdate(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
|
||||||
stackID, err := request.RetrieveRouteVariableValue(r, "id")
|
stackID, err := request.RetrieveRouteVariableValue(r, "id")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -66,6 +66,17 @@ func (handler *Handler) stackUpdate(w http.ResponseWriter, r *http.Request) *htt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this is a work-around for stacks created with Portainer version >= 1.17.1
|
||||||
|
// The EndpointID property is not available for these stacks, this API endpoint
|
||||||
|
// can use the optional EndpointID query parameter to associate a valid endpoint identifier to the stack.
|
||||||
|
endpointID, err := request.RetrieveNumericQueryParameter(r, "endpointId", true)
|
||||||
|
if err != nil {
|
||||||
|
return &httperror.HandlerError{http.StatusBadRequest, "Invalid query parameter: endpointId", err}
|
||||||
|
}
|
||||||
|
if endpointID != int(stack.EndpointID) {
|
||||||
|
stack.EndpointID = portainer.EndpointID(endpointID)
|
||||||
|
}
|
||||||
|
|
||||||
endpoint, err := handler.EndpointService.Endpoint(stack.EndpointID)
|
endpoint, err := handler.EndpointService.Endpoint(stack.EndpointID)
|
||||||
if err == portainer.ErrEndpointNotFound {
|
if err == portainer.ErrEndpointNotFound {
|
||||||
return &httperror.HandlerError{http.StatusNotFound, "Unable to find the endpoint associated to the stack inside the database", err}
|
return &httperror.HandlerError{http.StatusNotFound, "Unable to find the endpoint associated to the stack inside the database", err}
|
||||||
|
|
|
@ -3,6 +3,7 @@ function StackViewModel(data) {
|
||||||
this.Type = data.Type;
|
this.Type = data.Type;
|
||||||
this.Name = data.Name;
|
this.Name = data.Name;
|
||||||
this.Checked = false;
|
this.Checked = false;
|
||||||
|
this.EndpointId = data.EndpointId;
|
||||||
this.Env = data.Env ? data.Env : [];
|
this.Env = data.Env ? data.Env : [];
|
||||||
if (data.ResourceControl && data.ResourceControl.Id !== 0) {
|
if (data.ResourceControl && data.ResourceControl.Id !== 0) {
|
||||||
this.ResourceControl = new ResourceControlViewModel(data.ResourceControl);
|
this.ResourceControl = new ResourceControlViewModel(data.ResourceControl);
|
||||||
|
|
|
@ -174,8 +174,8 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
service.updateStack = function(id, stackFile, env, prune) {
|
service.updateStack = function(stack, stackFile, env, prune) {
|
||||||
return Stack.update({ id: id, StackFileContent: stackFile, Env: env, Prune: prune}).$promise;
|
return Stack.update({ endpointId: stack.EndpointId }, { id: stack.Id, StackFileContent: stackFile, Env: env, Prune: prune }).$promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
service.createComposeStackFromFileUpload = function(name, stackFile, endpointId) {
|
service.createComposeStackFromFileUpload = function(name, stackFile, endpointId) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
angular.module('portainer.app')
|
angular.module('portainer.app')
|
||||||
.controller('StackController', ['$q', '$scope', '$state', '$transition$', 'StackService', 'NodeService', 'ServiceService', 'TaskService', 'ContainerService', 'ServiceHelper', 'TaskHelper', 'Notifications', 'FormHelper',
|
.controller('StackController', ['$q', '$scope', '$state', '$transition$', 'StackService', 'NodeService', 'ServiceService', 'TaskService', 'ContainerService', 'ServiceHelper', 'TaskHelper', 'Notifications', 'FormHelper', 'EndpointProvider',
|
||||||
function ($q, $scope, $state, $transition$, StackService, NodeService, ServiceService, TaskService, ContainerService, ServiceHelper, TaskHelper, Notifications, FormHelper) {
|
function ($q, $scope, $state, $transition$, StackService, NodeService, ServiceService, TaskService, ContainerService, ServiceHelper, TaskHelper, Notifications, FormHelper, EndpointProvider) {
|
||||||
|
|
||||||
$scope.state = {
|
$scope.state = {
|
||||||
actionInProgress: false,
|
actionInProgress: false,
|
||||||
|
@ -15,9 +15,19 @@ function ($q, $scope, $state, $transition$, StackService, NodeService, ServiceSe
|
||||||
var stackFile = $scope.stackFileContent;
|
var stackFile = $scope.stackFileContent;
|
||||||
var env = FormHelper.removeInvalidEnvVars($scope.stack.Env);
|
var env = FormHelper.removeInvalidEnvVars($scope.stack.Env);
|
||||||
var prune = $scope.formValues.Prune;
|
var prune = $scope.formValues.Prune;
|
||||||
|
var stack = $scope.stack;
|
||||||
|
|
||||||
|
// TODO: this is a work-around for stacks created with Portainer version >= 1.17.1
|
||||||
|
// The EndpointID property is not available for these stacks, we can pass
|
||||||
|
// the current endpoint identifier as a part of the update request. It will be used if
|
||||||
|
// the EndpointID property is not defined on the stack.
|
||||||
|
var endpointId = EndpointProvider.endpointID();
|
||||||
|
if (stack.EndpointId === 0) {
|
||||||
|
stack.EndpointId = endpointId;
|
||||||
|
}
|
||||||
|
|
||||||
$scope.state.actionInProgress = true;
|
$scope.state.actionInProgress = true;
|
||||||
StackService.updateStack($scope.stack.Id, stackFile, env, prune)
|
StackService.updateStack(stack, stackFile, env, prune)
|
||||||
.then(function success(data) {
|
.then(function success(data) {
|
||||||
Notifications.success('Stack successfully deployed');
|
Notifications.success('Stack successfully deployed');
|
||||||
$state.reload();
|
$state.reload();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue