From daac1253d8ac8355b603ca11e880ed0a9700d2de Mon Sep 17 00:00:00 2001 From: Jan Saidl Date: Fri, 15 Mar 2024 12:38:38 +0100 Subject: [PATCH] z0 - fix service push, service deploy --- src/archiveClient/handler_tarFiles.go | 12 +-- src/archiveClient/handler_tarFiles_test.go | 13 ++- src/cmd/serviceDeploy.go | 105 ++++++++++++--------- src/cmd/servicePush.go | 98 ++++++++++--------- src/cmd/servicePushDeployShared.go | 7 +- src/httpClient/handler.go | 12 ++- src/i18n/en.go | 1 + src/i18n/i18n.go | 1 + src/uxHelpers/spinner.go | 39 ++++---- 9 files changed, 162 insertions(+), 126 deletions(-) diff --git a/src/archiveClient/handler_tarFiles.go b/src/archiveClient/handler_tarFiles.go index ceba87aa..8f961fc4 100644 --- a/src/archiveClient/handler_tarFiles.go +++ b/src/archiveClient/handler_tarFiles.go @@ -12,10 +12,7 @@ type File struct { ArchivePath string // path to the file in archive using / as separator } -func (h *Handler) TarFiles(w io.WriteCloser, files []File, errChan chan<- error) { - defer close(errChan) - defer w.Close() - +func (h *Handler) TarFiles(w io.Writer, files []File) error { gz := gzip.NewWriter(w) defer gz.Close() @@ -25,14 +22,13 @@ func (h *Handler) TarFiles(w io.WriteCloser, files []File, errChan chan<- error) for _, file := range files { fileInfo, err := os.Lstat(file.SourcePath) if err != nil { - errChan <- err - return + return err } err = tarFile(archive, file, fileInfo) if err != nil { - errChan <- err - return + return err } } + return nil } diff --git a/src/archiveClient/handler_tarFiles_test.go b/src/archiveClient/handler_tarFiles_test.go index 86a2b17e..477009ef 100644 --- a/src/archiveClient/handler_tarFiles_test.go +++ b/src/archiveClient/handler_tarFiles_test.go @@ -13,21 +13,20 @@ import ( func TestSymlink(t *testing.T) { archiver := New(Config{}) - errChan := make(chan error) - reader, writer := io.Pipe() - go archiver.TarFiles( - writer, + buf := bytes.NewBuffer(nil) + + require.NoError(t, archiver.TarFiles( + buf, []File{ { SourcePath: "./test/var/www/dir/subDir/file3.3.symlink.txt", ArchivePath: "dir/subDir/file3.3.symlink.txt", }, }, - errChan, - ) + )) - gz, err := gzip.NewReader(reader) + gz, err := gzip.NewReader(buf) require.NoError(t, err) b, err := io.ReadAll(gz) diff --git a/src/cmd/serviceDeploy.go b/src/cmd/serviceDeploy.go index 63452b63..cce8a116 100644 --- a/src/cmd/serviceDeploy.go +++ b/src/cmd/serviceDeploy.go @@ -3,6 +3,8 @@ package cmd import ( "context" "io" + "os" + "path" "time" "github.com/zeropsio/zcli/src/archiveClient" @@ -13,7 +15,7 @@ import ( "github.com/zeropsio/zcli/src/uxBlock/styles" "github.com/zeropsio/zcli/src/uxHelpers" "github.com/zeropsio/zerops-go/dto/input/body" - "github.com/zeropsio/zerops-go/dto/input/path" + dtoPath "github.com/zeropsio/zerops-go/dto/input/path" "github.com/zeropsio/zerops-go/types" ) @@ -53,35 +55,6 @@ func serviceDeployCmd() *cmdBuilder.Cmd { uxBlocks.PrintInfo(styles.InfoLine(i18n.T(i18n.BuildDeployCreatingPackageStart))) - files, err := arch.FindFilesByRules( - uxBlocks, - cmdData.Params.GetString("workingDir"), - cmdData.Args["pathToFileOrDir"], - ) - if err != nil { - return err - } - - var reader io.Reader - pipeReader, writer := io.Pipe() - defer pipeReader.Close() - reader = pipeReader - - tarErrChan := make(chan error, 1) - - go arch.TarFiles(writer, files, tarErrChan) - - if cmdData.Params.GetString("archiveFilePath") != "" { - packageFile, err := openPackageFile( - cmdData.Params.GetString("archiveFilePath"), - cmdData.Params.GetString("workingDir"), - ) - if err != nil { - return err - } - reader = io.TeeReader(reader, packageFile) - } - appVersion, err := createAppVersion( ctx, cmdData.RestApiClient, @@ -92,31 +65,71 @@ func serviceDeployCmd() *cmdBuilder.Cmd { return err } - // TODO - janhajek merge with sdk client? - httpClient := httpClient.New(ctx, httpClient.Config{ - HttpTimeout: time.Minute * 15, - }) - err = uxHelpers.ProcessCheckWithSpinner( ctx, cmdData.UxBlocks, []uxHelpers.Process{{ F: func(ctx context.Context) error { - if err := packageUpload(ctx, httpClient, appVersion.UploadUrl.String(), reader); err != nil { - // if an error occurred while packing the app, return that error - select { - case err := <-tarErrChan: + var size int64 + var reader io.Reader + + if cmdData.Params.GetString("archiveFilePath") != "" { + packageFile, err := openPackageFile( + cmdData.Params.GetString("archiveFilePath"), + cmdData.Params.GetString("workingDir"), + ) + if err != nil { return err - default: + } + s, err := packageFile.Stat() + if err != nil { return err } + size = s.Size() + reader = packageFile + } else { + tempFile := path.Join(os.TempDir(), appVersion.Id.Native()) + f, err := os.Create(tempFile) + if err != nil { + return err + } + defer os.Remove(tempFile) + files, err := arch.FindFilesByRules( + uxBlocks, + cmdData.Params.GetString("workingDir"), + cmdData.Args["pathToFileOrDir"], + ) + if err != nil { + return err + } + if err := arch.TarFiles(f, files); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + readFile, err := os.Open(tempFile) + if err != nil { + return err + } + defer readFile.Close() + stat, err := readFile.Stat() + if err != nil { + return err + } + size = stat.Size() + reader = readFile } - // wait for packing and saving to finish (should already be done after the package upload has finished) - if tarErr := <-tarErrChan; tarErr != nil { - return tarErr - } + // TODO - janhajek merge with sdk client? + client := httpClient.New(ctx, httpClient.Config{ + HttpTimeout: time.Minute * 15, + }) + if err := packageUpload(ctx, client, appVersion.UploadUrl.String(), reader, httpClient.ContentLength(size)); err != nil { + // if an error occurred while packing the app, return that error + return err + } return nil }, RunningMessage: i18n.T(i18n.BuildDeployUploadingPackageStart), @@ -132,7 +145,7 @@ func serviceDeployCmd() *cmdBuilder.Cmd { deployResponse, err := cmdData.RestApiClient.PutAppVersionDeploy( ctx, - path.AppVersionId{ + dtoPath.AppVersionId{ Id: appVersion.Id, }, body.PutAppVersionDeploy{ @@ -154,7 +167,7 @@ func serviceDeployCmd() *cmdBuilder.Cmd { []uxHelpers.Process{{ F: uxHelpers.CheckZeropsProcess(deployProcess.Id, cmdData.RestApiClient), RunningMessage: i18n.T(i18n.PushRunning), - ErrorMessageMessage: i18n.T(i18n.PushRunning), + ErrorMessageMessage: i18n.T(i18n.PushFailed), SuccessMessage: i18n.T(i18n.PushFinished), }}, ) diff --git a/src/cmd/servicePush.go b/src/cmd/servicePush.go index d380e5b2..da43e14c 100644 --- a/src/cmd/servicePush.go +++ b/src/cmd/servicePush.go @@ -3,6 +3,8 @@ package cmd import ( "context" "io" + "os" + "path" "time" "github.com/zeropsio/zcli/src/archiveClient" @@ -13,7 +15,7 @@ import ( "github.com/zeropsio/zcli/src/uxBlock/styles" "github.com/zeropsio/zcli/src/uxHelpers" "github.com/zeropsio/zerops-go/dto/input/body" - "github.com/zeropsio/zerops-go/dto/input/path" + dtoPath "github.com/zeropsio/zerops-go/dto/input/path" "github.com/zeropsio/zerops-go/types" ) @@ -53,31 +55,6 @@ func servicePushCmd() *cmdBuilder.Cmd { return err } - files, err := arch.FindGitFiles(cmdData.Params.GetString("workingDir")) - if err != nil { - return err - } - - var reader io.Reader - pipeReader, writer := io.Pipe() - defer pipeReader.Close() - reader = pipeReader - - tarErrChan := make(chan error, 1) - - go arch.TarFiles(writer, files, tarErrChan) - - if cmdData.Params.GetString("archiveFilePath") != "" { - packageFile, err := openPackageFile( - cmdData.Params.GetString("archiveFilePath"), - cmdData.Params.GetString("workingDir"), - ) - if err != nil { - return err - } - reader = io.TeeReader(reader, packageFile) - } - appVersion, err := createAppVersion( ctx, cmdData.RestApiClient, @@ -88,31 +65,66 @@ func servicePushCmd() *cmdBuilder.Cmd { return err } - // TODO - janhajek merge with sdk client - httpClient := httpClient.New(ctx, httpClient.Config{ - HttpTimeout: time.Minute * 15, - }) - err = uxHelpers.ProcessCheckWithSpinner( ctx, cmdData.UxBlocks, []uxHelpers.Process{{ - F: func(ctx context.Context) error { - if err := packageUpload(ctx, httpClient, appVersion.UploadUrl.String(), reader); err != nil { - // if an error occurred while packing the app, return that error - select { - case err := <-tarErrChan: + F: func(ctx context.Context) (err error) { + var size int64 + var reader io.Reader + + if cmdData.Params.GetString("archiveFilePath") != "" { + packageFile, err := openPackageFile( + cmdData.Params.GetString("archiveFilePath"), + cmdData.Params.GetString("workingDir"), + ) + if err != nil { + return err + } + s, err := packageFile.Stat() + if err != nil { + return err + } + size = s.Size() + reader = packageFile + } else { + tempFile := path.Join(os.TempDir(), appVersion.Id.Native()) + f, err := os.Create(tempFile) + if err != nil { + return err + } + defer os.Remove(tempFile) + files, err := arch.FindGitFiles(cmdData.Params.GetString("workingDir")) + if err != nil { + return err + } + if err := arch.TarFiles(f, files); err != nil { return err - default: + } + if err := f.Close(); err != nil { + return err + } + readFile, err := os.Open(tempFile) + if err != nil { return err } + defer readFile.Close() + stat, err := readFile.Stat() + if err != nil { + return err + } + size = stat.Size() + reader = readFile } - // wait for packing and saving to finish (should already be done after the package upload has finished) - if tarErr := <-tarErrChan; tarErr != nil { - return tarErr + // TODO - janhajek merge with sdk client + client := httpClient.New(ctx, httpClient.Config{ + HttpTimeout: time.Minute * 15, + }) + if err := packageUpload(ctx, client, appVersion.UploadUrl.String(), reader, httpClient.ContentLength(size)); err != nil { + // if an error occurred while packing the app, return that error + return err } - return nil }, RunningMessage: i18n.T(i18n.BuildDeployUploadingPackageStart), @@ -138,7 +150,7 @@ func servicePushCmd() *cmdBuilder.Cmd { } deployResponse, err := cmdData.RestApiClient.PutAppVersionBuildAndDeploy(ctx, - path.AppVersionId{ + dtoPath.AppVersionId{ Id: appVersion.Id, }, body.PutAppVersionBuildAndDeploy{ @@ -161,7 +173,7 @@ func servicePushCmd() *cmdBuilder.Cmd { []uxHelpers.Process{{ F: uxHelpers.CheckZeropsProcess(deployProcess.Id, cmdData.RestApiClient), RunningMessage: i18n.T(i18n.PushRunning), - ErrorMessageMessage: i18n.T(i18n.PushRunning), + ErrorMessageMessage: i18n.T(i18n.PushFailed), SuccessMessage: i18n.T(i18n.PushFinished), }}, ) diff --git a/src/cmd/servicePushDeployShared.go b/src/cmd/servicePushDeployShared.go index 7ad14209..0cb2b1d7 100644 --- a/src/cmd/servicePushDeployShared.go +++ b/src/cmd/servicePushDeployShared.go @@ -81,12 +81,13 @@ func openPackageFile(archiveFilePath string, workingDir string) (*os.File, error return file, nil } -func packageUpload(ctx context.Context, client *httpClient.Handler, uploadUrl string, reader io.Reader) error { - cephResponse, err := client.PutStream(ctx, uploadUrl, reader, httpClient.ContentType("application/gzip")) +func packageUpload(ctx context.Context, client *httpClient.Handler, uploadUrl string, reader io.Reader, options ...httpClient.Option) error { + options = append(options, httpClient.ContentType("application/gzip")) + cephResponse, err := client.PutStream(ctx, uploadUrl, reader, options...) if err != nil { return err } - if cephResponse.StatusCode != http.StatusCreated { + if cephResponse.StatusCode != http.StatusOK { return errors.New(i18n.T(i18n.BuildDeployUploadPackageFailed)) } diff --git a/src/httpClient/handler.go b/src/httpClient/handler.go index 4003c488..f000877d 100644 --- a/src/httpClient/handler.go +++ b/src/httpClient/handler.go @@ -45,8 +45,15 @@ func ContentType(contentType string) Option { } } +func ContentLength(contentLength int64) Option { + return func(cfg *optionConfig) { + cfg.contentLength = contentLength + } +} + type optionConfig struct { - headers map[string]string + contentLength int64 + headers map[string]string } func (h *Handler) PutStream(ctx context.Context, url string, body io.Reader, options ...Option) (Response, error) { @@ -54,7 +61,7 @@ func (h *Handler) PutStream(ctx context.Context, url string, body io.Reader, opt } func (h *Handler) Get(ctx context.Context, url string, options ...Option) (Response, error) { - return h.do(ctx, "GET", url, nil) + return h.do(ctx, "GET", url, nil, options...) } func (h *Handler) do(ctx context.Context, method string, url string, data []byte, options ...Option) (Response, error) { @@ -74,6 +81,7 @@ func (h *Handler) doStream(ctx context.Context, method string, url string, body client := &http.Client{Timeout: h.config.HttpTimeout} req, err := http.NewRequestWithContext(ctx, method, url, body) + req.ContentLength = cfg.contentLength if err != nil { return Response{}, err } diff --git a/src/i18n/en.go b/src/i18n/en.go index 0123fe6f..b8cc9d5b 100644 --- a/src/i18n/en.go +++ b/src/i18n/en.go @@ -138,6 +138,7 @@ var en = map[string]string{ // push PushRunning: "Push is running", PushFinished: "Push finished", + PushFailed: "Push failed", // deploy DeployHintPush: "To build your application in Zerops, use the zcli push command instead.", diff --git a/src/i18n/i18n.go b/src/i18n/i18n.go index 4e5c7908..6983be99 100644 --- a/src/i18n/i18n.go +++ b/src/i18n/i18n.go @@ -150,6 +150,7 @@ const ( // push PushRunning = "PushRunning" + PushFailed = "PushFailed" PushFinished = "PushFinished" // deploy diff --git a/src/uxHelpers/spinner.go b/src/uxHelpers/spinner.go index 2abcdcbd..c308c34c 100644 --- a/src/uxHelpers/spinner.go +++ b/src/uxHelpers/spinner.go @@ -6,6 +6,7 @@ import ( "time" "github.com/pkg/errors" + "github.com/zeropsio/zcli/src/i18n" "github.com/zeropsio/zcli/src/uxBlock" "github.com/zeropsio/zcli/src/uxBlock/styles" @@ -26,34 +27,28 @@ func ProcessCheckWithSpinner( } stopFunc := uxBlocks.RunSpinners(ctx, spinners) + defer stopFunc() var returnErr error - var once sync.Once - wg := sync.WaitGroup{} + var wg sync.WaitGroup for i := range processList { wg.Add(1) - go func(i int) { + go func(process Process, spinner *uxBlock.Spinner) { defer wg.Done() - process := processList[i] - err := process.F(ctx) if err != nil { - spinners[i].Finish(styles.ErrorLine(process.ErrorMessageMessage)) - stopFunc() - + spinner.Finish(styles.ErrorLine(process.ErrorMessageMessage)) once.Do(func() { returnErr = err }) return } - spinners[i].Finish(styles.SuccessLine(process.SuccessMessage)) - }(i) + spinner.Finish(styles.SuccessLine(process.SuccessMessage)) + }(processList[i], spinners[i]) } - wg.Wait() - stopFunc() return returnErr } @@ -90,12 +85,22 @@ func CheckZeropsProcess( processStatus := processOutput.Status - if processStatus == enum.ProcessStatusEnumFinished { + switch processStatus { + case enum.ProcessStatusEnumPending: + continue + case enum.ProcessStatusEnumRunning: + continue + case enum.ProcessStatusEnumFinished: return nil - } - - if !(processStatus == enum.ProcessStatusEnumRunning || - processStatus == enum.ProcessStatusEnumPending) { + case enum.ProcessStatusEnumRollbacking: + fallthrough + case enum.ProcessStatusEnumCanceling: + fallthrough + case enum.ProcessStatusEnumFailed: + fallthrough + case enum.ProcessStatusEnumCanceled: + fallthrough + default: return errors.Errorf(i18n.T(i18n.ProcessInvalidState), processId) } }