Skip to content

Commit

Permalink
Add external support for provision scripts
Browse files Browse the repository at this point in the history
Signed-off-by: Anders F Björklund <anders.f.bjorklund@gmail.com>
  • Loading branch information
afbjorklund committed Apr 28, 2024
1 parent 1c7939b commit e1d9b66
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
5 changes: 5 additions & 0 deletions pkg/hostagent/hostagent.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,11 @@ sudo chown -R "${USER}" /run/host-services`
return errors.Join(unlockErrs...)
})
}
if *a.y.VMType == limayaml.EXT {
if err := a.runProvisionScripts(); err != nil {
return err
}
}
if !*a.y.Plain {
go a.watchGuestAgentEvents(ctx)
}
Expand Down
69 changes: 69 additions & 0 deletions pkg/hostagent/provision.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package hostagent

import (
"errors"
"fmt"

"github.com/lima-vm/lima/pkg/limayaml"
"github.com/lima-vm/sshocker/pkg/ssh"
"github.com/sirupsen/logrus"
)

func (a *HostAgent) runProvisionScripts() error {
var errs []error

for i, f := range a.y.Provision {
switch f.Mode {
case limayaml.ProvisionModeSystem, limayaml.ProvisionModeUser:
logrus.Infof("Running %s provision %d of %d", f.Mode, i+1, len(a.y.Provision))
err := a.waitForProvision(
provision{
description: fmt.Sprintf("provision.%s/%08d", f.Mode, i),
sudo: f.Mode == limayaml.ProvisionModeSystem,
script: f.Script,
})
if err != nil {
errs = append(errs, err)
}
case limayaml.ProvisionModeDependency, limayaml.ProvisionModeBoot:
logrus.Infof("Skipping %s provision %d of %d", f.Mode, i+1, len(a.y.Provision))
continue
default:
return fmt.Errorf("unknown provision mode %q", f.Mode)
}
}
return errors.Join(errs...)
}

func (a *HostAgent) waitForProvision(p provision) error {
if p.sudo {
return a.waitForSystemProvision(p)
}
return a.waitForUserProvision(p)
}

func (a *HostAgent) waitForSystemProvision(p provision) error {
logrus.Debugf("executing script %q", p.description)
stdout, stderr, err := sudoExecuteScript(a.instSSHAddress, a.sshLocalPort, a.sshConfig, p.script, p.description)
logrus.Debugf("stdout=%q, stderr=%q, err=%v", stdout, stderr, err)
if err != nil {
return fmt.Errorf("stdout=%q, stderr=%q: %w", stdout, stderr, err)
}
return nil
}

func (a *HostAgent) waitForUserProvision(p provision) error {
logrus.Debugf("executing script %q", p.description)
stdout, stderr, err := ssh.ExecuteScript(a.instSSHAddress, a.sshLocalPort, a.sshConfig, p.script, p.description)
logrus.Debugf("stdout=%q, stderr=%q, err=%v", stdout, stderr, err)
if err != nil {
return fmt.Errorf("stdout=%q, stderr=%q: %w", stdout, stderr, err)
}
return nil
}

type provision struct {
description string
script string
sudo bool
}
43 changes: 43 additions & 0 deletions pkg/hostagent/sudo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package hostagent

import (
"bytes"
"errors"
"fmt"
"os/exec"
"strconv"
"strings"

"github.com/lima-vm/sshocker/pkg/ssh"
"github.com/sirupsen/logrus"
)

// sudoExecuteScript executes the given script (as root) on the remote host via stdin.
// Returns stdout and stderr.
//
// scriptName is used only for readability of error strings.
func sudoExecuteScript(host string, port int, c *ssh.SSHConfig, script, scriptName string) (stdout, stderr string, err error) {
if c == nil {
return "", "", errors.New("got nil SSHConfig")
}
interpreter, err := ssh.ParseScriptInterpreter(script)
if err != nil {
return "", "", err
}
sshBinary := c.Binary()
sshArgs := c.Args()
if port != 0 {
sshArgs = append(sshArgs, "-p", strconv.Itoa(port))
}
sshArgs = append(sshArgs, host, "--", "sudo", interpreter)
sshCmd := exec.Command(sshBinary, sshArgs...)
sshCmd.Stdin = strings.NewReader(script)
var buf bytes.Buffer
sshCmd.Stderr = &buf
logrus.Debugf("executing ssh for script %q: %s %v", scriptName, sshCmd.Path, sshCmd.Args)
out, err := sshCmd.Output()
if err != nil {
return string(out), buf.String(), fmt.Errorf("failed to execute script %q: stdout=%q, stderr=%q: %w", scriptName, string(out), buf.String(), err)
}
return string(out), buf.String(), nil
}

0 comments on commit e1d9b66

Please sign in to comment.