diff --git a/http.go b/http.go index cab5474..97c96cc 100644 --- a/http.go +++ b/http.go @@ -431,7 +431,7 @@ func (rt *Router) routeServerInstall(w http.ResponseWriter, r *http.Request, ps return } - w.WriteHeader(http.StatusNoContent) + w.WriteHeader(http.StatusAccepted) } func (rt *Router) routeServerUpdate(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { diff --git a/server/install.go b/server/install.go index 8ec9fea..fba4fe3 100644 --- a/server/install.go +++ b/server/install.go @@ -33,7 +33,28 @@ func (s *Server) Install() error { return errors.WithStack(err) } - return p.Execute() + go func(proc *InstallationProcess) { + installPath, err := proc.BeforeExecute() + if err != nil { + zap.S().Errorw( + "failed to complete BeforeExecute step of installation process", + zap.String("server", proc.Server.Uuid), + zap.Error(errors.WithStack(err)), + ) + + return + } + + if err := proc.Execute(installPath); err != nil { + zap.S().Errorw( + "failed to complete Execute step of installation process", + zap.String("server", proc.Server.Uuid), + zap.Error(errors.WithStack(err)), + ) + } + }(p) + + return nil } type InstallationProcess struct { @@ -80,7 +101,7 @@ func (ip *InstallationProcess) writeScriptToDisk() (string, error) { scanner := bufio.NewScanner(bytes.NewReader([]byte(ip.Script.Script))) for scanner.Scan() { - w.WriteString(scanner.Text()+"\n") + w.WriteString(scanner.Text() + "\n") } if err := scanner.Err(); err != nil { @@ -111,7 +132,7 @@ func (ip *InstallationProcess) pullInstallationImage() error { // Runs before the container is executed. This pulls down the required docker container image // as well as writes the installation script to the disk. This process is executed in an async // manner, if either one fails the error is returned. -func (ip *InstallationProcess) beforeExecute() (string, error) { +func (ip *InstallationProcess) BeforeExecute() (string, error) { wg := sync.WaitGroup{} wg.Add(3) @@ -163,18 +184,13 @@ func (ip *InstallationProcess) beforeExecute() (string, error) { } // Executes the installation process inside a specially created docker container. -func (ip *InstallationProcess) Execute() error { - installScriptPath, err := ip.beforeExecute() - if err != nil { - return errors.WithStack(err) - } - +func (ip *InstallationProcess) Execute(installPath string) error { ctx := context.Background() zap.S().Debugw( "creating server installer container", zap.String("server", ip.Server.Uuid), - zap.String("script_path", installScriptPath+"/install.sh"), + zap.String("script_path", installPath+"/install.sh"), ) conf := &container.Config{ @@ -203,7 +219,7 @@ func (ip *InstallationProcess) Execute() error { }, { Target: "/mnt/install", - Source: installScriptPath, + Source: installPath, Type: mount.TypeBind, ReadOnly: false, }, @@ -235,28 +251,15 @@ func (ip *InstallationProcess) Execute() error { return err } - stream, err := ip.client.ContainerAttach(ctx, r.ID, types.ContainerAttachOptions{ - Stdout: true, - Stderr: true, - Stream: true, - }) - - if err != nil { - return errors.WithStack(err) + sChann, eChann := ip.client.ContainerWait(ctx, r.ID, container.WaitConditionNotRunning) + select { + case err := <-eChann: + if err != nil { + return errors.WithStack(err) + } + case <-sChann: } - wg := sync.WaitGroup{} - wg.Add(1) - - go func() { - defer stream.Close() - defer wg.Done() - - io.Copy(os.Stdout, stream.Reader) - }() - - wg.Wait() - zap.S().Infow("completed installation process", zap.String("server", ip.Server.Uuid)) return nil