From e1ca5c44882e98c786248bd4b49431db31dee374 Mon Sep 17 00:00:00 2001 From: Michele Catalano Date: Fri, 12 Jun 2015 10:18:59 +0200 Subject: [PATCH 01/21] Add lxc to vagrant post-processor --- post-processor/vagrant/lxc.go | 30 ++++++++++++++++++++++++ post-processor/vagrant/lxc_test.go | 9 +++++++ post-processor/vagrant/post-processor.go | 3 +++ 3 files changed, 42 insertions(+) create mode 100644 post-processor/vagrant/lxc.go create mode 100644 post-processor/vagrant/lxc_test.go diff --git a/post-processor/vagrant/lxc.go b/post-processor/vagrant/lxc.go new file mode 100644 index 000000000..497bcc1cd --- /dev/null +++ b/post-processor/vagrant/lxc.go @@ -0,0 +1,30 @@ +package vagrant + +import ( + "fmt" + "github.com/mitchellh/packer/packer" + "path/filepath" +) + +type LxcProvider struct{} + +func (p *LxcProvider) KeepInputArtifact() bool { + return false +} + +func (p *LxcProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) { + // Create the metadata + metadata = map[string]interface{}{"provider": "lxc"} + + // Copy all of the original contents into the temporary directory + for _, path := range artifact.Files() { + ui.Message(fmt.Sprintf("Copying: %s", path)) + + dstPath := filepath.Join(dir, filepath.Base(path)) + if err = CopyContents(dstPath, path); err != nil { + return + } + } + + return +} diff --git a/post-processor/vagrant/lxc_test.go b/post-processor/vagrant/lxc_test.go new file mode 100644 index 000000000..f3fbc320c --- /dev/null +++ b/post-processor/vagrant/lxc_test.go @@ -0,0 +1,9 @@ +package vagrant + +import ( + "testing" +) + +func TestLxcProvider_impl(t *testing.T) { + var _ Provider = new(LxcProvider) +} diff --git a/post-processor/vagrant/post-processor.go b/post-processor/vagrant/post-processor.go index aa65b2292..9a20ed5ae 100644 --- a/post-processor/vagrant/post-processor.go +++ b/post-processor/vagrant/post-processor.go @@ -28,6 +28,7 @@ var builtins = map[string]string{ "packer.parallels": "parallels", "MSOpenTech.hyperv": "hyperv", "transcend.qemu": "libvirt", + "ustream.lxc": "lxc", } type Config struct { @@ -232,6 +233,8 @@ func providerForName(name string) Provider { return new(HypervProvider) case "libvirt": return new(LibVirtProvider) + case "lxc": + return new(LxcProvider) default: return nil } From 21c9f7a9aa512830f236189338049a972858c5e3 Mon Sep 17 00:00:00 2001 From: Michele Catalano Date: Tue, 16 Jun 2015 19:53:38 +0200 Subject: [PATCH 02/21] Add version field with value 1.0.0 to metadata --- post-processor/vagrant/lxc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/post-processor/vagrant/lxc.go b/post-processor/vagrant/lxc.go index 497bcc1cd..24fff2edb 100644 --- a/post-processor/vagrant/lxc.go +++ b/post-processor/vagrant/lxc.go @@ -14,7 +14,7 @@ func (p *LxcProvider) KeepInputArtifact() bool { func (p *LxcProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) { // Create the metadata - metadata = map[string]interface{}{"provider": "lxc"} + metadata = map[string]interface{}{"provider": "lxc", "version": "1.0.0"} // Copy all of the original contents into the temporary directory for _, path := range artifact.Files() { From 659a0da594eab67dbe20c3086d01958317408050 Mon Sep 17 00:00:00 2001 From: Michele Catalano Date: Tue, 22 Dec 2015 15:56:33 +0100 Subject: [PATCH 03/21] Add lxc builder to packer --- builder/lxc/artifact.go | 35 ++++++ builder/lxc/builder.go | 118 ++++++++++++++++++++ builder/lxc/command.go | 15 +++ builder/lxc/communicator.go | 147 +++++++++++++++++++++++++ builder/lxc/config.go | 70 ++++++++++++ builder/lxc/step_export.go | 99 +++++++++++++++++ builder/lxc/step_lxc_create.go | 89 +++++++++++++++ builder/lxc/step_prepare_output_dir.go | 49 +++++++++ builder/lxc/step_provision.go | 36 ++++++ builder/lxc/step_wait_init.go | 123 +++++++++++++++++++++ 10 files changed, 781 insertions(+) create mode 100644 builder/lxc/artifact.go create mode 100644 builder/lxc/builder.go create mode 100644 builder/lxc/command.go create mode 100644 builder/lxc/communicator.go create mode 100644 builder/lxc/config.go create mode 100644 builder/lxc/step_export.go create mode 100644 builder/lxc/step_lxc_create.go create mode 100644 builder/lxc/step_prepare_output_dir.go create mode 100644 builder/lxc/step_provision.go create mode 100644 builder/lxc/step_wait_init.go diff --git a/builder/lxc/artifact.go b/builder/lxc/artifact.go new file mode 100644 index 000000000..9ac57d0cc --- /dev/null +++ b/builder/lxc/artifact.go @@ -0,0 +1,35 @@ +package lxc + +import ( + "fmt" + "os" +) + +type Artifact struct { + dir string + f []string +} + +func (*Artifact) BuilderId() string { + return BuilderId +} + +func (a *Artifact) Files() []string { + return a.f +} + +func (*Artifact) Id() string { + return "VM" +} + +func (a *Artifact) String() string { + return fmt.Sprintf("VM files in directory: %s", a.dir) +} + +func (a *Artifact) State(name string) interface{} { + return nil +} + +func (a *Artifact) Destroy() error { + return os.RemoveAll(a.dir) +} diff --git a/builder/lxc/builder.go b/builder/lxc/builder.go new file mode 100644 index 000000000..7d630fe44 --- /dev/null +++ b/builder/lxc/builder.go @@ -0,0 +1,118 @@ +package lxc + +import ( + "errors" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" + "log" + "os" + "path/filepath" + "runtime" +) + +// The unique ID for this builder +const BuilderId = "ustream.lxc" + +type wrappedCommandTemplate struct { + Command string +} + +type Builder struct { + config *Config + runner multistep.Runner +} + +func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { + c, errs := NewConfig(raws...) + if errs != nil { + return nil, errs + } + b.config = c + + return nil, nil +} + +func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { + if runtime.GOOS != "linux" { + return nil, errors.New("The lxc builder only works on linux environments.") + } + + wrappedCommand := func(command string) (string, error) { + b.config.ctx.Data = &wrappedCommandTemplate{Command: command} + return interpolate.Render(b.config.CommandWrapper, &b.config.ctx) + } + + steps := []multistep.Step{ + new(stepPrepareOutputDir), + new(stepLxcCreate), + &StepWaitInit{ + WaitTimeout: b.config.InitTimeout, + }, + new(StepProvision), + new(stepExport), + } + + // Setup the state bag + state := new(multistep.BasicStateBag) + state.Put("config", b.config) + state.Put("cache", cache) + state.Put("hook", hook) + state.Put("ui", ui) + state.Put("wrappedCommand", CommandWrapper(wrappedCommand)) + + // Run + if b.config.PackerDebug { + b.runner = &multistep.DebugRunner{ + Steps: steps, + PauseFn: common.MultistepDebugFn(ui), + } + } else { + b.runner = &multistep.BasicRunner{Steps: steps} + } + + b.runner.Run(state) + + // If there was an error, return that + if rawErr, ok := state.GetOk("error"); ok { + return nil, rawErr.(error) + } + + // If we were interrupted or cancelled, then just exit. + if _, ok := state.GetOk(multistep.StateCancelled); ok { + return nil, errors.New("Build was cancelled.") + } + + if _, ok := state.GetOk(multistep.StateHalted); ok { + return nil, errors.New("Build was halted.") + } + + // Compile the artifact list + files := make([]string, 0, 5) + visit := func(path string, info os.FileInfo, err error) error { + if !info.IsDir() { + files = append(files, path) + } + + return err + } + + if err := filepath.Walk(b.config.OutputDir, visit); err != nil { + return nil, err + } + + artifact := &Artifact{ + dir: b.config.OutputDir, + f: files, + } + + return artifact, nil +} + +func (b *Builder) Cancel() { + if b.runner != nil { + log.Println("Cancelling the step runner...") + b.runner.Cancel() + } +} diff --git a/builder/lxc/command.go b/builder/lxc/command.go new file mode 100644 index 000000000..af81cff83 --- /dev/null +++ b/builder/lxc/command.go @@ -0,0 +1,15 @@ +package lxc + +import ( + "os/exec" +) + +// CommandWrapper is a type that given a command, will possibly modify that +// command in-flight. This might return an error. +type CommandWrapper func(string) (string, error) + +// ShellCommand takes a command string and returns an *exec.Cmd to execute +// it within the context of a shell (/bin/sh). +func ShellCommand(command string) *exec.Cmd { + return exec.Command("/bin/sh", "-c", command) +} diff --git a/builder/lxc/communicator.go b/builder/lxc/communicator.go new file mode 100644 index 000000000..a1eb50fdb --- /dev/null +++ b/builder/lxc/communicator.go @@ -0,0 +1,147 @@ +package lxc + +import ( + "fmt" + "github.com/mitchellh/packer/packer" + "io" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "syscall" + "strings" +) + +type LxcAttachCommunicator struct { + RootFs string + ContainerName string + CmdWrapper CommandWrapper +} + +func (c *LxcAttachCommunicator) Start(cmd *packer.RemoteCmd) error { + localCmd, err := c.Execute(cmd.Command) + + if err != nil { + return err + } + + localCmd.Stdin = cmd.Stdin + localCmd.Stdout = cmd.Stdout + localCmd.Stderr = cmd.Stderr + if err := localCmd.Start(); err != nil { + return err + } + + go func() { + exitStatus := 0 + if err := localCmd.Wait(); err != nil { + if exitErr, ok := err.(*exec.ExitError); ok { + exitStatus = 1 + + // There is no process-independent way to get the REAL + // exit status so we just try to go deeper. + if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { + exitStatus = status.ExitStatus() + } + } + } + + log.Printf( + "lxc-attach execution exited with '%d': '%s'", + exitStatus, cmd.Command) + cmd.SetExited(exitStatus) + }() + + return nil +} + +func (c *LxcAttachCommunicator) Upload(dst string, r io.Reader, fi *os.FileInfo) error { + dst = filepath.Join(c.RootFs, dst) + log.Printf("Uploading to rootfs: %s", dst) + tf, err := ioutil.TempFile("", "packer-lxc-attach") + if err != nil { + return fmt.Errorf("Error uploading file to rootfs: %s", err) + } + defer os.Remove(tf.Name()) + io.Copy(tf, r) + + cpCmd, err := c.CmdWrapper(fmt.Sprintf("sudo cp %s %s", tf.Name(), dst)) + if err != nil { + return err + } + + log.Printf("Running copy command: %s", dst) + + return ShellCommand(cpCmd).Run() +} + +func (c *LxcAttachCommunicator) UploadDir(dst string, src string, exclude []string) error { + // TODO: remove any file copied if it appears in `exclude` + dest := filepath.Join(c.RootFs, dst) + log.Printf("Uploading directory '%s' to rootfs '%s'", src, dest) + cpCmd, err := c.CmdWrapper(fmt.Sprintf("sudo cp -R %s/. %s", src, dest)) + if err != nil { + return err + } + + return ShellCommand(cpCmd).Run() +} + +func (c *LxcAttachCommunicator) Download(src string, w io.Writer) error { + src = filepath.Join(c.RootFs, src) + log.Printf("Downloading from rootfs dir: %s", src) + f, err := os.Open(src) + if err != nil { + return err + } + defer f.Close() + + if _, err := io.Copy(w, f); err != nil { + return err + } + + return nil +} + +func (c *LxcAttachCommunicator) Execute(commandString string) (*exec.Cmd, error) { + log.Printf("Executing with lxc-attach in container: %s %s %s", c.ContainerName, c.RootFs, commandString) + command, err := c.CmdWrapper( + fmt.Sprintf("sudo lxc-attach --name %s -- /bin/sh -c \"%s\"", c.ContainerName, commandString)) + if err != nil { + return nil, err + } + + localCmd := ShellCommand(command) + log.Printf("Executing lxc-attach: %s %#v", localCmd.Path, localCmd.Args) + + return localCmd, nil +} + +func (c *LxcAttachCommunicator) CheckInit() (string, error) { + log.Printf("Debug runlevel exec") + localCmd, err := c.Execute("/sbin/runlevel") + + if err != nil { + return "", err + } + + pr, _ := localCmd.StdoutPipe() + if err = localCmd.Start(); err != nil { + return "", err + } + + output, err := ioutil.ReadAll(pr) + + if err != nil { + return "", err + } + + err = localCmd.Wait() + + if err != nil { + return "", err + } + + return strings.TrimSpace(string(output)), nil +} \ No newline at end of file diff --git a/builder/lxc/config.go b/builder/lxc/config.go new file mode 100644 index 000000000..6c32eeb95 --- /dev/null +++ b/builder/lxc/config.go @@ -0,0 +1,70 @@ +package lxc + +import ( + "fmt" + "github.com/mitchellh/mapstructure" + "github.com/mitchellh/packer/common" + "github.com/mitchellh/packer/helper/config" + "github.com/mitchellh/packer/packer" + "github.com/mitchellh/packer/template/interpolate" + "time" +) + +type Config struct { + common.PackerConfig `mapstructure:",squash"` + ConfigFile string `mapstructure:"config_file"` + OutputDir string `mapstructure:"output_directory"` + ContainerName string `mapstructure:"container_name"` + CommandWrapper string `mapstructure:"command_wrapper"` + RawInitTimeout string `mapstructure:"init_timeout"` + Name string `mapstructure:"template_name"` + Parameters []string `mapstructure:"template_parameters"` + EnvVars []string `mapstructure:"template_environment_vars"` + TargetRunlevel int `mapstructure:"target_runlevel"` + InitTimeout time.Duration + + ctx interpolate.Context +} + +func NewConfig(raws ...interface{}) (*Config, error) { + var c Config + + var md mapstructure.Metadata + err := config.Decode(&c, &config.DecodeOpts{ + Metadata: &md, + Interpolate: true, + }, raws...) + if err != nil { + return nil, err + } + + // Accumulate any errors + var errs *packer.MultiError + + if c.OutputDir == "" { + c.OutputDir = fmt.Sprintf("output-%s", c.PackerBuildName) + } + + if c.ContainerName == "" { + c.ContainerName = fmt.Sprintf("packer-%s", c.PackerBuildName) + } + + if c.CommandWrapper == "" { + c.CommandWrapper = "{{.Command}}" + } + + if c.RawInitTimeout == "" { + c.RawInitTimeout = "20s" + } + + c.InitTimeout, err = time.ParseDuration(c.RawInitTimeout) + if err != nil { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed parsing init_timeout: %s", err)) + } + + if errs != nil && len(errs.Errors) > 0 { + return nil, errs + } + + return &c, nil +} diff --git a/builder/lxc/step_export.go b/builder/lxc/step_export.go new file mode 100644 index 000000000..3af9ed7f3 --- /dev/null +++ b/builder/lxc/step_export.go @@ -0,0 +1,99 @@ +package lxc + +import ( + "github.com/mitchellh/multistep" + "fmt" + "github.com/mitchellh/packer/packer" + "bytes" + "os/exec" + "log" + "strings" + "path/filepath" + "os" + "io" +) + +type stepExport struct{} + +func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(*Config) + ui := state.Get("ui").(packer.Ui) + + name := config.ContainerName + + containerDir := fmt.Sprintf("/var/lib/lxc/%s", name) + outputPath := filepath.Join(config.OutputDir, "rootfs.tar.gz") + configFilePath := filepath.Join(config.OutputDir, "lxc-config") + + configFile, err := os.Create(configFilePath) + + if err != nil { + err := fmt.Errorf("Error creating config file: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + originalConfigFile, err := os.Open(config.ConfigFile) + + if err != nil { + err := fmt.Errorf("Error opening config file: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + _, err = io.Copy(configFile, originalConfigFile) + + commands := make([][]string, 4) + commands[0] = []string{ + "lxc-stop", "--name", name, + } + commands[1] = []string{ + "tar", "-C", containerDir, "--numeric-owner", "--anchored", "--exclude=./rootfs/dev/log", "-czf", outputPath, "./rootfs", + } + commands[2] = []string{ + "chmod", "+x", configFilePath, + } + commands[3] = []string{ + "sh", "-c", "chown $USER:`id -gn` " + filepath.Join(config.OutputDir, "*"), + } + + ui.Say("Exporting container...") + for _, command := range commands { + err := s.SudoCommand(command...) + if err != nil { + err := fmt.Errorf("Error exporting container: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + } + + return multistep.ActionContinue +} + +func (s *stepExport) Cleanup(state multistep.StateBag) {} + + +func (s *stepExport) 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 +} \ No newline at end of file diff --git a/builder/lxc/step_lxc_create.go b/builder/lxc/step_lxc_create.go new file mode 100644 index 000000000..070eae680 --- /dev/null +++ b/builder/lxc/step_lxc_create.go @@ -0,0 +1,89 @@ +package lxc + +import ( + "bytes" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "os/exec" + "path/filepath" + "strings" +) + +type stepLxcCreate struct{} + +func (s *stepLxcCreate) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(*Config) + ui := state.Get("ui").(packer.Ui) + + name := config.ContainerName + + // TODO: read from env + lxc_dir := "/var/lib/lxc" + rootfs := filepath.Join(lxc_dir, name, "rootfs") + + if config.PackerForce { + s.Cleanup(state) + } + + commands := make([][]string, 3) + commands[0] = append(config.EnvVars, []string{"lxc-create", "-n", name, "-t", config.Name, "--"}...) + commands[0] = append(commands[0], config.Parameters...) + // prevent tmp from being cleaned on boot, we put provisioning scripts there + // todo: wait for init to finish before moving on to provisioning instead of this + commands[1] = []string{"touch", filepath.Join(rootfs, "tmp", ".tmpfs")} + commands[2] = []string{"lxc-start", "-d", "--name", name} + + ui.Say("Creating container...") + for _, command := range commands { + log.Printf("Executing sudo command: %#v", command) + err := s.SudoCommand(command...) + if err != nil { + err := fmt.Errorf("Error creating container: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + } + + state.Put("mount_path", rootfs) + + return multistep.ActionContinue +} + +func (s *stepLxcCreate) Cleanup(state multistep.StateBag) { + config := state.Get("config").(*Config) + ui := state.Get("ui").(packer.Ui) + + command := []string{ + "lxc-destroy", "-f", "-n", config.ContainerName, + } + + ui.Say("Unregistering and deleting virtual machine...") + if err := s.SudoCommand(command...); err != nil { + ui.Error(fmt.Sprintf("Error deleting virtual machine: %s", err)) + } +} + +func (s *stepLxcCreate) 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 +} diff --git a/builder/lxc/step_prepare_output_dir.go b/builder/lxc/step_prepare_output_dir.go new file mode 100644 index 000000000..4b66c0c87 --- /dev/null +++ b/builder/lxc/step_prepare_output_dir.go @@ -0,0 +1,49 @@ +package lxc + +import ( + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "os" + "time" +) + +type stepPrepareOutputDir struct{} + +func (stepPrepareOutputDir) Run(state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(*Config) + ui := state.Get("ui").(packer.Ui) + + if _, err := os.Stat(config.OutputDir); err == nil && config.PackerForce { + ui.Say("Deleting previous output directory...") + os.RemoveAll(config.OutputDir) + } + + if err := os.MkdirAll(config.OutputDir, 0755); err != nil { + state.Put("error", err) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (stepPrepareOutputDir) Cleanup(state multistep.StateBag) { + _, cancelled := state.GetOk(multistep.StateCancelled) + _, halted := state.GetOk(multistep.StateHalted) + + if cancelled || halted { + config := state.Get("config").(*Config) + ui := state.Get("ui").(packer.Ui) + + ui.Say("Deleting output directory...") + for i := 0; i < 5; i++ { + err := os.RemoveAll(config.OutputDir) + if err == nil { + break + } + + log.Printf("Error removing output dir: %s", err) + time.Sleep(2 * time.Second) + } + } +} diff --git a/builder/lxc/step_provision.go b/builder/lxc/step_provision.go new file mode 100644 index 000000000..b8fe6cd04 --- /dev/null +++ b/builder/lxc/step_provision.go @@ -0,0 +1,36 @@ +package lxc + +import ( + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" +) + +// StepProvision provisions the instance within a chroot. +type StepProvision struct {} + +func (s *StepProvision) Run(state multistep.StateBag) multistep.StepAction { + hook := state.Get("hook").(packer.Hook) + config := state.Get("config").(*Config) + mountPath := state.Get("mount_path").(string) + ui := state.Get("ui").(packer.Ui) + wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) + + // Create our communicator + comm := &LxcAttachCommunicator{ + ContainerName: config.ContainerName, + RootFs: mountPath, + CmdWrapper: wrappedCommand, + } + + // Provision + log.Println("Running the provision hook") + if err := hook.Run(packer.HookProvision, ui, comm, nil); err != nil { + state.Put("error", err) + return multistep.ActionHalt + } + + return multistep.ActionContinue +} + +func (s *StepProvision) Cleanup(state multistep.StateBag) {} diff --git a/builder/lxc/step_wait_init.go b/builder/lxc/step_wait_init.go new file mode 100644 index 000000000..180f83f73 --- /dev/null +++ b/builder/lxc/step_wait_init.go @@ -0,0 +1,123 @@ +package lxc + +import ( + "errors" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "log" + "strings" + "time" +) + +type StepWaitInit struct { + WaitTimeout time.Duration +} + +func (s *StepWaitInit) Run(state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + + var err error + + cancel := make(chan struct{}) + waitDone := make(chan bool, 1) + go func() { + ui.Say("Waiting for container to finish init...") + err = s.waitForInit(state, cancel) + waitDone <- true + }() + + log.Printf("Waiting for container to finish init, up to timeout: %s", s.WaitTimeout) + timeout := time.After(s.WaitTimeout) +WaitLoop: + for { + select { + case <-waitDone: + if err != nil { + ui.Error(fmt.Sprintf("Error waiting for container to finish init: %s", err)) + return multistep.ActionHalt + } + + ui.Say("Container finished init!") + break WaitLoop + case <-timeout: + err := fmt.Errorf("Timeout waiting for container to finish init.") + state.Put("error", err) + ui.Error(err.Error()) + close(cancel) + return multistep.ActionHalt + case <-time.After(1 * time.Second): + if _, ok := state.GetOk(multistep.StateCancelled); ok { + close(cancel) + log.Println("Interrupt detected, quitting waiting for container to finish init.") + return multistep.ActionHalt + } + } + } + + return multistep.ActionContinue +} + +func (s *StepWaitInit) Cleanup(multistep.StateBag) { +} + +func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struct{}) error { + config := state.Get("config").(*Config) + mountPath := state.Get("mount_path").(string) + wrappedCommand := state.Get("wrappedCommand").(CommandWrapper) + + for { + select { + case <-cancel: + log.Println("Cancelled. Exiting loop.") + return errors.New("Wait cancelled") + case <-time.After(1 * time.Second): + } + + comm := &LxcAttachCommunicator{ + ContainerName: config.ContainerName, + RootFs: mountPath, + CmdWrapper: wrappedCommand, + } + + runlevel, _ := comm.CheckInit() + currentRunlevel := "unknown" + if arr := strings.Split(runlevel, " "); len(arr) >= 2 { + currentRunlevel = arr[1] + } + + log.Printf("Current runlevel in container: '%s'", runlevel) + + targetRunlevel := fmt.Sprintf("%d", config.TargetRunlevel) + if currentRunlevel == targetRunlevel { + log.Printf("Container finished init.") + break + } + + /*log.Println("Attempting SSH connection...") + comm, err = ssh.New(config) + if err != nil { + log.Printf("SSH handshake err: %s", err) + + // Only count this as an attempt if we were able to attempt + // to authenticate. Note this is very brittle since it depends + // on the string of the error... but I don't see any other way. + if strings.Contains(err.Error(), "authenticate") { + log.Printf("Detected authentication error. Increasing handshake attempts.") + handshakeAttempts += 1 + } + + if handshakeAttempts < 10 { + // Try to connect via SSH a handful of times + continue + } + + return nil, err + } + + break + */ + } + + return nil +} From f4f0ab9f5029a464f22fcc159d9fea38b9d6e145 Mon Sep 17 00:00:00 2001 From: Michele Catalano Date: Thu, 24 Dec 2015 23:48:40 +0100 Subject: [PATCH 04/21] add integrate lxc builder in packer add lxc with scripts/generate-plugins.go --- command/plugin.go | 6 ++++-- plugin/builder-lxc/main.go | 15 +++++++++++++++ plugin/builder-lxc/main_test.go | 1 + 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 plugin/builder-lxc/main.go create mode 100644 plugin/builder-lxc/main_test.go diff --git a/command/plugin.go b/command/plugin.go index af2fa2985..2b0d3428c 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -26,6 +26,8 @@ import ( filebuilder "github.com/hashicorp/packer/builder/file" googlecomputebuilder "github.com/hashicorp/packer/builder/googlecompute" hypervisobuilder "github.com/hashicorp/packer/builder/hyperv/iso" + lxcbuilder "github.com/hashicorp/packer/builder/lxc" + lxdbuilder "github.com/hashicorp/packer/builder/lxd" nullbuilder "github.com/hashicorp/packer/builder/null" oneandonebuilder "github.com/hashicorp/packer/builder/oneandone" openstackbuilder "github.com/hashicorp/packer/builder/openstack" @@ -69,8 +71,6 @@ import ( shelllocalprovisioner "github.com/hashicorp/packer/provisioner/shell-local" windowsrestartprovisioner "github.com/hashicorp/packer/provisioner/windows-restart" windowsshellprovisioner "github.com/hashicorp/packer/provisioner/windows-shell" - - lxdbuilder "github.com/hashicorp/packer/builder/lxd" ) type PluginCommand struct { @@ -78,6 +78,7 @@ type PluginCommand struct { } var Builders = map[string]packer.Builder{ +<<<<<<< HEAD "alicloud-ecs": new(alicloudecsbuilder.Builder), "amazon-chroot": new(amazonchrootbuilder.Builder), "amazon-ebs": new(amazonebsbuilder.Builder), @@ -91,6 +92,7 @@ var Builders = map[string]packer.Builder{ "file": new(filebuilder.Builder), "googlecompute": new(googlecomputebuilder.Builder), "hyperv-iso": new(hypervisobuilder.Builder), + "lxc": new(lxcbuilder.Builder), "lxd": new(lxdbuilder.Builder), "null": new(nullbuilder.Builder), "oneandone": new(oneandonebuilder.Builder), diff --git a/plugin/builder-lxc/main.go b/plugin/builder-lxc/main.go new file mode 100644 index 000000000..8e885232f --- /dev/null +++ b/plugin/builder-lxc/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "github.com/mitchellh/packer/builder/lxc" + "github.com/mitchellh/packer/packer/plugin" +) + +func main() { + server, err := plugin.Server() + if err != nil { + panic(err) + } + server.RegisterBuilder(new(lxc.Builder)) + server.Serve() +} diff --git a/plugin/builder-lxc/main_test.go b/plugin/builder-lxc/main_test.go new file mode 100644 index 000000000..06ab7d0f9 --- /dev/null +++ b/plugin/builder-lxc/main_test.go @@ -0,0 +1 @@ +package main From 341ebdd7e8002df6eb4e43ed7aef890355a2933c Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Wed, 11 May 2016 00:37:01 +0000 Subject: [PATCH 05/21] [lxc] implement interface, add validation --- builder/lxc/communicator.go | 6 +++++- builder/lxc/config.go | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/builder/lxc/communicator.go b/builder/lxc/communicator.go index a1eb50fdb..4d6fab911 100644 --- a/builder/lxc/communicator.go +++ b/builder/lxc/communicator.go @@ -104,6 +104,10 @@ func (c *LxcAttachCommunicator) Download(src string, w io.Writer) error { return nil } +func (c *LxcAttachCommunicator) DownloadDir(src string, dst string, exclude []string) error { + return fmt.Errorf("DownloadDir is not implemented for lxc") +} + func (c *LxcAttachCommunicator) Execute(commandString string) (*exec.Cmd, error) { log.Printf("Executing with lxc-attach in container: %s %s %s", c.ContainerName, c.RootFs, commandString) command, err := c.CmdWrapper( @@ -144,4 +148,4 @@ func (c *LxcAttachCommunicator) CheckInit() (string, error) { } return strings.TrimSpace(string(output)), nil -} \ No newline at end of file +} diff --git a/builder/lxc/config.go b/builder/lxc/config.go index 6c32eeb95..2e05b00f5 100644 --- a/builder/lxc/config.go +++ b/builder/lxc/config.go @@ -8,6 +8,7 @@ import ( "github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate" "time" + "os" ) type Config struct { @@ -62,6 +63,10 @@ func NewConfig(raws ...interface{}) (*Config, error) { errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed parsing init_timeout: %s", err)) } + if _, err := os.Stat(c.ConfigFile); os.IsNotExist(err) { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("LXC Config file appears to be missing: %s", c.ConfigFile)) + } + if errs != nil && len(errs.Errors) > 0 { return nil, errs } From 3a136aad77bbc07d8cae884ae6e6f711ff9fa9da Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Wed, 11 May 2016 01:22:26 +0000 Subject: [PATCH 06/21] [lxc] remove vagrant post processor --- post-processor/vagrant/lxc.go | 30 ------------------------ post-processor/vagrant/lxc_test.go | 9 ------- post-processor/vagrant/post-processor.go | 3 --- 3 files changed, 42 deletions(-) delete mode 100644 post-processor/vagrant/lxc.go delete mode 100644 post-processor/vagrant/lxc_test.go diff --git a/post-processor/vagrant/lxc.go b/post-processor/vagrant/lxc.go deleted file mode 100644 index 24fff2edb..000000000 --- a/post-processor/vagrant/lxc.go +++ /dev/null @@ -1,30 +0,0 @@ -package vagrant - -import ( - "fmt" - "github.com/mitchellh/packer/packer" - "path/filepath" -) - -type LxcProvider struct{} - -func (p *LxcProvider) KeepInputArtifact() bool { - return false -} - -func (p *LxcProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) { - // Create the metadata - metadata = map[string]interface{}{"provider": "lxc", "version": "1.0.0"} - - // Copy all of the original contents into the temporary directory - for _, path := range artifact.Files() { - ui.Message(fmt.Sprintf("Copying: %s", path)) - - dstPath := filepath.Join(dir, filepath.Base(path)) - if err = CopyContents(dstPath, path); err != nil { - return - } - } - - return -} diff --git a/post-processor/vagrant/lxc_test.go b/post-processor/vagrant/lxc_test.go deleted file mode 100644 index f3fbc320c..000000000 --- a/post-processor/vagrant/lxc_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package vagrant - -import ( - "testing" -) - -func TestLxcProvider_impl(t *testing.T) { - var _ Provider = new(LxcProvider) -} diff --git a/post-processor/vagrant/post-processor.go b/post-processor/vagrant/post-processor.go index 9a20ed5ae..aa65b2292 100644 --- a/post-processor/vagrant/post-processor.go +++ b/post-processor/vagrant/post-processor.go @@ -28,7 +28,6 @@ var builtins = map[string]string{ "packer.parallels": "parallels", "MSOpenTech.hyperv": "hyperv", "transcend.qemu": "libvirt", - "ustream.lxc": "lxc", } type Config struct { @@ -233,8 +232,6 @@ func providerForName(name string) Provider { return new(HypervProvider) case "libvirt": return new(LibVirtProvider) - case "lxc": - return new(LxcProvider) default: return nil } From ddbb584235aecce9b7c4f91778fd6371f1beb8a7 Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Sat, 14 May 2016 07:13:49 +0000 Subject: [PATCH 07/21] [lxc] Ubuntu likes runlevel 5 --- builder/lxc/step_wait_init.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builder/lxc/step_wait_init.go b/builder/lxc/step_wait_init.go index 180f83f73..5b7d8c5cb 100644 --- a/builder/lxc/step_wait_init.go +++ b/builder/lxc/step_wait_init.go @@ -92,6 +92,9 @@ func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struc if currentRunlevel == targetRunlevel { log.Printf("Container finished init.") break + } else if currentRunlevel > targetRunlevel { + log.Printf("Expected Runlevel %d, Got Runlevel %s, continuing", targetRunlevel, currentRunlevel) + break } /*log.Println("Attempting SSH connection...") From 15c18c83a9df066d3ced103ba06e8492539811ce Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Mon, 16 May 2016 05:59:39 +0000 Subject: [PATCH 08/21] [lxc] default to target runlevel 3 --- builder/lxc/config.go | 4 ++++ builder/lxc/step_wait_init.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/builder/lxc/config.go b/builder/lxc/config.go index 2e05b00f5..4c4152592 100644 --- a/builder/lxc/config.go +++ b/builder/lxc/config.go @@ -50,6 +50,10 @@ func NewConfig(raws ...interface{}) (*Config, error) { c.ContainerName = fmt.Sprintf("packer-%s", c.PackerBuildName) } + if c.TargetRunlevel == 0 { + c.TargetRunlevel = 3 + } + if c.CommandWrapper == "" { c.CommandWrapper = "{{.Command}}" } diff --git a/builder/lxc/step_wait_init.go b/builder/lxc/step_wait_init.go index 5b7d8c5cb..4b5d28fb2 100644 --- a/builder/lxc/step_wait_init.go +++ b/builder/lxc/step_wait_init.go @@ -93,7 +93,7 @@ func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struc log.Printf("Container finished init.") break } else if currentRunlevel > targetRunlevel { - log.Printf("Expected Runlevel %d, Got Runlevel %s, continuing", targetRunlevel, currentRunlevel) + log.Printf("Expected Runlevel %s, Got Runlevel %s, continuing", targetRunlevel, currentRunlevel) break } From 612c87ee2db675277af547b1d84faffaff2f2041 Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Mon, 16 May 2016 18:02:14 +0000 Subject: [PATCH 09/21] [lxc] add first draft of documentation --- website/source/docs/builders/lxc.html.md | 82 ++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 website/source/docs/builders/lxc.html.md diff --git a/website/source/docs/builders/lxc.html.md b/website/source/docs/builders/lxc.html.md new file mode 100644 index 000000000..b92033724 --- /dev/null +++ b/website/source/docs/builders/lxc.html.md @@ -0,0 +1,82 @@ +--- +description: | + The `lxc` Packer builder builds containers for lxc1. The builder starts an LXC + container, runs provisioners within this container, then exports the container + as a tar.gz of the root file system. +layout: docs +page_title: LXC Builder +... + +# LXC Builder + +Type: `lxc` + +The `lxc` Packer builder builds containers for lxc1. The builder starts an LXC +container, runs provisioners within this container, then exports the container +as a tar.gz of the root file system. + +The LXC builder requires a modern linux kernel and the `lxc` or `lxc1` package. +This builder does not work with LXD. + +## Basic Example + +Below is a fully functioning example. + +``` {.javascript} +{ + "builders": [ + { + "type": "lxc", + "name": "lxc-trusty", + "config_file": "/tmp/lxc/config", + "template_name": "ubuntu", + "template_environment_vars": [ + "SUITE=trusty" + ] + }, + { + "type": "lxc", + "name": "lxc-xenial", + "config_file": "/tmp/lxc/config", + "template_name": "ubuntu", + "template_environment_vars": [ + "SUITE=xenial" + ] + }, + { + "type": "lxc", + "name": "lxc-jessie", + "config_file": "/tmp/lxc/config", + "template_name": "debian", + "template_environment_vars": [ + "SUITE=jessie" + ] + } + ] +} +``` + +## Configuration Reference + +### Required: + +- `config_file` (string) - The path to the lxc configuration file. + +- `template_name` (string) - The LXC template name to use. + +- `template_environment_vars` (array of strings) - Environmental variables to use to build the template with. + +### Optional: + +- `target_runlevel` (int) - The minimum run level to wait for the container to reach. Note some distributions (Ubuntu) simulate run levels and may report 5 rather than 3. + +- `output_directory` (string) - The directory in which to save the exported tar.gz. + +- `container_name` (string) - The name of the LXC container. Usually `/var/lib/lxc/containers/`. + +- `command_wrapper` (string) - Allows you to specify a wrapper command, such as `ssh` so you can execute packer builds on a remote host. + +- `init_timeout` (string) - The timeout in seconds to wait for the the container to start. + +- `template_parameters` (array of strings) - Environmental variables for running `lxc-create`. + From e23920a6b9843457acc0e554477d5f8adca9a1e4 Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Thu, 19 May 2016 05:50:38 +0000 Subject: [PATCH 10/21] [lxc] only build for linux. Ignore vim swp files. --- .gitignore | 1 + builder/lxc/artifact.go | 2 ++ builder/lxc/builder.go | 2 ++ builder/lxc/command.go | 2 ++ builder/lxc/communicator.go | 2 ++ builder/lxc/config.go | 2 ++ builder/lxc/step_export.go | 4 +++- builder/lxc/step_lxc_create.go | 2 ++ builder/lxc/step_prepare_output_dir.go | 2 ++ builder/lxc/step_provision.go | 2 ++ builder/lxc/step_wait_init.go | 2 ++ 11 files changed, 22 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a23e18aec..61bc6fa8c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /website/.sass-cache /website/build .DS_Store +*.swp .vagrant .idea test/.env diff --git a/builder/lxc/artifact.go b/builder/lxc/artifact.go index 9ac57d0cc..9e34bd2fd 100644 --- a/builder/lxc/artifact.go +++ b/builder/lxc/artifact.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/builder.go b/builder/lxc/builder.go index 7d630fe44..ea483dda1 100644 --- a/builder/lxc/builder.go +++ b/builder/lxc/builder.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/command.go b/builder/lxc/command.go index af81cff83..878a3ce2c 100644 --- a/builder/lxc/command.go +++ b/builder/lxc/command.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/communicator.go b/builder/lxc/communicator.go index 4d6fab911..4e3b575bc 100644 --- a/builder/lxc/communicator.go +++ b/builder/lxc/communicator.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/config.go b/builder/lxc/config.go index 4c4152592..79d4653b3 100644 --- a/builder/lxc/config.go +++ b/builder/lxc/config.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/step_export.go b/builder/lxc/step_export.go index 3af9ed7f3..4763d0b68 100644 --- a/builder/lxc/step_export.go +++ b/builder/lxc/step_export.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( @@ -96,4 +98,4 @@ func (s *stepExport) SudoCommand(args ...string) error { log.Printf("stderr: %s", stderrString) return err -} \ No newline at end of file +} diff --git a/builder/lxc/step_lxc_create.go b/builder/lxc/step_lxc_create.go index 070eae680..f78804a5d 100644 --- a/builder/lxc/step_lxc_create.go +++ b/builder/lxc/step_lxc_create.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/step_prepare_output_dir.go b/builder/lxc/step_prepare_output_dir.go index 4b66c0c87..ccd0fc2c3 100644 --- a/builder/lxc/step_prepare_output_dir.go +++ b/builder/lxc/step_prepare_output_dir.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/step_provision.go b/builder/lxc/step_provision.go index b8fe6cd04..913e86d70 100644 --- a/builder/lxc/step_provision.go +++ b/builder/lxc/step_provision.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( diff --git a/builder/lxc/step_wait_init.go b/builder/lxc/step_wait_init.go index 4b5d28fb2..646964272 100644 --- a/builder/lxc/step_wait_init.go +++ b/builder/lxc/step_wait_init.go @@ -1,3 +1,5 @@ +// +build linux + package lxc import ( From 8b4e94d9c633352c7abcb7d6e830b2b32c83fd17 Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Thu, 19 May 2016 06:00:42 +0000 Subject: [PATCH 11/21] [lxc] remove commented code --- builder/lxc/step_wait_init.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/builder/lxc/step_wait_init.go b/builder/lxc/step_wait_init.go index 646964272..c83910bc4 100644 --- a/builder/lxc/step_wait_init.go +++ b/builder/lxc/step_wait_init.go @@ -98,30 +98,6 @@ func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struc log.Printf("Expected Runlevel %s, Got Runlevel %s, continuing", targetRunlevel, currentRunlevel) break } - - /*log.Println("Attempting SSH connection...") - comm, err = ssh.New(config) - if err != nil { - log.Printf("SSH handshake err: %s", err) - - // Only count this as an attempt if we were able to attempt - // to authenticate. Note this is very brittle since it depends - // on the string of the error... but I don't see any other way. - if strings.Contains(err.Error(), "authenticate") { - log.Printf("Detected authentication error. Increasing handshake attempts.") - handshakeAttempts += 1 - } - - if handshakeAttempts < 10 { - // Try to connect via SSH a handful of times - continue - } - - return nil, err - } - - break - */ } return nil From 44c942a21f45fea945c2cd2d93b975c3931225e0 Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Thu, 19 May 2016 06:09:40 +0000 Subject: [PATCH 12/21] [lxc] provide centos 7 example --- website/source/docs/builders/lxc.html.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/website/source/docs/builders/lxc.html.md b/website/source/docs/builders/lxc.html.md index b92033724..2efaaf656 100644 --- a/website/source/docs/builders/lxc.html.md +++ b/website/source/docs/builders/lxc.html.md @@ -51,6 +51,16 @@ Below is a fully functioning example. "template_environment_vars": [ "SUITE=jessie" ] + }, + { + "type": "lxc", + "name": "lxc-centos-7-x64", + "config_file": "/tmp/lxc/config", + "template_name": "centos", + "template_parameters": [ + "-R","7", + "-a","x86_64" + ], } ] } @@ -78,5 +88,5 @@ Below is a fully functioning example. - `init_timeout` (string) - The timeout in seconds to wait for the the container to start. -- `template_parameters` (array of strings) - Environmental variables for running `lxc-create`. +- `template_parameters` (array of strings) - Options to pass to the given `lxc-template` command, usually located in `/usr/share/lxc/templates/lxc-``. Note: This gets passed as ARGV to the template command. Ensure you have an array of strings, as a single string with spaces probably won't work. From db74392528d2ac8e430f7cb71ea8d3c9aaa7f283 Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Thu, 19 May 2016 06:14:11 +0000 Subject: [PATCH 13/21] [lxc] add some words of warning around edge cases --- website/source/docs/builders/lxc.html.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/source/docs/builders/lxc.html.md b/website/source/docs/builders/lxc.html.md index 2efaaf656..4412e4546 100644 --- a/website/source/docs/builders/lxc.html.md +++ b/website/source/docs/builders/lxc.html.md @@ -18,6 +18,11 @@ as a tar.gz of the root file system. The LXC builder requires a modern linux kernel and the `lxc` or `lxc1` package. This builder does not work with LXD. +Note to build Centos images on a Debian family host, you will need the `yum` package installed. + +Some provisioners such as `ansible-local` get confused when running in a container of a different family. +E.G. it will attempt to use `apt-get` to install packages, when running in a Centos container if the parent OS is Debian based. + ## Basic Example Below is a fully functioning example. From 2d19b4f2d22a9f495e77bc0053569a1912534a7f Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Thu, 19 May 2016 06:17:56 +0000 Subject: [PATCH 14/21] Revert "[lxc] only build for linux. Ignore vim swp files." This reverts commit 60409dc678273864dbb29f624a669d00b4cc0134. --- .gitignore | 1 - builder/lxc/artifact.go | 2 -- builder/lxc/builder.go | 2 -- builder/lxc/command.go | 2 -- builder/lxc/communicator.go | 2 -- builder/lxc/config.go | 2 -- builder/lxc/step_export.go | 4 +--- builder/lxc/step_lxc_create.go | 2 -- builder/lxc/step_prepare_output_dir.go | 2 -- builder/lxc/step_provision.go | 2 -- builder/lxc/step_wait_init.go | 2 -- 11 files changed, 1 insertion(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 61bc6fa8c..a23e18aec 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ /website/.sass-cache /website/build .DS_Store -*.swp .vagrant .idea test/.env diff --git a/builder/lxc/artifact.go b/builder/lxc/artifact.go index 9e34bd2fd..9ac57d0cc 100644 --- a/builder/lxc/artifact.go +++ b/builder/lxc/artifact.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/builder.go b/builder/lxc/builder.go index ea483dda1..7d630fe44 100644 --- a/builder/lxc/builder.go +++ b/builder/lxc/builder.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/command.go b/builder/lxc/command.go index 878a3ce2c..af81cff83 100644 --- a/builder/lxc/command.go +++ b/builder/lxc/command.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/communicator.go b/builder/lxc/communicator.go index 4e3b575bc..4d6fab911 100644 --- a/builder/lxc/communicator.go +++ b/builder/lxc/communicator.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/config.go b/builder/lxc/config.go index 79d4653b3..4c4152592 100644 --- a/builder/lxc/config.go +++ b/builder/lxc/config.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/step_export.go b/builder/lxc/step_export.go index 4763d0b68..3af9ed7f3 100644 --- a/builder/lxc/step_export.go +++ b/builder/lxc/step_export.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( @@ -98,4 +96,4 @@ func (s *stepExport) SudoCommand(args ...string) error { log.Printf("stderr: %s", stderrString) return err -} +} \ No newline at end of file diff --git a/builder/lxc/step_lxc_create.go b/builder/lxc/step_lxc_create.go index f78804a5d..070eae680 100644 --- a/builder/lxc/step_lxc_create.go +++ b/builder/lxc/step_lxc_create.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/step_prepare_output_dir.go b/builder/lxc/step_prepare_output_dir.go index ccd0fc2c3..4b66c0c87 100644 --- a/builder/lxc/step_prepare_output_dir.go +++ b/builder/lxc/step_prepare_output_dir.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/step_provision.go b/builder/lxc/step_provision.go index 913e86d70..b8fe6cd04 100644 --- a/builder/lxc/step_provision.go +++ b/builder/lxc/step_provision.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( diff --git a/builder/lxc/step_wait_init.go b/builder/lxc/step_wait_init.go index c83910bc4..d2d58628a 100644 --- a/builder/lxc/step_wait_init.go +++ b/builder/lxc/step_wait_init.go @@ -1,5 +1,3 @@ -// +build linux - package lxc import ( From 986ac9a5015186f7604307353486c1906527fe4d Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Thu, 19 May 2016 06:18:18 +0000 Subject: [PATCH 15/21] [lxc] ignore vim swap files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a23e18aec..31246ce8e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ test/.env *~ *.received.* +*.swp website/.bundle website/vendor From 9b4a7e935fe1ad384d07787e7a90cf5b807898c8 Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Wed, 25 May 2016 19:34:36 +0000 Subject: [PATCH 16/21] [lxc] add basic tests --- builder/lxc/builder_test.go | 56 ++++++++++++++++++++++++++++++++ builder/lxc/communicator.go | 4 +-- builder/lxc/communicator_test.go | 14 ++++++++ 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 builder/lxc/builder_test.go create mode 100644 builder/lxc/communicator_test.go diff --git a/builder/lxc/builder_test.go b/builder/lxc/builder_test.go new file mode 100644 index 000000000..e73cd8b0e --- /dev/null +++ b/builder/lxc/builder_test.go @@ -0,0 +1,56 @@ +package lxc + +import ( + "testing" + "os" + + "github.com/mitchellh/packer/packer" +) + +func testConfig() map[string]interface{} { + return map[string]interface{}{ + "config_file": "builder_test.go", + "template_name": "debian", + "template_environment_vars": "SUITE=jessie", + } +} + +func TestBuilder_Foo(t *testing.T) { + if os.Getenv("PACKER_ACC") == "" { + t.Skip("This test is only run with PACKER_ACC=1") + } +} + +func TestBuilderPrepare_ConfigFile(t *testing.T) { + var b Builder + // Good + config := testConfig() + warnings, err := b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err != nil { + t.Fatalf("should not have error: %s", err) + } + + // Bad, missing config file + config = testConfig() + delete(config, "config_file") + b = Builder{} + warnings, err = b.Prepare(config) + if len(warnings) > 0 { + t.Fatalf("bad: %#v", warnings) + } + if err == nil { + t.Fatalf("should have error") + } + +} + +func TestBuilder_ImplementsBuilder(t *testing.T) { + var raw interface{} + raw = &Builder{} + if _, ok := raw.(packer.Builder); !ok { + t.Fatalf("Builder should be a builder") + } +} diff --git a/builder/lxc/communicator.go b/builder/lxc/communicator.go index 4d6fab911..7a4133057 100644 --- a/builder/lxc/communicator.go +++ b/builder/lxc/communicator.go @@ -9,8 +9,8 @@ import ( "os" "os/exec" "path/filepath" - "syscall" "strings" + "syscall" ) type LxcAttachCommunicator struct { @@ -105,7 +105,7 @@ func (c *LxcAttachCommunicator) Download(src string, w io.Writer) error { } func (c *LxcAttachCommunicator) DownloadDir(src string, dst string, exclude []string) error { - return fmt.Errorf("DownloadDir is not implemented for lxc") + return fmt.Errorf("DownloadDir is not implemented for lxc") } func (c *LxcAttachCommunicator) Execute(commandString string) (*exec.Cmd, error) { diff --git a/builder/lxc/communicator_test.go b/builder/lxc/communicator_test.go new file mode 100644 index 000000000..b8857df47 --- /dev/null +++ b/builder/lxc/communicator_test.go @@ -0,0 +1,14 @@ +package lxc + +import ( + "github.com/mitchellh/packer/packer" + "testing" +) + +func TestCommunicator_ImplementsCommunicator(t *testing.T) { + var raw interface{} + raw = &LxcAttachCommunicator{} + if _, ok := raw.(packer.Communicator); !ok { + t.Fatalf("Communicator should be a communicator") + } +} From 5eb1bc9338e6c8a1919d4805358a4f34cbed813c Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Wed, 25 May 2016 19:34:51 +0000 Subject: [PATCH 17/21] [lxc] go fmt our files --- builder/lxc/artifact.go | 2 +- builder/lxc/builder_test.go | 2 +- builder/lxc/communicator_test.go | 14 +++++++------- builder/lxc/config.go | 2 +- builder/lxc/step_export.go | 19 +++++++++---------- builder/lxc/step_provision.go | 2 +- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/builder/lxc/artifact.go b/builder/lxc/artifact.go index 9ac57d0cc..0a53f70e0 100644 --- a/builder/lxc/artifact.go +++ b/builder/lxc/artifact.go @@ -27,7 +27,7 @@ func (a *Artifact) String() string { } func (a *Artifact) State(name string) interface{} { - return nil + return nil } func (a *Artifact) Destroy() error { diff --git a/builder/lxc/builder_test.go b/builder/lxc/builder_test.go index e73cd8b0e..55bd4a547 100644 --- a/builder/lxc/builder_test.go +++ b/builder/lxc/builder_test.go @@ -1,8 +1,8 @@ package lxc import ( - "testing" "os" + "testing" "github.com/mitchellh/packer/packer" ) diff --git a/builder/lxc/communicator_test.go b/builder/lxc/communicator_test.go index b8857df47..7599bd630 100644 --- a/builder/lxc/communicator_test.go +++ b/builder/lxc/communicator_test.go @@ -1,14 +1,14 @@ package lxc import ( - "github.com/mitchellh/packer/packer" - "testing" + "github.com/mitchellh/packer/packer" + "testing" ) func TestCommunicator_ImplementsCommunicator(t *testing.T) { - var raw interface{} - raw = &LxcAttachCommunicator{} - if _, ok := raw.(packer.Communicator); !ok { - t.Fatalf("Communicator should be a communicator") - } + var raw interface{} + raw = &LxcAttachCommunicator{} + if _, ok := raw.(packer.Communicator); !ok { + t.Fatalf("Communicator should be a communicator") + } } diff --git a/builder/lxc/config.go b/builder/lxc/config.go index 4c4152592..a0f1edb9f 100644 --- a/builder/lxc/config.go +++ b/builder/lxc/config.go @@ -7,8 +7,8 @@ import ( "github.com/mitchellh/packer/helper/config" "github.com/mitchellh/packer/packer" "github.com/mitchellh/packer/template/interpolate" - "time" "os" + "time" ) type Config struct { diff --git a/builder/lxc/step_export.go b/builder/lxc/step_export.go index 3af9ed7f3..bc10a2338 100644 --- a/builder/lxc/step_export.go +++ b/builder/lxc/step_export.go @@ -1,16 +1,16 @@ package lxc import ( - "github.com/mitchellh/multistep" - "fmt" - "github.com/mitchellh/packer/packer" "bytes" - "os/exec" - "log" - "strings" - "path/filepath" - "os" + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" "io" + "log" + "os" + "os/exec" + "path/filepath" + "strings" ) type stepExport struct{} @@ -75,7 +75,6 @@ func (s *stepExport) Run(state multistep.StateBag) multistep.StepAction { func (s *stepExport) Cleanup(state multistep.StateBag) {} - func (s *stepExport) SudoCommand(args ...string) error { var stdout, stderr bytes.Buffer @@ -96,4 +95,4 @@ func (s *stepExport) SudoCommand(args ...string) error { log.Printf("stderr: %s", stderrString) return err -} \ No newline at end of file +} diff --git a/builder/lxc/step_provision.go b/builder/lxc/step_provision.go index b8fe6cd04..8b33373dc 100644 --- a/builder/lxc/step_provision.go +++ b/builder/lxc/step_provision.go @@ -7,7 +7,7 @@ import ( ) // StepProvision provisions the instance within a chroot. -type StepProvision struct {} +type StepProvision struct{} func (s *StepProvision) Run(state multistep.StateBag) multistep.StepAction { hook := state.Get("hook").(packer.Hook) From 34b6c97c2126f6041b89c8b414aef1fc0d0c846c Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Wed, 25 May 2016 21:23:07 +0000 Subject: [PATCH 18/21] [lxc] add bats tests --- test/builder_lxc.bats | 40 ++++++++++++++++++++++++++ test/fixtures/builder-lxc/minimal.json | 15 ++++++++++ 2 files changed, 55 insertions(+) create mode 100644 test/builder_lxc.bats create mode 100644 test/fixtures/builder-lxc/minimal.json diff --git a/test/builder_lxc.bats b/test/builder_lxc.bats new file mode 100644 index 000000000..c29030424 --- /dev/null +++ b/test/builder_lxc.bats @@ -0,0 +1,40 @@ +#!/usr/bin/env bats +# +# This tests the lxc builder. The teardown function will +# delete any images in the output-lxc-* folders. + +#load test_helper +#fixtures builder-lxc +FIXTURE_ROOT="$BATS_TEST_DIRNAME/fixtures/builder-lxc" + +# Required parameters +command -v lxc-create >/dev/null 2>&1 || { + echo "'lxc-create' must be installed via the lxc (or lxc1 for ubuntu >=16.04) package" >&2 + exit 1 +} + +teardown() { + rm -rf output-lxc-* +} + +@test "lxc: build centos minimal.json" { + run packer build -var template_name=centos $FIXTURE_ROOT/minimal.json + [ "$status" -eq 0 ] + [ -f output-lxc-centos/rootfs.tar.gz ] + [ -f output-lxc-centos/lxc-config ] +} + + +@test "lxc: build trusty minimal.json" { + run packer build -var template_name=ubuntu -var template_parameters="SUITE=trusty" $FIXTURE_ROOT/minimal.json + [ "$status" -eq 0 ] + [ -f output-lxc-ubuntu/rootfs.tar.gz ] + [ -f output-lxc-ubuntu/lxc-config ] +} + +@test "lxc: build debian minimal.json" { + run packer build -var template_name=debian -var template_parameters="SUITE=jessie" $FIXTURE_ROOT/minimal.json + [ "$status" -eq 0 ] + [ -f output-lxc-debian/rootfs.tar.gz ] + [ -f output-lxc-debian/lxc-config ] +} diff --git a/test/fixtures/builder-lxc/minimal.json b/test/fixtures/builder-lxc/minimal.json new file mode 100644 index 000000000..5bf7998fd --- /dev/null +++ b/test/fixtures/builder-lxc/minimal.json @@ -0,0 +1,15 @@ +{ + "variables": { + "template_name": "debian", + "template_parameters": "SUITE=jessie" + }, + "builders": [ + { + "type": "lxc", + "name": "lxc-{{user `template_name`}}", + "template_name": "{{user `template_name`}}", + "config_file": "/usr/share/lxc/config/{{user `template_name`}}.common.conf", + "template_environment_vars": [ "{{user `template_parameters`}}" ] + } + ] +} From cd2a783382aa25faecd72c5440491db978c166df Mon Sep 17 00:00:00 2001 From: Chris Lundquist Date: Mon, 4 Sep 2017 18:24:03 +0000 Subject: [PATCH 19/21] [lxc] update to new conventions, improve docs --- builder/lxc/builder.go | 30 ++++-------------------- plugin/builder-lxc/main.go | 4 ++-- plugin/builder-lxc/main_test.go | 1 - website/source/docs/builders/lxc.html.md | 10 ++++---- 4 files changed, 11 insertions(+), 34 deletions(-) delete mode 100644 plugin/builder-lxc/main_test.go diff --git a/builder/lxc/builder.go b/builder/lxc/builder.go index 7d630fe44..2f8fb83b3 100644 --- a/builder/lxc/builder.go +++ b/builder/lxc/builder.go @@ -2,14 +2,13 @@ package lxc import ( "errors" + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/template/interpolate" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/template/interpolate" "log" "os" "path/filepath" - "runtime" ) // The unique ID for this builder @@ -35,10 +34,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { - if runtime.GOOS != "linux" { - return nil, errors.New("The lxc builder only works on linux environments.") - } - wrappedCommand := func(command string) (string, error) { b.config.ctx.Data = &wrappedCommandTemplate{Command: command} return interpolate.Render(b.config.CommandWrapper, &b.config.ctx) @@ -63,15 +58,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe state.Put("wrappedCommand", CommandWrapper(wrappedCommand)) // Run - if b.config.PackerDebug { - b.runner = &multistep.DebugRunner{ - Steps: steps, - PauseFn: common.MultistepDebugFn(ui), - } - } else { - b.runner = &multistep.BasicRunner{Steps: steps} - } - + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, state) b.runner.Run(state) // If there was an error, return that @@ -79,15 +66,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe return nil, rawErr.(error) } - // If we were interrupted or cancelled, then just exit. - if _, ok := state.GetOk(multistep.StateCancelled); ok { - return nil, errors.New("Build was cancelled.") - } - - if _, ok := state.GetOk(multistep.StateHalted); ok { - return nil, errors.New("Build was halted.") - } - // Compile the artifact list files := make([]string, 0, 5) visit := func(path string, info os.FileInfo, err error) error { diff --git a/plugin/builder-lxc/main.go b/plugin/builder-lxc/main.go index 8e885232f..0329b8c8a 100644 --- a/plugin/builder-lxc/main.go +++ b/plugin/builder-lxc/main.go @@ -1,8 +1,8 @@ package main import ( - "github.com/mitchellh/packer/builder/lxc" - "github.com/mitchellh/packer/packer/plugin" + "github.com/hashicorp/packer/builder/lxc" + "github.com/hashicorp/packer/packer/plugin" ) func main() { diff --git a/plugin/builder-lxc/main_test.go b/plugin/builder-lxc/main_test.go deleted file mode 100644 index 06ab7d0f9..000000000 --- a/plugin/builder-lxc/main_test.go +++ /dev/null @@ -1 +0,0 @@ -package main diff --git a/website/source/docs/builders/lxc.html.md b/website/source/docs/builders/lxc.html.md index 4412e4546..6ca1274d1 100644 --- a/website/source/docs/builders/lxc.html.md +++ b/website/source/docs/builders/lxc.html.md @@ -85,13 +85,13 @@ Below is a fully functioning example. - `target_runlevel` (int) - The minimum run level to wait for the container to reach. Note some distributions (Ubuntu) simulate run levels and may report 5 rather than 3. -- `output_directory` (string) - The directory in which to save the exported tar.gz. +- `output_directory` (string) - The directory in which to save the exported tar.gz. Defaults to `output-` in the current directory. -- `container_name` (string) - The name of the LXC container. Usually `/var/lib/lxc/containers/`. +- `container_name` (string) - The name of the LXC container. Usually stored in `/var/lib/lxc/containers/`. Defaults to `packer-`. -- `command_wrapper` (string) - Allows you to specify a wrapper command, such as `ssh` so you can execute packer builds on a remote host. +- `command_wrapper` (string) - Allows you to specify a wrapper command, such as `ssh` so you can execute packer builds on a remote host. Defaults to Empty. -- `init_timeout` (string) - The timeout in seconds to wait for the the container to start. +- `init_timeout` (string) - The timeout in seconds to wait for the the container to start. Defaults to 20 seconds. -- `template_parameters` (array of strings) - Options to pass to the given `lxc-template` command, usually located in `/usr/share/lxc/templates/lxc-``. Note: This gets passed as ARGV to the template command. Ensure you have an array of strings, as a single string with spaces probably won't work. +- `template_parameters` (array of strings) - Options to pass to the given `lxc-template` command, usually located in `/usr/share/lxc/templates/lxc-``. Note: This gets passed as ARGV to the template command. Ensure you have an array of strings, as a single string with spaces probably won't work. Defaults to `[]`. From 8d24b3930a0841f659fb9b13a5e8b9989785fb6d Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Tue, 5 Sep 2017 15:23:22 -0700 Subject: [PATCH 20/21] cleanup imports and rebase artifacts --- builder/lxc/builder.go | 1 - builder/lxc/builder_test.go | 2 +- builder/lxc/communicator.go | 2 +- builder/lxc/communicator_test.go | 2 +- builder/lxc/config.go | 8 ++++---- builder/lxc/step_export.go | 2 +- builder/lxc/step_lxc_create.go | 2 +- builder/lxc/step_prepare_output_dir.go | 2 +- builder/lxc/step_provision.go | 2 +- builder/lxc/step_wait_init.go | 2 +- command/plugin.go | 3 +-- 11 files changed, 13 insertions(+), 15 deletions(-) diff --git a/builder/lxc/builder.go b/builder/lxc/builder.go index 2f8fb83b3..31770b740 100644 --- a/builder/lxc/builder.go +++ b/builder/lxc/builder.go @@ -1,7 +1,6 @@ package lxc import ( - "errors" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/template/interpolate" diff --git a/builder/lxc/builder_test.go b/builder/lxc/builder_test.go index 55bd4a547..4eeb27594 100644 --- a/builder/lxc/builder_test.go +++ b/builder/lxc/builder_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/mitchellh/packer/packer" + "github.com/hashicorp/packer/packer" ) func testConfig() map[string]interface{} { diff --git a/builder/lxc/communicator.go b/builder/lxc/communicator.go index 7a4133057..8d9765979 100644 --- a/builder/lxc/communicator.go +++ b/builder/lxc/communicator.go @@ -2,7 +2,7 @@ package lxc import ( "fmt" - "github.com/mitchellh/packer/packer" + "github.com/hashicorp/packer/packer" "io" "io/ioutil" "log" diff --git a/builder/lxc/communicator_test.go b/builder/lxc/communicator_test.go index 7599bd630..854ba6680 100644 --- a/builder/lxc/communicator_test.go +++ b/builder/lxc/communicator_test.go @@ -1,7 +1,7 @@ package lxc import ( - "github.com/mitchellh/packer/packer" + "github.com/hashicorp/packer/packer" "testing" ) diff --git a/builder/lxc/config.go b/builder/lxc/config.go index a0f1edb9f..c3c28d4fb 100644 --- a/builder/lxc/config.go +++ b/builder/lxc/config.go @@ -2,11 +2,11 @@ package lxc import ( "fmt" + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/helper/config" + "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/template/interpolate" "github.com/mitchellh/mapstructure" - "github.com/mitchellh/packer/common" - "github.com/mitchellh/packer/helper/config" - "github.com/mitchellh/packer/packer" - "github.com/mitchellh/packer/template/interpolate" "os" "time" ) diff --git a/builder/lxc/step_export.go b/builder/lxc/step_export.go index bc10a2338..59e4b79e9 100644 --- a/builder/lxc/step_export.go +++ b/builder/lxc/step_export.go @@ -3,8 +3,8 @@ package lxc import ( "bytes" "fmt" + "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" "io" "log" "os" diff --git a/builder/lxc/step_lxc_create.go b/builder/lxc/step_lxc_create.go index 070eae680..a98926ffa 100644 --- a/builder/lxc/step_lxc_create.go +++ b/builder/lxc/step_lxc_create.go @@ -3,8 +3,8 @@ package lxc import ( "bytes" "fmt" + "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" "log" "os/exec" "path/filepath" diff --git a/builder/lxc/step_prepare_output_dir.go b/builder/lxc/step_prepare_output_dir.go index 4b66c0c87..07c6f08b7 100644 --- a/builder/lxc/step_prepare_output_dir.go +++ b/builder/lxc/step_prepare_output_dir.go @@ -1,8 +1,8 @@ package lxc import ( + "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" "log" "os" "time" diff --git a/builder/lxc/step_provision.go b/builder/lxc/step_provision.go index 8b33373dc..f91eb56ce 100644 --- a/builder/lxc/step_provision.go +++ b/builder/lxc/step_provision.go @@ -1,8 +1,8 @@ package lxc import ( + "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" "log" ) diff --git a/builder/lxc/step_wait_init.go b/builder/lxc/step_wait_init.go index d2d58628a..e5d375312 100644 --- a/builder/lxc/step_wait_init.go +++ b/builder/lxc/step_wait_init.go @@ -3,8 +3,8 @@ package lxc import ( "errors" "fmt" + "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" - "github.com/mitchellh/packer/packer" "log" "strings" "time" diff --git a/command/plugin.go b/command/plugin.go index 2b0d3428c..cc87e81dc 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -27,7 +27,7 @@ import ( googlecomputebuilder "github.com/hashicorp/packer/builder/googlecompute" hypervisobuilder "github.com/hashicorp/packer/builder/hyperv/iso" lxcbuilder "github.com/hashicorp/packer/builder/lxc" - lxdbuilder "github.com/hashicorp/packer/builder/lxd" + lxdbuilder "github.com/hashicorp/packer/builder/lxd" nullbuilder "github.com/hashicorp/packer/builder/null" oneandonebuilder "github.com/hashicorp/packer/builder/oneandone" openstackbuilder "github.com/hashicorp/packer/builder/openstack" @@ -78,7 +78,6 @@ type PluginCommand struct { } var Builders = map[string]packer.Builder{ -<<<<<<< HEAD "alicloud-ecs": new(alicloudecsbuilder.Builder), "amazon-chroot": new(amazonchrootbuilder.Builder), "amazon-ebs": new(amazonebsbuilder.Builder), From 41103cf9cae6d88140f9c182c7f05c0095025578 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Wed, 6 Sep 2017 08:55:39 -0700 Subject: [PATCH 21/21] fix docs --- website/source/docs/builders/lxc.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/docs/builders/lxc.html.md b/website/source/docs/builders/lxc.html.md index 6ca1274d1..0dc207a9e 100644 --- a/website/source/docs/builders/lxc.html.md +++ b/website/source/docs/builders/lxc.html.md @@ -65,7 +65,7 @@ Below is a fully functioning example. "template_parameters": [ "-R","7", "-a","x86_64" - ], + ] } ] }