// runScripts is used to copy and execute a set of scripts
func (p *ResourceProvisioner) runScripts(conf *helper.SSHConfig, scripts []io.ReadCloser) error {
	// Get the SSH client config
	config, err := helper.PrepareConfig(conf)
	if err != nil {
		return err
	}

	// Wait and retry until we establish the SSH connection
	var comm *helper.SSHCommunicator
	err = retryFunc(conf.TimeoutVal, func() error {
		host := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
		comm, err = helper.New(host, config)
		return err
	})
	if err != nil {
		return err
	}

	for _, script := range scripts {
		var cmd *helper.RemoteCmd
		err := retryFunc(conf.TimeoutVal, func() error {
			if err := comm.Upload(conf.ScriptPath, script); err != nil {
				return fmt.Errorf("Failed to upload script: %v", err)
			}
			cmd = &helper.RemoteCmd{
				Command: fmt.Sprintf("chmod 0777 %s", conf.ScriptPath),
			}
			if err := comm.Start(cmd); err != nil {
				return fmt.Errorf(
					"Error chmodding script file to 0777 in remote "+
						"machine: %s", err)
			}
			cmd.Wait()

			rPipe1, wPipe1 := io.Pipe()
			rPipe2, wPipe2 := io.Pipe()
			go streamLogs(rPipe1, "stdout")
			go streamLogs(rPipe2, "stderr")

			cmd = &helper.RemoteCmd{
				Command: conf.ScriptPath,
				Stdout:  wPipe1,
				Stderr:  wPipe2,
			}
			if err := comm.Start(cmd); err != nil {
				return fmt.Errorf("Error starting script: %v", err)
			}
			return nil
		})
		if err != nil {
			return err
		}

		cmd.Wait()
		if cmd.ExitStatus != 0 {
			return fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus)
		}
	}

	return nil
}
Exemplo n.º 2
0
// runScripts is used to copy and execute a set of scripts
func (p *ResourceProvisioner) runScripts(
	o terraform.UIOutput,
	conf *helper.SSHConfig,
	scripts []io.ReadCloser) error {
	// Get the SSH client config
	config, err := helper.PrepareConfig(conf)
	if err != nil {
		return err
	}

	o.Output(fmt.Sprintf(
		"Connecting to remote host via SSH...\n"+
			"  Host: %s\n"+
			"  User: %s\n"+
			"  Password: %v\n"+
			"  Private key: %v",
		conf.Host, conf.User,
		conf.Password != "",
		conf.KeyFile != ""))

	// Wait and retry until we establish the SSH connection
	var comm *helper.SSHCommunicator
	err = retryFunc(conf.TimeoutVal, func() error {
		host := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
		comm, err = helper.New(host, config)
		if err != nil {
			o.Output(fmt.Sprintf("Connection error, will retry: %s", err))
		}

		return err
	})
	if err != nil {
		return err
	}

	o.Output("Connected! Executing scripts...")
	for _, script := range scripts {
		var cmd *helper.RemoteCmd
		outR, outW := io.Pipe()
		errR, errW := io.Pipe()
		outDoneCh := make(chan struct{})
		errDoneCh := make(chan struct{})
		go p.copyOutput(o, outR, outDoneCh)
		go p.copyOutput(o, errR, errDoneCh)

		err := retryFunc(conf.TimeoutVal, func() error {
			if err := comm.Upload(conf.ScriptPath, script); err != nil {
				return fmt.Errorf("Failed to upload script: %v", err)
			}
			cmd = &helper.RemoteCmd{
				Command: fmt.Sprintf("chmod 0777 %s", conf.ScriptPath),
			}
			if err := comm.Start(cmd); err != nil {
				return fmt.Errorf(
					"Error chmodding script file to 0777 in remote "+
						"machine: %s", err)
			}
			cmd.Wait()

			cmd = &helper.RemoteCmd{
				Command: conf.ScriptPath,
				Stdout:  outW,
				Stderr:  errW,
			}
			if err := comm.Start(cmd); err != nil {
				return fmt.Errorf("Error starting script: %v", err)
			}
			return nil
		})
		if err == nil {
			cmd.Wait()
			if cmd.ExitStatus != 0 {
				err = fmt.Errorf("Script exited with non-zero exit status: %d", cmd.ExitStatus)
			}
		}

		// Wait for output to clean up
		outW.Close()
		errW.Close()
		<-outDoneCh
		<-errDoneCh

		// If we have an error, return it out now that we've cleaned up
		if err != nil {
			return err
		}
	}

	return nil
}