Don't block the HTTP request while waiting on the installation
This commit is contained in:
		
							parent
							
								
									6ef2773c01
								
							
						
					
					
						commit
						5350a2d5a5
					
				
							
								
								
									
										2
									
								
								http.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user