func (s *server) start() error {
	klog.Infof("Starting server %q with command %q", s.name, commandToString(s.startCommand))
	errCh := make(chan error)

	// Set up restart channels if the server is configured for restart on exit.
	var stopRestartingCh, ackStopRestartingCh chan bool
	if s.restartOnExit {
		if len(s.healthCheckUrls) == 0 {
			return fmt.Errorf("tried to start %s which has s.restartOnExit == true, but no health check urls provided", s)
		}

		stopRestartingCh = make(chan bool)
		ackStopRestartingCh = make(chan bool)

		s.stopRestartingCh = stopRestartingCh
		s.ackStopRestartingCh = ackStopRestartingCh
	}

	// This goroutine actually runs the start command for the server.
	go func() {
		defer close(errCh)

		// Create the output filename
		outPath := path.Join(framework.TestContext.ReportDir, s.outFilename)
		outfile, err := os.Create(outPath)
		if err != nil {
			errCh <- fmt.Errorf("failed to create file %q for `%s` %v", outPath, s, err)
			return
		}
		klog.Infof("Output file for server %q: %v", s.name, outfile.Name())
		defer outfile.Close()
		defer outfile.Sync()

		// Set the command to write the output file
		s.startCommand.Stdout = outfile
		s.startCommand.Stderr = outfile

		// If monitorParent is set, set Pdeathsig when starting the server.
		if s.monitorParent {
			// Death of this test process should kill the server as well.
			attrs := &syscall.SysProcAttr{}
			// Hack to set linux-only field without build tags.
			deathSigField := reflect.ValueOf(attrs).Elem().FieldByName("Pdeathsig")
			if deathSigField.IsValid() {
				deathSigField.Set(reflect.ValueOf(syscall.SIGTERM))
			} else {
				errCh <- fmt.Errorf("failed to set Pdeathsig field (non-linux build)")
				return
			}
			s.startCommand.SysProcAttr = attrs
		}

		// Start the command
		err = s.startCommand.Start()
		if err != nil {
			errCh <- fmt.Errorf("failed to run %s: %v", s, err)
			return
		}
		if !s.restartOnExit {
			klog.Infof("Waiting for server %q start command to complete", s.name)
			// If we aren't planning on restarting, ok to Wait() here to release resources.
			// Otherwise, we Wait() in the restart loop.
			err = s.startCommand.Wait()
			if err != nil {
				errCh <- fmt.Errorf("failed to run start command for server %q: %v", s.name, err)
				return
			}
		} else {
			usedStartCmd := true
			for {
				klog.Infof("Running health check for service %q", s.name)
				// Wait for an initial health check to pass, so that we are sure the server started.
				err := readinessCheck(s.name, s.healthCheckUrls, nil)
				if err != nil {
					if usedStartCmd {
						klog.Infof("Waiting for server %q start command to complete after initial health check failed", s.name)
						s.startCommand.Wait() // Release resources if necessary.
					}
					// This should not happen, immediately stop the e2eService process.
					klog.Fatalf("Restart loop readinessCheck failed for %s", s)
				} else {
					klog.Infof("Initial health check passed for service %q", s.name)
				}

				// Initial health check passed, wait until a health check fails again.
			stillAlive:
				for {
					select {
					case <-stopRestartingCh:
						ackStopRestartingCh <- true
						return
					case <-time.After(time.Second):
						for _, url := range s.healthCheckUrls {
							resp, err := http.Head(url)
							if err != nil || resp.StatusCode != http.StatusOK {
								break stillAlive
							}
						}
					}
				}

				if usedStartCmd {
					s.startCommand.Wait() // Release resources from last cmd
					usedStartCmd = false
				}
				if s.restartCommand != nil {
					// Always make a fresh copy of restartCommand before
					// running, we may have to restart multiple times
					s.restartCommand = &exec.Cmd{
						Path:        s.restartCommand.Path,
						Args:        s.restartCommand.Args,
						Env:         s.restartCommand.Env,
						Dir:         s.restartCommand.Dir,
						Stdin:       s.restartCommand.Stdin,
						Stdout:      s.restartCommand.Stdout,
						Stderr:      s.restartCommand.Stderr,
						ExtraFiles:  s.restartCommand.ExtraFiles,
						SysProcAttr: s.restartCommand.SysProcAttr,
					}
					// Run and wait for exit. This command is assumed to have
					// short duration, e.g. systemctl restart
					klog.Infof("Restarting server %q with restart command", s.name)
					err = s.restartCommand.Run()
					if err != nil {
						// This should not happen, immediately stop the e2eService process.
						klog.Fatalf("Restarting server %s with restartCommand failed. Error: %v.", s, err)
					}
				} else {
					s.startCommand = &exec.Cmd{
						Path:        s.startCommand.Path,
						Args:        s.startCommand.Args,
						Env:         s.startCommand.Env,
						Dir:         s.startCommand.Dir,
						Stdin:       s.startCommand.Stdin,
						Stdout:      s.startCommand.Stdout,
						Stderr:      s.startCommand.Stderr,
						ExtraFiles:  s.startCommand.ExtraFiles,
						SysProcAttr: s.startCommand.SysProcAttr,
					}
					klog.Infof("Restarting server %q with start command", s.name)
					err = s.startCommand.Start()
					usedStartCmd = true
					if err != nil {
						// This should not happen, immediately stop the e2eService process.
						klog.Fatalf("Restarting server %s with startCommand failed. Error: %v.", s, err)
					}
				}
			}
		}
	}()

	return readinessCheck(s.name, s.healthCheckUrls, errCh)
}
// start starts the server by running its commands, monitors it with a health
// check, and ensures that it is restarted if applicable.
//
// Note: restartOnExit == true requires len(s.healthCheckUrls) > 0 to work properly.
start starts the server by running its commands, monitors it with a health
check, and ensures that it is restarted if applicable.

