func (res *smResource) Provision(l logger.Logger) (err error) { l = l.Tag(res.ID) for _, pkg := range res.Packages { if err := pkg.Provision(l, res.client); err != nil { return err } } return nil }
func (lsess *loggedSession) readStream(l logger.Logger, stream io.Reader) { defer lsess.wg.Done() sc := bufio.NewScanner(stream) for sc.Scan() { l.Printf(sc.Text()) } if err := sc.Err(); err != nil { l.Printf("failed scanning stderr: %s", err) } }
func (res *smResource) Prepare(l logger.Logger) error { l = l.Tag(res.ID) if err := res.initializeClient(); err != nil { return err } for _, pkg := range res.Packages { if err := pkg.Prepare(res.client, res.Attributes); err != nil { return err } } return nil }
func newLoggedSession(l logger.Logger, sess Session) (Session, error) { s := &loggedSession{Session: sess, wg: new(sync.WaitGroup)} stdout, err := s.Session.StdoutPipe() if err != nil { return nil, errors.Wrap(err, "failed to build stdout pipe") } stderr, err := s.Session.StderrPipe() if err != nil { return nil, errors.Wrap(err, "failed to build stderr pipe") } s.wg.Add(2) go s.readStream(l.Tag("stdout"), stdout) go s.readStream(l.Tag("stderr"), stderr) return s, nil }
func (a *execJenkinsArtifactCmd) Exec(l logger.Logger, client connection.Client) error { sess, err := client.NewLoggedSession(l) if err != nil { return err } defer sess.Close() l.Printf("downloading file %q from %q", a.Target, a.url) setFilePerms := "" // TODO is possible to set only one of the both? if a.Owner != "" && a.Umask != "" { setFilePerms = " && chown " + a.Owner + " %[1]s && chmod " + a.Umask + " %[1]s" } cmd := fmt.Sprintf(`bash -c "{ dir=$(dirname %[1]s); test -d \${dir} || mkdir -p \${dir}; } && curl -sSL %[2]s -o %[1]s`+setFilePerms+`"`, a.Target, a.url) if err := sess.Start(cmd); err != nil { return err } return sess.Wait() }
func (a *execWriteFileCmd) Exec(l logger.Logger, clients connection.Client) error { r, err := a.read() if err != nil { return err } defer r.Close() sess, err := clients.NewLoggedSession(l) if err != nil { return err } defer sess.Close() stdin, err := sess.StdinPipe() if err != nil { return errors.Wrap(err, "failed to receive stdin pipe") } l.Printf("writing file %q", a.Target) setFilePerms := "" // TODO is possible to set only one of the both? if a.Owner != "" && a.Umask != "" { setFilePerms = " && chown " + a.Owner + " %[1]s && chmod " + a.Umask + " %[1]s" } cmd := fmt.Sprintf(`bash -c "{ dir=$(dirname %[1]s); test -d \${dir} || mkdir -p \${dir}; } && cat - > %[1]s`+setFilePerms+`"`, a.Target) if err := sess.Start(cmd); err != nil { return err } if _, err := io.Copy(stdin, r); err != nil { return errors.Wrap(err, "failed to send script to target") } stdin.Close() // TODO validate all bytes written // TODO use compression on the wire return sess.Wait() }
func (pkg *smPackage) Provision(l logger.Logger, client connection.Client) (err error) { l = l.Tag(pkg.ID) oldState := pkg.state pkg.state = make([]string, len(pkg.Scripts)) allCached := true defer func() { if allCached { return } e := pkg.writeTargetState(client) if err == nil { err = e } }() for i, s := range pkg.Scripts { hash := s.Hash() if allCached && i < len(oldState) && oldState[i][1:] == hash { l.Printf("step %d cached", i) pkg.state[i] = "." + hash continue } allCached = false if err = s.Exec(l, client); err != nil { l.Printf("failed in %s", hash) pkg.state[i] = "-" + hash pkg.state = pkg.state[:i+1] return err } pkg.state[i] = "+" + hash } return nil }
func (hp *smartOS) Create(l logger.Logger, blueprint string) (string, error) { m := map[string]interface{}{} if err := json.Unmarshal([]byte(blueprint), &m); err != nil { return "", errors.Wrap(err, "failed to unmarshal the blueprint") } l.Printf("updating the image database") if err := runCommand(hp.client, "imgadm update"); err != nil { return "", err } imgUUID := m["image_uuid"].(string) l.Printf("importing image %s", imgUUID) if err := runCommand(hp.client, "imgadm import -q "+imgUUID); err != nil { return "", err } // determine whether the VM in question already exists sess, err := hp.client.NewSession() if err != nil { return "", err } defer sess.Close() wg := new(sync.WaitGroup) wg.Add(2) outBuf := bytes.NewBuffer(nil) stderr, err := sess.StderrPipe() if err != nil { return "", errors.Wrap(err, "failed to retrieve stderr pipe") } go func() { defer wg.Done() _, _ = io.Copy(outBuf, stderr) }() stdin, err := sess.StdinPipe() if err != nil { return "", errors.Wrap(err, "failed to retrieve stdin pipe") } go func() { defer wg.Done() _, _ = io.WriteString(stdin, blueprint) stdin.Close() }() l.Printf("creating the virtual resource") if err := sess.Run("vmadm create"); err != nil { log.Printf("failed: %s", outBuf.String()) return "", err } wg.Wait() output := strings.TrimSpace(outBuf.String()) expResponsePrefix := "Successfully created VM " if !strings.HasPrefix(output, expResponsePrefix) { return "", errors.Errorf("wrong response received: %s", output) } return strings.TrimPrefix(output, expResponsePrefix), nil }