[lxd] first pass
This commit is contained in:
parent
78f9c8a619
commit
7366b6c78e
|
@ -0,0 +1,35 @@
|
|||
package lxd
|
||||
|
||||
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 "Container"
|
||||
}
|
||||
|
||||
func (a *Artifact) String() string {
|
||||
return fmt.Sprintf("Container 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)
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
package lxd
|
||||
|
||||
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 = "lxd"
|
||||
|
||||
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(stepLxdLaunch),
|
||||
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()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package lxd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
)
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"output_dir": "foo",
|
||||
"image": "bar",
|
||||
}
|
||||
}
|
||||
|
||||
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 image name
|
||||
config = testConfig()
|
||||
delete(config, "image")
|
||||
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")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package lxd
|
||||
|
||||
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)
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package lxd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type Communicator struct {
|
||||
RootFs string
|
||||
ContainerName string
|
||||
CmdWrapper CommandWrapper
|
||||
}
|
||||
|
||||
func (c *Communicator) 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 *Communicator) 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 *Communicator) 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 *Communicator) 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 *Communicator) DownloadDir(src string, dst string, exclude []string) error {
|
||||
return fmt.Errorf("DownloadDir is not implemented for lxc")
|
||||
}
|
||||
|
||||
func (c *Communicator) 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 *Communicator) 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
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package lxd
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommunicator_ImplementsCommunicator(t *testing.T) {
|
||||
var raw interface{}
|
||||
raw = &Communicator{}
|
||||
if _, ok := raw.(packer.Communicator); !ok {
|
||||
t.Fatalf("Communicator should be a communicator")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package lxd
|
||||
|
||||
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_dir"`
|
||||
ContainerName string `mapstructure:"container_name"`
|
||||
CommandWrapper string `mapstructure:"command_wrapper"`
|
||||
RawInitTimeout string `mapstructure:"init_timeout"`
|
||||
Image string `mapstructure:"image"`
|
||||
Remote string `mapstructure:"remote"`
|
||||
//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"
|
||||
}
|
||||
|
||||
if c.Image == "" {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("`image` is a required parameter for LXD."))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package lxd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
//outputPath := filepath.Join(config.OutputDir, "rootfs.tar.gz")
|
||||
|
||||
commands := make([][]string, 3)
|
||||
commands[0] = []string{
|
||||
"lxc", "stop", name,
|
||||
}
|
||||
commands[1] = []string{
|
||||
"lxc", "export",
|
||||
}
|
||||
//commands[1] = []string{
|
||||
// "tar", "-C", containerDir, "--numeric-owner", "--anchored", "--exclude=./rootfs/dev/log", "-czf", outputPath, "./rootfs",
|
||||
//}
|
||||
commands[2] = []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
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package lxd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type stepLxdLaunch struct{}
|
||||
|
||||
func (s *stepLxdLaunch) Run(state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
name := config.ContainerName
|
||||
image := config.Image
|
||||
remote := config.Remote
|
||||
|
||||
commands := make([][]string, 1)
|
||||
if remote == "" {
|
||||
commands[0] = []string{"lxc", "launch", image, name}
|
||||
} else {
|
||||
|
||||
commands[0] = []string{"lxc", "launch", fmt.Sprintf("%s:%s", remote, image), name}
|
||||
}
|
||||
//commands[0] = append(commands[0], config.Parameters...)
|
||||
// todo: wait for init to finish before moving on to provisioning instead of this
|
||||
|
||||
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 *stepLxdLaunch) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
command := []string{
|
||||
"lxc", "delete", "--force", config.ContainerName,
|
||||
}
|
||||
|
||||
ui.Say("Unregistering and deleting deleting container...")
|
||||
if err := s.SudoCommand(command...); err != nil {
|
||||
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
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package lxd
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package lxd
|
||||
|
||||
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)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
||||
|
||||
// Create our communicator
|
||||
comm := &Communicator{
|
||||
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) {}
|
|
@ -69,6 +69,8 @@ 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 {
|
||||
|
@ -89,6 +91,7 @@ var Builders = map[string]packer.Builder{
|
|||
"file": new(filebuilder.Builder),
|
||||
"googlecompute": new(googlecomputebuilder.Builder),
|
||||
"hyperv-iso": new(hypervisobuilder.Builder),
|
||||
"lxd": new(lxdbuilder.Builder),
|
||||
"null": new(nullbuilder.Builder),
|
||||
"oneandone": new(oneandonebuilder.Builder),
|
||||
"openstack": new(openstackbuilder.Builder),
|
||||
|
|
Loading…
Reference in New Issue