mirror of https://github.com/portainer/portainer
feat(stack-details): add stack deploy prune option (#1567)
* feat(stack-details): add stack deploy prune option * fix go fmt issues * add changes proposed by reviewer * refactor deployStack as suggested by codeclimatepull/1581/head
parent
e1bf9599ef
commit
edadce359c
|
@ -54,10 +54,15 @@ func (manager *StackManager) Logout(endpoint *portainer.Endpoint) error {
|
|||
}
|
||||
|
||||
// Deploy executes the docker stack deploy command.
|
||||
func (manager *StackManager) Deploy(stack *portainer.Stack, endpoint *portainer.Endpoint) error {
|
||||
func (manager *StackManager) Deploy(stack *portainer.Stack, prune bool, endpoint *portainer.Endpoint) error {
|
||||
stackFilePath := path.Join(stack.ProjectPath, stack.EntryPoint)
|
||||
command, args := prepareDockerCommandAndArgs(manager.binaryPath, endpoint)
|
||||
|
||||
if prune {
|
||||
args = append(args, "stack", "deploy", "--prune", "--with-registry-auth", "--compose-file", stackFilePath, stack.Name)
|
||||
} else {
|
||||
args = append(args, "stack", "deploy", "--with-registry-auth", "--compose-file", stackFilePath, stack.Name)
|
||||
}
|
||||
|
||||
env := make([]string, 0)
|
||||
for _, envvar := range stack.Env {
|
||||
|
|
|
@ -37,6 +37,14 @@ type StackHandler struct {
|
|||
StackManager portainer.StackManager
|
||||
}
|
||||
|
||||
type stackDeploymentConfig struct {
|
||||
endpoint *portainer.Endpoint
|
||||
stack *portainer.Stack
|
||||
prune bool
|
||||
dockerhub *portainer.DockerHub
|
||||
registries []portainer.Registry
|
||||
}
|
||||
|
||||
// NewStackHandler returns a new instance of StackHandler.
|
||||
func NewStackHandler(bouncer *security.RequestBouncer) *StackHandler {
|
||||
h := &StackHandler{
|
||||
|
@ -78,6 +86,7 @@ type (
|
|||
putStackRequest struct {
|
||||
StackFileContent string `valid:"required"`
|
||||
Env []portainer.Pair `valid:""`
|
||||
Prune bool `valid:"-"`
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -207,7 +216,14 @@ func (handler *StackHandler) handlePostStacksStringMethod(w http.ResponseWriter,
|
|||
return
|
||||
}
|
||||
|
||||
err = handler.deployStack(endpoint, stack, dockerhub, filteredRegistries)
|
||||
config := stackDeploymentConfig{
|
||||
stack: stack,
|
||||
endpoint: endpoint,
|
||||
dockerhub: dockerhub,
|
||||
registries: filteredRegistries,
|
||||
prune: false,
|
||||
}
|
||||
err = handler.deployStack(&config)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
|
@ -334,7 +350,14 @@ func (handler *StackHandler) handlePostStacksRepositoryMethod(w http.ResponseWri
|
|||
return
|
||||
}
|
||||
|
||||
err = handler.deployStack(endpoint, stack, dockerhub, filteredRegistries)
|
||||
config := stackDeploymentConfig{
|
||||
stack: stack,
|
||||
endpoint: endpoint,
|
||||
dockerhub: dockerhub,
|
||||
registries: filteredRegistries,
|
||||
prune: false,
|
||||
}
|
||||
err = handler.deployStack(&config)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
|
@ -445,7 +468,14 @@ func (handler *StackHandler) handlePostStacksFileMethod(w http.ResponseWriter, r
|
|||
return
|
||||
}
|
||||
|
||||
err = handler.deployStack(endpoint, stack, dockerhub, filteredRegistries)
|
||||
config := stackDeploymentConfig{
|
||||
stack: stack,
|
||||
endpoint: endpoint,
|
||||
dockerhub: dockerhub,
|
||||
registries: filteredRegistries,
|
||||
prune: false,
|
||||
}
|
||||
err = handler.deployStack(&config)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
|
@ -637,7 +667,14 @@ func (handler *StackHandler) handlePutStack(w http.ResponseWriter, r *http.Reque
|
|||
return
|
||||
}
|
||||
|
||||
err = handler.deployStack(endpoint, stack, dockerhub, filteredRegistries)
|
||||
config := stackDeploymentConfig{
|
||||
stack: stack,
|
||||
endpoint: endpoint,
|
||||
dockerhub: dockerhub,
|
||||
registries: filteredRegistries,
|
||||
prune: req.Prune,
|
||||
}
|
||||
err = handler.deployStack(&config)
|
||||
if err != nil {
|
||||
httperror.WriteErrorResponse(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
|
@ -732,22 +769,22 @@ func (handler *StackHandler) handleDeleteStack(w http.ResponseWriter, r *http.Re
|
|||
}
|
||||
}
|
||||
|
||||
func (handler *StackHandler) deployStack(endpoint *portainer.Endpoint, stack *portainer.Stack, dockerhub *portainer.DockerHub, registries []portainer.Registry) error {
|
||||
func (handler *StackHandler) deployStack(config *stackDeploymentConfig) error {
|
||||
handler.stackCreationMutex.Lock()
|
||||
|
||||
err := handler.StackManager.Login(dockerhub, registries, endpoint)
|
||||
err := handler.StackManager.Login(config.dockerhub, config.registries, config.endpoint)
|
||||
if err != nil {
|
||||
handler.stackCreationMutex.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
err = handler.StackManager.Deploy(stack, endpoint)
|
||||
err = handler.StackManager.Deploy(config.stack, config.prune, config.endpoint)
|
||||
if err != nil {
|
||||
handler.stackCreationMutex.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
err = handler.StackManager.Logout(endpoint)
|
||||
err = handler.StackManager.Logout(config.endpoint)
|
||||
if err != nil {
|
||||
handler.stackCreationMutex.Unlock()
|
||||
return err
|
||||
|
|
|
@ -384,7 +384,7 @@ type (
|
|||
StackManager interface {
|
||||
Login(dockerhub *DockerHub, registries []Registry, endpoint *Endpoint) error
|
||||
Logout(endpoint *Endpoint) error
|
||||
Deploy(stack *Stack, endpoint *Endpoint) error
|
||||
Deploy(stack *Stack, prune bool, endpoint *Endpoint) error
|
||||
Remove(stack *Stack, endpoint *Endpoint) error
|
||||
}
|
||||
)
|
||||
|
|
|
@ -2976,6 +2976,10 @@ definitions:
|
|||
description: "A list of environment variables used during stack deployment"
|
||||
items:
|
||||
$ref: "#/definitions/Stack_Env"
|
||||
Prune:
|
||||
type: "boolean"
|
||||
example: false
|
||||
description: "Prune services that are no longer referenced"
|
||||
StackFileInspectResponse:
|
||||
type: "object"
|
||||
properties:
|
||||
|
|
|
@ -90,6 +90,22 @@
|
|||
<!-- !environment-variable-input-list -->
|
||||
</div>
|
||||
<!-- !environment-variables -->
|
||||
<!-- options -->
|
||||
<div class="col-sm-12 form-section-title" ng-if="applicationState.endpoint.apiVersion >= 1.27">
|
||||
Options
|
||||
</div>
|
||||
<div class="form-group" ng-if="applicationState.endpoint.apiVersion >= 1.27">
|
||||
<div class="col-sm-12">
|
||||
<label for="prune" class="control-label text-left">
|
||||
Prune services
|
||||
<portainer-tooltip position="bottom" message="Prune services that are no longer referenced."></portainer-tooltip>
|
||||
</label>
|
||||
<label class="switch" style="margin-left: 20px;">
|
||||
<input name="prune" type="checkbox" ng-model="formValues.Prune"><i></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !options -->
|
||||
<div class="col-sm-12 form-section-title">
|
||||
Actions
|
||||
</div>
|
||||
|
|
|
@ -7,14 +7,19 @@ function ($q, $scope, $state, $transition$, $document, StackService, NodeService
|
|||
publicURL: EndpointProvider.endpointPublicURL()
|
||||
};
|
||||
|
||||
$scope.formValues = {
|
||||
Prune: false
|
||||
};
|
||||
|
||||
$scope.deployStack = function () {
|
||||
// The codemirror editor does not work with ng-model so we need to retrieve
|
||||
// the value directly from the editor.
|
||||
var stackFile = $scope.editor.getValue();
|
||||
var env = FormHelper.removeInvalidEnvVars($scope.stack.Env);
|
||||
var prune = $scope.formValues.Prune;
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
StackService.updateStack($scope.stack.Id, stackFile, env)
|
||||
StackService.updateStack($scope.stack.Id, stackFile, env, prune)
|
||||
.then(function success(data) {
|
||||
Notifications.success('Stack successfully deployed');
|
||||
$state.reload();
|
||||
|
@ -37,6 +42,7 @@ function ($q, $scope, $state, $transition$, $document, StackService, NodeService
|
|||
|
||||
function initView() {
|
||||
var stackId = $transition$.params().id;
|
||||
var apiVersion = $scope.applicationState.endpoint.apiVersion;
|
||||
|
||||
StackService.stack(stackId)
|
||||
.then(function success(data) {
|
||||
|
|
|
@ -167,8 +167,8 @@ function StackServiceFactory($q, Stack, ResourceControlService, FileUploadServic
|
|||
return deferred.promise;
|
||||
};
|
||||
|
||||
service.updateStack = function(id, stackFile, env) {
|
||||
return Stack.update({ id: id, StackFileContent: stackFile, Env: env }).$promise;
|
||||
service.updateStack = function(id, stackFile, env, prune) {
|
||||
return Stack.update({ id: id, StackFileContent: stackFile, Env: env, Prune: prune}).$promise;
|
||||
};
|
||||
|
||||
return service;
|
||||
|
|
Loading…
Reference in New Issue