func Build(cfg *config.BuildConfig) error { // Prepare sh script t := template.New("_") template.Must(t.Parse(build_sh_src)) var w bytes.Buffer if err := t.Execute(&w, cfg); err != nil { panic(err.Error()) } build_sh := string(w.Bytes()) if cfg.Show { println(build_sh) } // Execute remotely cmd := exec.Command("ssh", cfg.Host, "sh") cmd.Stdin = bytes.NewBufferString(build_sh) // Capture stdout and stderr stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } prefix := fmt.Sprintf("%s:4build/err| ", cfg.Host) posix.ForwardStderr(prefix, stderr) if err = cmd.Start(); err != nil { return err } // Read result (remote directory of built bundle) from stdout result, _ := ioutil.ReadAll(stdout) if err = cmd.Wait(); err != nil { return err } // Fetch the built shipping bundle if err = os.MkdirAll(cfg.ShipDir, 0700); err != nil { return err } // Make ship directory if not present if err := os.MkdirAll(cfg.ShipDir, 0755); err != nil { return err } // Clean the ship directory if _, _, err = posix.Shell(`rm -f ` + cfg.ShipDir + `/*`); err != nil { return err } // Cleanup remote dir of built files r := strings.TrimSpace(string(result)) if r == "" { return errors.New("empty shipping source directory") } // Download files println("Downloading from", r) if err = posix.DownloadDir(cfg.Host, r, cfg.ShipDir); err != nil { return err } println("Download successful.") return nil }
func (c *Config) Spawn(host string, anchors ...string) (circuit.Addr, error) { cmd := exec.Command("ssh", host, "sh") stdin, err := cmd.StdinPipe() if err != nil { return nil, err } stdout, err := cmd.StdoutPipe() if err != nil { return nil, err } stderr, err := cmd.StderrPipe() if err != nil { return nil, err } //posix.ForwardStderrBatch(stderr) id := circuit.ChooseWorkerID() // Forward the stderr of the ssh process to this process' stderr posix.ForwardStderr(fmt.Sprintf("%s:kicker/err| ", id), stderr) // Start process if err := cmd.Start(); err != nil { return nil, err } defer cmd.Wait() /// Make sure that ssh does not remain zombie // Feed shell script to execute circuit binary bindir, _ := path.Split(c.Binary) if bindir == "" { panic("binary path not absolute") } var sh string if c.LibPath == "" { sh = fmt.Sprintf("cd %s\n%s=%s %s\n", bindir, config.RoleEnv, config.Daemonizer, c.Binary) } else { sh = fmt.Sprintf( "cd %s\nLD_LIBRARY_PATH=%s DYLD_LIBRARY_PATH=%s %s=%s %s\n", bindir, c.LibPath, c.LibPath, config.RoleEnv, config.Daemonizer, c.Binary) } stdin.Write([]byte(sh)) // Write worker configuration to stdin of running worker process wc := &config.WorkerConfig{ Spark: &config.SparkConfig{ ID: id, BindAddr: "", Host: host, Anchor: append(anchors, fmt.Sprintf("/host/%s", host)), }, Zookeeper: config.Config.Zookeeper, Deploy: config.Config.Deploy, } if err := json.NewEncoder(stdin).Encode(wc); err != nil { return nil, err } // Close stdin if err = stdin.Close(); err != nil { return nil, err } // Read the first two lines of stdout. They should hold the Port and PID of the runtime process. stdoutBuffer := bufio.NewReader(stdout) // First line equals PID line, err := stdoutBuffer.ReadString('\n') if err != nil { return nil, err } line = line[:len(line)-1] pid, err := strconv.Atoi(line) if err != nil { return nil, err } // Second line equals port line, err = stdoutBuffer.ReadString('\n') if err != nil { return nil, err } line = line[:len(line)-1] port, err := strconv.Atoi(line) if err != nil { return nil, err } addr, err := transport.NewAddr(id, pid, fmt.Sprintf("%s:%d", host, port)) if err != nil { return nil, err } return addr.(*transport.Addr), nil }