From 182bf10b91b8be9db3cf45c528746a0cd4ed5d19 Mon Sep 17 00:00:00 2001 From: Hui Date: Wed, 1 Sep 2021 18:32:54 +1200 Subject: [PATCH] fix(k8s): file content overridden when deployment failed with compose format EE-1556 --- .../handler/stacks/update_kubernetes_stack.go | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/api/http/handler/stacks/update_kubernetes_stack.go b/api/http/handler/stacks/update_kubernetes_stack.go index d39d250d9..18753d8ba 100644 --- a/api/http/handler/stacks/update_kubernetes_stack.go +++ b/api/http/handler/stacks/update_kubernetes_stack.go @@ -1,7 +1,11 @@ package stacks import ( + "fmt" + "io/ioutil" "net/http" + "os" + "path" "strconv" "github.com/asaskevich/govalidator" @@ -9,6 +13,7 @@ import ( httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/filesystem" gittypes "github.com/portainer/portainer/api/git/types" k "github.com/portainer/portainer/api/kubernetes" ) @@ -90,12 +95,16 @@ func (handler *Handler) updateKubernetesStack(r *http.Request, stack *portainer. return &httperror.HandlerError{StatusCode: http.StatusBadRequest, Message: "Invalid request payload", Err: err} } - stackFolder := strconv.Itoa(int(stack.ID)) - projectPath, err := handler.FileService.StoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent)) - if err != nil { - return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: "Unable to persist Kubernetes manifest file on disk", Err: err} + tempFileDir, _ := ioutil.TempDir("", "kub_file_content") + defer os.RemoveAll(tempFileDir) + + if err := filesystem.WriteToFile(path.Join(tempFileDir, stack.EntryPoint), []byte(payload.StackFileContent)); err != nil { + return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: "Failed to persist deployment file in a temp directory", Err: err} } - stack.ProjectPath = projectPath + + //use temp dir as the stack project path for deployment + //so if the deployment failed, the original file won't be over-written + stack.ProjectPath = tempFileDir _, err = handler.deployKubernetesStack(r, endpoint, stack, k.KubeAppLabels{ StackID: int(stack.ID), @@ -108,5 +117,17 @@ func (handler *Handler) updateKubernetesStack(r *http.Request, stack *portainer. return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: "Unable to deploy Kubernetes stack via file content", Err: err} } + stackFolder := strconv.Itoa(int(stack.ID)) + projectPath, err := handler.FileService.StoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent)) + if err != nil { + fileType := "Manifest" + if stack.IsComposeFormat { + fileType = "Compose" + } + errMsg := fmt.Sprintf("Unable to persist Kubernetes %s file on disk", fileType) + return &httperror.HandlerError{StatusCode: http.StatusInternalServerError, Message: errMsg, Err: err} + } + stack.ProjectPath = projectPath + return nil }