[lxd] refactor commands to dry things up

This commit is contained in:
Chris Lundquist 2016-08-07 03:25:57 +00:00 committed by Megan Marsh
parent 05f072929f
commit e29f06fe1c
5 changed files with 44 additions and 62 deletions

View File

@ -1,7 +1,11 @@
package lxd package lxd
import ( import (
"bytes"
"fmt"
"log"
"os/exec" "os/exec"
"strings"
) )
// CommandWrapper is a type that given a command, will possibly modify that // CommandWrapper is a type that given a command, will possibly modify that
@ -13,3 +17,27 @@ type CommandWrapper func(string) (string, error)
func ShellCommand(command string) *exec.Cmd { func ShellCommand(command string) *exec.Cmd {
return exec.Command("/bin/sh", "-c", command) return exec.Command("/bin/sh", "-c", command)
} }
// Yeah...LXD calls `lxc` because the command line is different between the
// packages. This should also avoid a naming collision between the LXC builder.
func LXDCommand(args ...string) (string, error) {
var stdout, stderr bytes.Buffer
log.Printf("Executing lxc command: %#v", args)
cmd := exec.Command("lxc", args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
stdoutString := strings.TrimSpace(stdout.String())
stderrString := strings.TrimSpace(stderr.String())
if _, ok := err.(*exec.ExitError); ok {
err = fmt.Errorf("LXD command error: %s", stderrString)
}
log.Printf("stdout: %s", stdoutString)
log.Printf("stderr: %s", stderrString)
return stdoutString, err
}

View File

@ -128,7 +128,7 @@ func (c *Communicator) DownloadDir(src string, dst string, exclude []string) err
func (c *Communicator) Execute(commandString string) (*exec.Cmd, error) { func (c *Communicator) Execute(commandString string) (*exec.Cmd, error) {
log.Printf("Executing with lxc exec in container: %s %s", c.ContainerName, commandString) log.Printf("Executing with lxc exec in container: %s %s", c.ContainerName, commandString)
command, err := c.CmdWrapper( command, err := c.CmdWrapper(
fmt.Sprintf("sudo lxc exec %s -- /bin/sh -c \"%s\"", c.ContainerName, commandString)) fmt.Sprintf("lxc exec %s -- /bin/sh -c \"%s\"", c.ContainerName, commandString))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,13 +1,9 @@
package lxd package lxd
import ( import (
"bytes"
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
"os/exec"
"strings"
"time" "time"
) )
@ -20,20 +16,17 @@ func (s *stepLxdLaunch) Run(state multistep.StateBag) multistep.StepAction {
name := config.ContainerName name := config.ContainerName
image := config.Image image := config.Image
commands := [][]string{ args := []string{
{"lxc", "launch", image, name}, "launch", image, name,
} }
ui.Say("Creating container...") ui.Say("Creating container...")
for _, command := range commands { _, err := LXDCommand(args...)
log.Printf("Executing sudo command: %#v", command) if err != nil {
err := s.SudoCommand(command...) err := fmt.Errorf("Error creating container: %s", err)
if err != nil { state.Put("error", err)
err := fmt.Errorf("Error creating container: %s", err) ui.Error(err.Error())
state.Put("error", err) return multistep.ActionHalt
ui.Error(err.Error())
return multistep.ActionHalt
}
} }
// TODO: Should we check `lxc info <container>` for "Running"? // TODO: Should we check `lxc info <container>` for "Running"?
// We have to do this so /tmp doens't get cleared and lose our provisioner scripts. // We have to do this so /tmp doens't get cleared and lose our provisioner scripts.
@ -46,34 +39,12 @@ func (s *stepLxdLaunch) Cleanup(state multistep.StateBag) {
config := state.Get("config").(*Config) config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
command := []string{ args := []string{
"lxc", "delete", "--force", config.ContainerName, "delete", "--force", config.ContainerName,
} }
ui.Say("Unregistering and deleting deleting container...") ui.Say("Unregistering and deleting deleting container...")
if err := s.SudoCommand(command...); err != nil { if _, err := LXDCommand(args...); err != nil {
ui.Error(fmt.Sprintf("Error deleting container: %s", err)) ui.Error(fmt.Sprintf("Error deleting container: %s", err))
} }
} }
func (s *stepLxdLaunch) SudoCommand(args ...string) error {
var stdout, stderr bytes.Buffer
log.Printf("Executing sudo command: %#v", args)
cmd := exec.Command("sudo", args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
stdoutString := strings.TrimSpace(stdout.String())
stderrString := strings.TrimSpace(stderr.String())
if _, ok := err.(*exec.ExitError); ok {
err = fmt.Errorf("Sudo command error: %s", stderrString)
}
log.Printf("stdout: %s", stdoutString)
log.Printf("stderr: %s", stderrString)
return err
}

View File

@ -6,7 +6,7 @@ import (
"log" "log"
) )
// StepProvision provisions the instance within a chroot. // StepProvision provisions the container
type StepProvision struct{} type StepProvision struct{}
func (s *StepProvision) Run(state multistep.StateBag) multistep.StepAction { func (s *StepProvision) Run(state multistep.StateBag) multistep.StepAction {

View File

@ -1,20 +1,15 @@
package lxd package lxd
import ( import (
"bytes"
"fmt" "fmt"
"github.com/mitchellh/multistep" "github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/packer"
"log"
"os/exec"
"regexp" "regexp"
"strings"
) )
type stepPublish struct{} type stepPublish struct{}
func (s *stepPublish) Run(state multistep.StateBag) multistep.StepAction { func (s *stepPublish) Run(state multistep.StateBag) multistep.StepAction {
var stdout, stderr bytes.Buffer
config := state.Get("config").(*Config) config := state.Get("config").(*Config)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
@ -23,25 +18,13 @@ func (s *stepPublish) Run(state multistep.StateBag) multistep.StepAction {
args := []string{ args := []string{
// If we use `lxc stop <container>`, an ephemeral container would die forever. // If we use `lxc stop <container>`, an ephemeral container would die forever.
// `lxc publish` has special logic to handle this case. // `lxc publish` has special logic to handle this case.
"lxc", "publish", "--force", name, "--alias", config.OutputImage, "publish", "--force", name, "--alias", config.OutputImage,
} }
ui.Say("Publishing container...") ui.Say("Publishing container...")
cmd := exec.Command("sudo", args...) stdoutString, err := LXDCommand(args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
stdoutString := strings.TrimSpace(stdout.String())
stderrString := strings.TrimSpace(stderr.String())
if _, ok := err.(*exec.ExitError); ok {
err = fmt.Errorf("Sudo command error: %s", stderrString)
}
log.Printf("stdout: %s", stdoutString)
log.Printf("stderr: %s", stderrString)
if err != nil { if err != nil {
err := fmt.Errorf("Error publishing container: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())
return multistep.ActionHalt return multistep.ActionHalt