replace command config with wrapper command.
This commit is contained in:
parent
cebbcc51a6
commit
ac496a63dc
|
@ -29,12 +29,9 @@ type Config struct {
|
||||||
ChrootMounts [][]string `mapstructure:"chroot_mounts"`
|
ChrootMounts [][]string `mapstructure:"chroot_mounts"`
|
||||||
CopyFiles []string `mapstructure:"copy_files"`
|
CopyFiles []string `mapstructure:"copy_files"`
|
||||||
DevicePath string `mapstructure:"device_path"`
|
DevicePath string `mapstructure:"device_path"`
|
||||||
MountCommand string `mapstructure:"mount_command"`
|
CommandWrapper string `mapstructure:"command_wrapper"`
|
||||||
ChrootCommand string `mapstructure:"chroot_command"`
|
|
||||||
CopyCommand string `mapstructure:"copy_command"`
|
|
||||||
MountPath string `mapstructure:"mount_path"`
|
MountPath string `mapstructure:"mount_path"`
|
||||||
SourceAmi string `mapstructure:"source_ami"`
|
SourceAmi string `mapstructure:"source_ami"`
|
||||||
UnmountCommand string `mapstructure:"unmount_command"`
|
|
||||||
|
|
||||||
tpl *packer.ConfigTemplate
|
tpl *packer.ConfigTemplate
|
||||||
}
|
}
|
||||||
|
@ -80,26 +77,14 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||||
b.config.CopyFiles = []string{"/etc/resolv.conf"}
|
b.config.CopyFiles = []string{"/etc/resolv.conf"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.MountCommand == "" {
|
if b.config.CommandWrapper == "" {
|
||||||
b.config.MountCommand = "mount"
|
b.config.CommandWrapper = "{{.Command}}"
|
||||||
}
|
|
||||||
|
|
||||||
if b.config.ChrootCommand == "" {
|
|
||||||
b.config.ChrootCommand = "chroot"
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.config.CopyCommand == "" {
|
|
||||||
b.config.CopyCommand = "cp"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.MountPath == "" {
|
if b.config.MountPath == "" {
|
||||||
b.config.MountPath = "packer-amazon-chroot-volumes/{{.Device}}"
|
b.config.MountPath = "packer-amazon-chroot-volumes/{{.Device}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.UnmountCommand == "" {
|
|
||||||
b.config.UnmountCommand = "umount"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Accumulate any errors
|
// Accumulate any errors
|
||||||
errs := common.CheckUnusedConfig(md)
|
errs := common.CheckUnusedConfig(md)
|
||||||
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...)
|
errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...)
|
||||||
|
@ -137,12 +122,8 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
templates := map[string]*string{
|
templates := map[string]*string{
|
||||||
"device_path": &b.config.DevicePath,
|
"device_path": &b.config.DevicePath,
|
||||||
"mount_command": &b.config.MountCommand,
|
"source_ami": &b.config.SourceAmi,
|
||||||
"chroot_command": &b.config.ChrootCommand,
|
|
||||||
"copy_command": &b.config.CopyCommand,
|
|
||||||
"source_ami": &b.config.SourceAmi,
|
|
||||||
"unmount_command": &b.config.UnmountCommand,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for n, ptr := range templates {
|
for n, ptr := range templates {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package chroot
|
package chroot
|
||||||
|
|
||||||
|
// pf := func () { somefunc("a str", 1) }
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
@ -12,18 +14,18 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Command func(string) *exec.Cmd
|
||||||
|
|
||||||
// Communicator is a special communicator that works by executing
|
// Communicator is a special communicator that works by executing
|
||||||
// commands locally but within a chroot.
|
// commands locally but within a chroot.
|
||||||
type Communicator struct {
|
type Communicator struct {
|
||||||
Chroot string
|
Chroot string
|
||||||
ChrootCommand string
|
ChrootCmd Command
|
||||||
CopyCommand string
|
wrappedCommand Command
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
func (c *Communicator) Start(cmd *packer.RemoteCmd) error {
|
||||||
|
localCmd := c.ChrootCmd(cmd.Command)
|
||||||
chrootCommand := fmt.Sprintf("%s %s %s", c.ChrootCommand, c.Chroot, cmd.Command)
|
|
||||||
localCmd := exec.Command("/bin/sh", "-c", chrootCommand)
|
|
||||||
localCmd.Stdin = cmd.Stdin
|
localCmd.Stdin = cmd.Stdin
|
||||||
localCmd.Stdout = cmd.Stdout
|
localCmd.Stdout = cmd.Stdout
|
||||||
localCmd.Stderr = cmd.Stderr
|
localCmd.Stderr = cmd.Stderr
|
||||||
|
@ -64,7 +66,8 @@ func (c *Communicator) Upload(dst string, r io.Reader) error {
|
||||||
}
|
}
|
||||||
defer os.Remove(tf.Name())
|
defer os.Remove(tf.Name())
|
||||||
io.Copy(tf, r)
|
io.Copy(tf, r)
|
||||||
return copySingle(dst, tf.Name(), c.CopyCommand)
|
cpCmd := fmt.Sprintf("cp %s %s", dst, tf.Name())
|
||||||
|
return (*c.ChrootCmd(cpCmd)).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Communicator) UploadDir(dst string, src string, exclude []string) error {
|
func (c *Communicator) UploadDir(dst string, src string, exclude []string) error {
|
||||||
|
@ -87,7 +90,8 @@ func (c *Communicator) UploadDir(dst string, src string, exclude []string) error
|
||||||
|
|
||||||
chrootDest := filepath.Join(c.Chroot, dst, path)
|
chrootDest := filepath.Join(c.Chroot, dst, path)
|
||||||
log.Printf("Uploading to chroot dir: %s", dst)
|
log.Printf("Uploading to chroot dir: %s", dst)
|
||||||
return copySingle(chrootDest, fullPath, c.CopyCommand)
|
cpCmd := fmt.Sprintf("cp %s %s", chrootDest, fullPath)
|
||||||
|
return c.ChrootCmd(cpCmd).Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Uploading directory '%s' to '%s'", src, dst)
|
log.Printf("Uploading directory '%s' to '%s'", src, dst)
|
||||||
|
|
|
@ -2,16 +2,17 @@ package chroot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
|
||||||
"log"
|
"log"
|
||||||
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
func copySingle(dest string, src string, copyCommand string) error {
|
func ChrootCommand(chroot string, command string) *exec.Cmd {
|
||||||
cpCommand := fmt.Sprintf("%s %s %s", copyCommand, src, dest)
|
chrootCommand := fmt.Sprintf("chroot %s %s", chroot, command)
|
||||||
localCmd := exec.Command("/bin/sh", "-c", cpCommand)
|
return ShellCommand(chrootCommand)
|
||||||
log.Printf("Executing copy: %s %#v", localCmd.Path, localCmd.Args)
|
}
|
||||||
if err := localCmd.Run(); err != nil {
|
|
||||||
return err
|
func ShellCommand(command string) *exec.Cmd {
|
||||||
}
|
cmd := exec.Command("/bin/sh", "-c", command)
|
||||||
return nil
|
log.Printf("WrappedCommand(%s) -> #%v", command, cmd.Args)
|
||||||
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
"log"
|
"log"
|
||||||
|
"os/exec"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StepChrootProvision provisions the instance within a chroot.
|
// StepChrootProvision provisions the instance within a chroot.
|
||||||
|
@ -11,17 +12,36 @@ type StepChrootProvision struct {
|
||||||
mounts []string
|
mounts []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WrappedCommandTemplate struct {
|
||||||
|
command string
|
||||||
|
}
|
||||||
|
|
||||||
func (s *StepChrootProvision) Run(state multistep.StateBag) multistep.StepAction {
|
func (s *StepChrootProvision) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
hook := state.Get("hook").(packer.Hook)
|
hook := state.Get("hook").(packer.Hook)
|
||||||
mountPath := state.Get("mount_path").(string)
|
mountPath := state.Get("mount_path").(string)
|
||||||
config := state.Get("config").(*Config)
|
config := state.Get("config").(*Config)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
chrootCmd := func(command string) *exec.Cmd {
|
||||||
|
return ChrootCommand(mountPath, command)
|
||||||
|
}
|
||||||
|
wrappedCommand := func(command string) *exec.Cmd {
|
||||||
|
wrapped, err := config.tpl.Process(config.CommandWrapper, &WrappedCommandTemplate{
|
||||||
|
command: command,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(err.Error())
|
||||||
|
}
|
||||||
|
return ShellCommand(wrapped)
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Put("chrootCmd", chrootCmd)
|
||||||
|
state.Put("wrappedCommand", wrappedCommand)
|
||||||
|
|
||||||
// Create our communicator
|
// Create our communicator
|
||||||
comm := &Communicator{
|
comm := &Communicator{
|
||||||
Chroot: mountPath,
|
Chroot: mountPath,
|
||||||
ChrootCommand: config.ChrootCommand,
|
ChrootCmd: chrootCmd,
|
||||||
CopyCommand: config.CopyCommand,
|
wrappedCommand: wrappedCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provision
|
// Provision
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,6 +21,7 @@ func (s *StepCopyFiles) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
config := state.Get("config").(*Config)
|
config := state.Get("config").(*Config)
|
||||||
mountPath := state.Get("mount_path").(string)
|
mountPath := state.Get("mount_path").(string)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
wrappedCommand := state.Get("wrappedCommand").(Command)
|
||||||
|
|
||||||
s.files = make([]string, 0, len(config.CopyFiles))
|
s.files = make([]string, 0, len(config.CopyFiles))
|
||||||
if len(config.CopyFiles) > 0 {
|
if len(config.CopyFiles) > 0 {
|
||||||
|
@ -31,7 +31,8 @@ func (s *StepCopyFiles) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
chrootPath := filepath.Join(mountPath, path)
|
chrootPath := filepath.Join(mountPath, path)
|
||||||
log.Printf("Copying '%s' to '%s'", path, chrootPath)
|
log.Printf("Copying '%s' to '%s'", path, chrootPath)
|
||||||
|
|
||||||
if err := copySingle(chrootPath, path, config.CopyCommand); err != nil {
|
cmd := fmt.Sprintf("cp %s %s", chrootPath, path)
|
||||||
|
if err := wrappedCommand(cmd); err != nil {
|
||||||
err := fmt.Errorf("Error copying file: %s", err)
|
err := fmt.Errorf("Error copying file: %s", err)
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
|
@ -53,12 +54,13 @@ func (s *StepCopyFiles) Cleanup(state multistep.StateBag) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepCopyFiles) CleanupFunc(multistep.StateBag) error {
|
func (s *StepCopyFiles) CleanupFunc(state multistep.StateBag) error {
|
||||||
|
wrappedCommand := state.Get("wrappedCommand").(Command)
|
||||||
if s.files != nil {
|
if s.files != nil {
|
||||||
for _, file := range s.files {
|
for _, file := range s.files {
|
||||||
log.Printf("Removing: %s", file)
|
log.Printf("Removing: %s", file)
|
||||||
chrootCommand := fmt.Sprintf("rm %s", file)
|
localCmd := wrappedCommand(fmt.Sprintf("rm -f %s", file))
|
||||||
localCmd := exec.Command("/bin/sh", "-c", chrootCommand)
|
log.Println(localCmd.Args)
|
||||||
if err := localCmd.Run(); err != nil {
|
if err := localCmd.Run(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,8 +58,9 @@ func (s *StepMountDevice) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
|
||||||
ui.Say("Mounting the root device...")
|
ui.Say("Mounting the root device...")
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
mountCommand := fmt.Sprintf("%s %s %s", config.MountCommand, device, mountPath)
|
mountCommand := fmt.Sprintf("mount %s %s", device, mountPath)
|
||||||
cmd := exec.Command("/bin/sh", "-c", mountCommand)
|
wrappedCommand := state.Get("wrappedCommand").(Command)
|
||||||
|
cmd := wrappedCommand(mountCommand)
|
||||||
cmd.Stderr = stderr
|
cmd.Stderr = stderr
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
err := fmt.Errorf(
|
err := fmt.Errorf(
|
||||||
|
@ -90,12 +90,12 @@ func (s *StepMountDevice) CleanupFunc(state multistep.StateBag) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config := state.Get("config").(*Config)
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
ui.Say("Unmounting the root device...")
|
ui.Say("Unmounting the root device...")
|
||||||
|
|
||||||
unmountCommand := fmt.Sprintf("%s %s", config.UnmountCommand, s.mountPath)
|
unmountCommand := fmt.Sprintf("umount %s", s.mountPath)
|
||||||
cmd := exec.Command("/bin/sh", "-c", unmountCommand)
|
wrappedCommand := state.Get("wrappedCommand").(Command)
|
||||||
|
cmd := wrappedCommand(unmountCommand)
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return fmt.Errorf("Error unmounting root device: %s", err)
|
return fmt.Errorf("Error unmounting root device: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// StepMountExtra mounts the attached device.
|
// StepMountExtra mounts the attached device.
|
||||||
|
@ -21,6 +20,7 @@ func (s *StepMountExtra) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
config := state.Get("config").(*Config)
|
config := state.Get("config").(*Config)
|
||||||
mountPath := state.Get("mount_path").(string)
|
mountPath := state.Get("mount_path").(string)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
wrappedCommand := state.Get("wrappedCommand").(Command)
|
||||||
|
|
||||||
s.mounts = make([]string, 0, len(config.ChrootMounts))
|
s.mounts = make([]string, 0, len(config.ChrootMounts))
|
||||||
|
|
||||||
|
@ -43,12 +43,11 @@ func (s *StepMountExtra) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
ui.Message(fmt.Sprintf("Mounting: %s", mountInfo[2]))
|
ui.Message(fmt.Sprintf("Mounting: %s", mountInfo[2]))
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
mountCommand := fmt.Sprintf(
|
mountCommand := fmt.Sprintf(
|
||||||
"%s %s %s %s",
|
"mount %s %s %s",
|
||||||
config.MountCommand,
|
|
||||||
flags,
|
flags,
|
||||||
mountInfo[1],
|
mountInfo[1],
|
||||||
innerPath)
|
innerPath)
|
||||||
cmd := exec.Command("/bin/sh", "-c", mountCommand)
|
cmd := wrappedCommand(mountCommand)
|
||||||
cmd.Stderr = stderr
|
cmd.Stderr = stderr
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
err := fmt.Errorf(
|
err := fmt.Errorf(
|
||||||
|
@ -79,15 +78,15 @@ func (s *StepMountExtra) CleanupFunc(state multistep.StateBag) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
config := state.Get("config").(*Config)
|
wrappedCommand := state.Get("wrappedCommand").(Command)
|
||||||
for len(s.mounts) > 0 {
|
for len(s.mounts) > 0 {
|
||||||
var path string
|
var path string
|
||||||
lastIndex := len(s.mounts) - 1
|
lastIndex := len(s.mounts) - 1
|
||||||
path, s.mounts = s.mounts[lastIndex], s.mounts[:lastIndex]
|
path, s.mounts = s.mounts[lastIndex], s.mounts[:lastIndex]
|
||||||
unmountCommand := fmt.Sprintf("%s %s", config.UnmountCommand, path)
|
unmountCommand := fmt.Sprintf("unmount %s", path)
|
||||||
|
|
||||||
stderr := new(bytes.Buffer)
|
stderr := new(bytes.Buffer)
|
||||||
cmd := exec.Command("/bin/sh", "-c", unmountCommand)
|
cmd := wrappedCommand(unmountCommand)
|
||||||
cmd.Stderr = stderr
|
cmd.Stderr = stderr
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
|
|
|
@ -111,9 +111,11 @@ Optional:
|
||||||
of the source AMI will be attached. This defaults to "" (empty string),
|
of the source AMI will be attached. This defaults to "" (empty string),
|
||||||
which forces Packer to find an open device automatically.
|
which forces Packer to find an open device automatically.
|
||||||
|
|
||||||
* `mount_command` (string) - The command to use to mount devices. This
|
* `command_wrapper` (string) - How to run shell commands. This
|
||||||
defaults to "mount". This may be useful to set if you want to set
|
defaults to "{{.Command}}". This may be useful to set if you want to set
|
||||||
environmental variables or perhaps run it with `sudo` or so on.
|
environmental variables or perhaps run it with `sudo` or so on. This is a
|
||||||
|
configuration template where the `.Command` variable is replaced with the
|
||||||
|
command to be run..
|
||||||
|
|
||||||
* `mount_path` (string) - The path where the volume will be mounted. This is
|
* `mount_path` (string) - The path where the volume will be mounted. This is
|
||||||
where the chroot environment will be. This defaults to
|
where the chroot environment will be. This defaults to
|
||||||
|
@ -123,13 +125,6 @@ Optional:
|
||||||
|
|
||||||
* `tags` (object of key/value strings) - Tags applied to the AMI.
|
* `tags` (object of key/value strings) - Tags applied to the AMI.
|
||||||
|
|
||||||
* `unmount_command` (string) - Just like `mount_command`, except this is
|
|
||||||
the command to unmount devices.
|
|
||||||
|
|
||||||
* `chroot_command` (string) - The command to use to create the chroot.
|
|
||||||
This defaults to "chroot", but like `mount_command`, it may be useful
|
|
||||||
to use `sudo` or variables.
|
|
||||||
|
|
||||||
## Basic Example
|
## Basic Example
|
||||||
|
|
||||||
Here is a basic example. It is completely valid except for the access keys:
|
Here is a basic example. It is completely valid except for the access keys:
|
||||||
|
|
Loading…
Reference in New Issue