restartOnExit == true requires len(s.healthCheckUrls) > 0 to work properly.
// start starts the server by running its commands monitors it with a health // check and ensures that it is restarted if applicable . // // Note : restartOnExit == true requires len ( s . healthCheckUrls ) > 0 to work properly .
func (s *server) start() error {
	klog.Infof("Starting server %q with command %q", s.name, commandToString(s.startCommand))
	errCh := make(chan error)
	var stopRestartingCh, ackStopRestartingCh chan bool
	if s.restartOnExit {
		if len(s.healthCheckUrls) == 0 {
			return fmt.Errorf("tried to start %s which has s.restartOnExit == true, but no health check urls provided", s)
		}
		stopRestartingCh = make(chan bool)
		ackStopRestartingCh = make(chan bool)
		s.stopRestartingCh = stopRestartingCh
		s.ackStopRestartingCh = ackStopRestartingCh
	}
	go func() {
		defer close(errCh)
		outPath := path.Join(framework.TestContext.ReportDir, s.outFilename)
		outfile, err := os.Create(outPath)
		if err != nil {
			errCh <- fmt.Errorf("failed to create file %q for `%s` %v", outPath, s, err)
			return
		}
		klog.Infof("Output file for server %q: %v", s.name, outfile.Name())
		defer outfile.Close()
		defer outfile.Sync()
		s.startCommand.Stdout = outfile
		s.startCommand.Stderr = outfile
		if s.monitorParent {
			attrs := &syscall.SysProcAttr{}
			deathSigField := reflect.ValueOf(attrs).Elem().FieldByName("Pdeathsig")
			if deathSigField.IsValid() {
				deathSigField.Set(reflect.ValueOf(syscall.SIGTERM))
			} else {
				errCh <- fmt.Errorf("failed to set Pdeathsig field (non-linux build)")
				return
			}
			s.startCommand.SysProcAttr = attrs
		}
		err = s.startCommand.Start()
		if err != nil {
			errCh <- fmt.Errorf("failed to run %s: %v", s, err)
			return
		}
		if !s.restartOnExit {
			klog.Infof("Waiting for server %q start command to complete", s.name)
			err = s.startCommand.Wait()
			if err != nil {
				errCh <- fmt.Errorf("failed to run start command for server %q: %v", s.name, err)
				return
			}
		} else {
			usedStartCmd := true
			for {
				klog.Infof("Running health check for service %q", s.name)
				err := readinessCheck(s.name, s.healthCheckUrls, nil)
				if err != nil {
					if usedStartCmd {
						klog.Infof("Waiting for server %q start command to complete after initial health check failed", s.name)
						s.startCommand.Wait() 
					}
					klog.Fatalf("Restart loop readinessCheck failed for %s", s)
				} else {
					klog.Infof("Initial health check passed for service %q", s.name)
				}
			stillAlive:
				for {
					select {
					case <-stopRestartingCh:
						ackStopRestartingCh <- true
						return
					case <-time.After(time.Second):
						for _, url := range s.healthCheckUrls {
							resp, err := http.Head(url)
							if err != nil || resp.StatusCode != http.StatusOK {
								break stillAlive
							}
						}
					}
				}
				if usedStartCmd {
					s.startCommand.Wait() 
					usedStartCmd = false
				}
				if s.restartCommand != nil {
					s.restartCommand = &exec.Cmd{
						Path:        s.restartCommand.Path,
						Args:        s.restartCommand.Args,
						Env:         s.restartCommand.Env,
						Dir:         s.restartCommand.Dir,
						Stdin:       s.restartCommand.Stdin,
						Stdout:      s.restartCommand.Stdout,
						Stderr:      s.restartCommand.Stderr,
						ExtraFiles:  s.restartCommand.ExtraFiles,
						SysProcAttr: s.restartCommand.SysProcAttr,
					}
					klog.Infof("Restarting server %q with restart command", s.name)
					err = s.restartCommand.Run()
					if err != nil {
						klog.Fatalf("Restarting server %s with restartCommand failed. Error: %v.", s, err)
					}
				} else {
					s.startCommand = &exec.Cmd{
						Path:        s.startCommand.Path,
						Args:        s.startCommand.Args,
						Env:         s.startCommand.Env,
						Dir:         s.startCommand.Dir,
						Stdin:       s.startCommand.Stdin,
						Stdout:      s.startCommand.Stdout,
						Stderr:      s.startCommand.Stderr,
						ExtraFiles:  s.startCommand.ExtraFiles,
						SysProcAttr: s.startCommand.SysProcAttr,
					}
					klog.Infof("Restarting server %q with start command", s.name)
					err = s.startCommand.Start()
					usedStartCmd = true
					if err != nil {
						klog.Fatalf("Restarting server %s with startCommand failed. Error: %v.", s, err)
					}
				}
			}
		}
	}()
	return readinessCheck(s.name, s.healthCheckUrls, errCh)
}
func ( s * server ) start ( ) error { klog . Infof ( " " , s . name , commandToString ( s . startCommand ) ) errCh := make ( chan error ) var stopRestartingCh , ackStopRestartingCh chan bool if s . restartOnExit { if len ( s . healthCheckUrls ) == 0 { return fmt . Errorf ( " " , s ) } stopRestartingCh = make ( chan bool ) ackStopRestartingCh = make ( chan bool ) s . stopRestartingCh = stopRestartingCh s . ackStopRestartingCh = ackStopRestartingCh } go func ( ) { defer close ( errCh ) outPath := path . Join ( framework . TestContext . ReportDir , s . outFilename ) outfile , err := os . Create ( outPath ) if err != nil { errCh <- fmt . Errorf ( " " , outPath , s , err ) return } klog . Infof ( " " , s . name , outfile . Name ( ) ) defer outfile . Close ( ) defer outfile . Sync ( ) s . startCommand . Stdout = outfile s . startCommand . Stderr = outfile if s . monitorParent { attrs := & syscall . SysProcAttr { } deathSigField := reflect . ValueOf ( attrs ) . Elem ( ) . FieldByName ( " " ) if deathSigField . IsValid ( ) { deathSigField . Set ( reflect . ValueOf ( syscall . SIGTERM ) ) } else { errCh <- fmt . Errorf ( " " ) return } s . startCommand . SysProcAttr = attrs } err = s . startCommand . Start ( ) if err != nil { errCh <- fmt . Errorf ( " " , s , err ) return } if ! s . restartOnExit { klog . Infof ( " " , s . name ) err = s . startCommand . Wait ( ) if err != nil { errCh <- fmt . Errorf ( " " , s . name , err ) return } } else { usedStartCmd := true for { klog . Infof ( " " , s . name ) err := readinessCheck ( s . name , s . healthCheckUrls , nil ) if err != nil { if usedStartCmd { klog . Infof ( " " , s . name ) s . startCommand . Wait ( ) } klog . Fatalf ( " " , s ) } else { klog . Infof ( " " , s . name ) } stillAlive : for { select { case <- stopRestartingCh : ackStopRestartingCh <- true return case <- time . After ( time . Second ) : for _ , url := range s . healthCheckUrls { resp , err := http . Head ( url ) if err != nil || resp . StatusCode != http . StatusOK { break stillAlive } } } } if usedStartCmd { s . startCommand . Wait ( ) usedStartCmd = false } if s . restartCommand != nil { s . restartCommand = & exec . Cmd { Path : s . restartCommand . Path , Args : s . restartCommand . Args , Env : s . restartCommand . Env , Dir : s . restartCommand . Dir , Stdin : s . restartCommand . Stdin , Stdout : s . restartCommand . Stdout , Stderr : s . restartCommand . Stderr , ExtraFiles : s . restartCommand . ExtraFiles , SysProcAttr : s . restartCommand . SysProcAttr , } klog . Infof ( " " , s . name ) err = s . restartCommand . Run ( ) if err != nil { klog . Fatalf ( " " , s , err ) } } else { s . startCommand = & exec . Cmd { Path : s . startCommand . Path , Args : s . startCommand . Args , Env : s . startCommand . Env , Dir : s . startCommand . Dir , Stdin : s . startCommand . Stdin , Stdout : s . startCommand . Stdout , Stderr : s . startCommand . Stderr , ExtraFiles : s . startCommand . ExtraFiles , SysProcAttr : s . startCommand . SysProcAttr , } klog . Infof ( " " , s . name ) err = s . startCommand . Start ( ) usedStartCmd = true if err != nil { klog . Fatalf ( " " , s , err ) } } } } } ( ) return readinessCheck ( s . name , s . healthCheckUrls , errCh ) }
start starts the server by running its commands, monitors it with a health
check, and ensures that it is restarted if applicable.
start starts the server by running its commands monitors it with a health check and ensures that it is restarted if applicable .
// Set up restart channels if the server is configured for restart on exit. // This goroutine actually runs the start command for the server. // Create the output filename // Set the command to write the output file // If monitorParent is set, set Pdeathsig when starting the server. // Death of this test process should kill the server as well. // Hack to set linux-only field without build tags. // Start the command // If we aren't planning on restarting, ok to Wait() here to release resources. // Otherwise, we Wait() in the restart loop. // Wait for an initial health check to pass, so that we are sure the server started. // Release resources if necessary. // This should not happen, immediately stop the e2eService process. // Initial health check passed, wait until a health check fails again. // Release resources from last cmd // Always make a fresh copy of restartCommand before // running, we may have to restart multiple times // Run and wait for exit. This command is assumed to have // short duration, e.g. systemctl restart // This should not happen, immediately stop the e2eService process. // This should not happen, immediately stop the e2eService process.