builder/amazon/chroot: find available device
This commit is contained in:
parent
6b7f59216e
commit
997b81da21
|
@ -24,14 +24,13 @@ type Config struct {
|
||||||
common.PackerConfig `mapstructure:",squash"`
|
common.PackerConfig `mapstructure:",squash"`
|
||||||
awscommon.AccessConfig `mapstructure:",squash"`
|
awscommon.AccessConfig `mapstructure:",squash"`
|
||||||
|
|
||||||
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"`
|
||||||
DevicePrefix string `mapstructure:"device_prefix"`
|
MountCommand string `mapstructure:"mount_command"`
|
||||||
MountCommand string `mapstructure:"mount_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"`
|
||||||
UnmountCommand string `mapstructure:"unmount_command"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Builder struct {
|
type Builder struct {
|
||||||
|
@ -68,10 +67,6 @@ func (b *Builder) Prepare(raws ...interface{}) error {
|
||||||
b.config.CopyFiles = []string{"/etc/resolv.conf"}
|
b.config.CopyFiles = []string{"/etc/resolv.conf"}
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.DevicePath == "" {
|
|
||||||
b.config.DevicePath = "/dev/sdh"
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.config.MountCommand == "" {
|
if b.config.MountCommand == "" {
|
||||||
b.config.MountCommand = "mount"
|
b.config.MountCommand = "mount"
|
||||||
}
|
}
|
||||||
|
@ -128,6 +123,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
steps := []multistep.Step{
|
steps := []multistep.Step{
|
||||||
&StepInstanceInfo{},
|
&StepInstanceInfo{},
|
||||||
&StepSourceAMIInfo{},
|
&StepSourceAMIInfo{},
|
||||||
|
&StepPrepareDevice{},
|
||||||
&StepCreateVolume{},
|
&StepCreateVolume{},
|
||||||
&StepAttachVolume{},
|
&StepAttachVolume{},
|
||||||
&StepMountDevice{},
|
&StepMountDevice{},
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package chroot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AvailableDevice finds an available device and returns it. Note that
|
||||||
|
// you should externally hold a flock or something in order to guarantee
|
||||||
|
// that this device is available across processes.
|
||||||
|
func AvailableDevice() (string, error) {
|
||||||
|
prefix, err := devicePrefix()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
letters := "fghijklmnop"
|
||||||
|
for _, letter := range letters {
|
||||||
|
for i := 1; i < 16; i++ {
|
||||||
|
device := fmt.Sprintf("/dev/%s%c%d", prefix, letter, i)
|
||||||
|
if _, err := os.Stat(device); err != nil {
|
||||||
|
return device, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("available device could not be found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// devicePrefix returns the prefix ("sd" or "xvd" or so on) of the devices
|
||||||
|
// on the system.
|
||||||
|
func devicePrefix() (string, error) {
|
||||||
|
available := []string{"sd", "xvd"}
|
||||||
|
|
||||||
|
f, err := os.Open("/sys/block")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
dirs, err := f.Readdirnames(-1)
|
||||||
|
if dirs != nil && len(dirs) > 0 {
|
||||||
|
for _, dir := range dirs {
|
||||||
|
dirBase := filepath.Base(dir)
|
||||||
|
for _, prefix := range available {
|
||||||
|
if strings.HasPrefix(dirBase, prefix) {
|
||||||
|
return prefix, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("device prefix could not be detected")
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StepAttachVolume attaches the previously created volume to an
|
// StepAttachVolume attaches the previously created volume to an
|
||||||
|
@ -21,16 +22,17 @@ type StepAttachVolume struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StepAttachVolume) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *StepAttachVolume) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
config := state["config"].(*Config)
|
|
||||||
ec2conn := state["ec2"].(*ec2.EC2)
|
ec2conn := state["ec2"].(*ec2.EC2)
|
||||||
|
device := state["device"].(string)
|
||||||
instance := state["instance"].(*ec2.Instance)
|
instance := state["instance"].(*ec2.Instance)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state["ui"].(packer.Ui)
|
||||||
volumeId := state["volume_id"].(string)
|
volumeId := state["volume_id"].(string)
|
||||||
|
|
||||||
device := config.DevicePath
|
// For the API call, it expects "sd" prefixed devices.
|
||||||
|
attachVolume := strings.Replace(device, "/xvd", "/sd", 1)
|
||||||
|
|
||||||
ui.Say("Attaching the root volume...")
|
ui.Say(fmt.Sprintf("Attaching the root volume to %s", attachVolume))
|
||||||
_, err := ec2conn.AttachVolume(volumeId, instance.InstanceId, device)
|
_, err := ec2conn.AttachVolume(volumeId, instance.InstanceId, attachVolume)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Error attaching volume: %s", err)
|
err := fmt.Errorf("Error attaching volume: %s", err)
|
||||||
state["error"] = err
|
state["error"] = err
|
||||||
|
@ -70,7 +72,6 @@ func (s *StepAttachVolume) Run(state map[string]interface{}) multistep.StepActio
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
state["device"] = device
|
|
||||||
state["attach_cleanup"] = s
|
state["attach_cleanup"] = s
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package chroot
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StepPrepareDevice finds an available device and sets it.
|
||||||
|
type StepPrepareDevice struct {
|
||||||
|
mounts []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepPrepareDevice) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
|
config := state["config"].(*Config)
|
||||||
|
ui := state["ui"].(packer.Ui)
|
||||||
|
|
||||||
|
device := config.DevicePath
|
||||||
|
if device == "" {
|
||||||
|
var err error
|
||||||
|
log.Println("Device path not specified, searching for available device...")
|
||||||
|
device, err = AvailableDevice()
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error finding available device: %s", err)
|
||||||
|
state["error"] = err
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(device); err == nil {
|
||||||
|
err := fmt.Errorf("Device is in use: %s", device)
|
||||||
|
state["error"] = err
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Device: %s", device)
|
||||||
|
state["device"] = device
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepPrepareDevice) Cleanup(state map[string]interface{}) {}
|
Loading…
Reference in New Issue