Commit e422d45f authored by Ross Smith II's avatar Ross Smith II

Allow wildcards and directories for floppy_files parameter

parent 8cdd784e
......@@ -11,6 +11,7 @@ import (
"log"
"os"
"path/filepath"
"strings"
)
// StepCreateFloppy will create a floppy disk with the given files.
......@@ -20,6 +21,8 @@ type StepCreateFloppy struct {
Files []string
floppyPath string
FilesAdded map[string]bool
}
func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
......@@ -28,6 +31,8 @@ func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionContinue
}
s.FilesAdded = make(map[string]bool)
ui := state.Get("ui").(packer.Ui)
ui.Say("Creating floppy disk...")
......@@ -43,7 +48,7 @@ func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
// Set the path so we can remove it later
s.floppyPath = floppyF.Name()
log.Printf("Floppy path: %s", floppyF.Name())
log.Printf("Floppy path: %s", s.floppyPath)
// Set the size of the file to be a floppy sized
if err := floppyF.Truncate(1440 * 1024); err != nil {
......@@ -89,8 +94,8 @@ func (s *StepCreateFloppy) Run(state multistep.StateBag) multistep.StepAction {
// Go over each file and copy it.
for _, filename := range s.Files {
ui.Message(fmt.Sprintf("Copying: %s", filepath.Base(filename)))
if err := s.addSingleFile(rootDir, filename); err != nil {
ui.Message(fmt.Sprintf("Copying: %s", filename))
if err := s.addFilespec(rootDir, filename); err != nil {
state.Put("error", fmt.Errorf("Error adding file to floppy: %s", err))
return multistep.ActionHalt
}
......@@ -109,6 +114,61 @@ func (s *StepCreateFloppy) Cleanup(multistep.StateBag) {
}
}
func (s *StepCreateFloppy) addFilespec(dir fs.Directory, src string) error {
// same as http://golang.org/src/pkg/path/filepath/match.go#L308
if strings.IndexAny(src, "*?[") >= 0 {
matches, err := filepath.Glob(src)
if err != nil {
return err
}
return s.addFiles(dir, matches)
}
finfo, err := os.Stat(src)
if err != nil {
return err
}
if finfo.IsDir() {
return s.addDirectory(dir, src)
}
return s.addSingleFile(dir, src)
}
func (s *StepCreateFloppy) addFiles(dir fs.Directory, files []string) error {
for _, file := range files {
err := s.addFilespec(dir, file)
if err != nil {
return err
}
}
return nil
}
func (s *StepCreateFloppy) addDirectory(dir fs.Directory, src string) error {
log.Printf("Adding directory to floppy: %s", src)
walkFn := func(path string, finfo os.FileInfo, err error) error {
if err != nil {
return err
}
if path == src {
return nil
}
if finfo.IsDir() {
return s.addDirectory(dir, path)
}
return s.addSingleFile(dir, path)
}
return filepath.Walk(src, walkFn)
}
func (s *StepCreateFloppy) addSingleFile(dir fs.Directory, src string) error {
log.Printf("Adding file to floppy: %s", src)
......@@ -132,5 +192,7 @@ func (s *StepCreateFloppy) addSingleFile(dir fs.Directory, src string) error {
return err
}
s.FilesAdded[src] = true
return nil
}
package common
import (
"bytes"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"io/ioutil"
"os"
"path"
"strconv"
"testing"
)
func TestStepCreateFloppy_Impl(t *testing.T) {
var raw interface{}
raw = new(StepCreateFloppy)
if _, ok := raw.(multistep.Step); !ok {
t.Fatalf("StepCreateFloppy should be a step")
}
}
func testStepCreateFloppyState(t *testing.T) multistep.StateBag {
state := new(multistep.BasicStateBag)
state.Put("ui", &packer.BasicUi{
Reader: new(bytes.Buffer),
Writer: new(bytes.Buffer),
})
return state
}
func TestStepCreateFloppy(t *testing.T) {
state := testStepCreateFloppyState(t)
step := new(StepCreateFloppy)
dir, err := ioutil.TempDir("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)
count := 10
expected := count
files := make([]string, count)
prefix := "exists"
ext := ".tmp"
for i := 0; i < expected; i++ {
files[i] = path.Join(dir, prefix + strconv.Itoa(i) + ext)
_, err := os.Create(files[i])
if err != nil {
t.Fatalf("err: %s", err)
}
}
lists := [][]string{
files,
[]string{dir + string(os.PathSeparator) + prefix + "*" + ext},
[]string{dir + string(os.PathSeparator) + prefix + "?" + ext},
[]string{dir + string(os.PathSeparator) + prefix + "[0123456789]" + ext},
[]string{dir + string(os.PathSeparator) + prefix + "[0-9]" + ext},
[]string{dir + string(os.PathSeparator)},
[]string{dir},
}
for _, step.Files = range lists {
if action := step.Run(state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v for %v", action, step.Files)
}
if _, ok := state.GetOk("error"); ok {
t.Fatalf("state should be ok for %v", step.Files)
}
floppy_path := state.Get("floppy_path").(string)
if _, err := os.Stat(floppy_path); err != nil {
t.Fatal("file not found: %s for %v", floppy_path, step.Files)
}
if len(step.FilesAdded) != expected {
t.Fatalf("expected %d, found %d for %v", expected, len(step.FilesAdded), step.Files)
}
step.Cleanup(state)
if _, err := os.Stat(floppy_path); err == nil {
t.Fatal("file found: %s for %v", floppy_path, step.Files)
}
}
}
func xxxTestStepCreateFloppy_missing(t *testing.T) {
state := testStepCreateFloppyState(t)
step := new(StepCreateFloppy)
dir, err := ioutil.TempDir("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)
count := 2
expected := 0
files := make([]string, count)
prefix := "missing"
for i := 0; i < count; i++ {
files[i] = path.Join(dir, prefix + strconv.Itoa(i))
}
lists := [][]string{
files,
}
for _, step.Files = range lists {
if action := step.Run(state); action != multistep.ActionHalt {
t.Fatalf("bad action: %#v for %v", action, step.Files)
}
if _, ok := state.GetOk("error"); !ok {
t.Fatalf("state should not be ok for %v", step.Files)
}
floppy_path := state.Get("floppy_path")
if floppy_path != nil {
t.Fatalf("floppy_path is not nil for %v", step.Files)
}
if len(step.FilesAdded) != expected {
t.Fatalf("expected %d, found %d for %v", expected, len(step.FilesAdded), step.Files)
}
}
}
func xxxTestStepCreateFloppy_notfound(t *testing.T) {
state := testStepCreateFloppyState(t)
step := new(StepCreateFloppy)
dir, err := ioutil.TempDir("", "packer")
if err != nil {
t.Fatalf("err: %s", err)
}
defer os.RemoveAll(dir)
count := 2
expected := 0
files := make([]string, count)
prefix := "notfound"
for i := 0; i < count; i++ {
files[i] = path.Join(dir, prefix + strconv.Itoa(i))
}
lists := [][]string{
[]string{dir + string(os.PathSeparator) + prefix + "*"},
[]string{dir + string(os.PathSeparator) + prefix + "?"},
[]string{dir + string(os.PathSeparator) + prefix + "[0123456789]"},
[]string{dir + string(os.PathSeparator) + prefix + "[0-9]"},
[]string{dir + string(os.PathSeparator)},
[]string{dir},
}
for _, step.Files = range lists {
if action := step.Run(state); action != multistep.ActionContinue {
t.Fatalf("bad action: %#v for %v", action, step.Files)
}
if _, ok := state.GetOk("error"); ok {
t.Fatalf("state should be ok for %v", step.Files)
}
floppy_path := state.Get("floppy_path").(string)
if _, err := os.Stat(floppy_path); err != nil {
t.Fatal("file not found: %s for %v", floppy_path, step.Files)
}
if len(step.FilesAdded) != expected {
t.Fatalf("expected %d, found %d for %v", expected, len(step.FilesAdded), step.Files)
}
step.Cleanup(state)
if _, err := os.Stat(floppy_path); err == nil {
t.Fatal("file found: %s for %v", floppy_path, step.Files)
}
}
}
......@@ -119,12 +119,14 @@ Optional:
format of the virtual machine image. This defaults to "qcow2".
* `floppy_files` (array of strings) - A list of files to place onto a floppy
disk that gets attached when Packer powers up the VM. This is most useful
disk that is attached when the VM is booted. This is most useful
for unattended Windows installs, which look for an `Autounattend.xml` file
on removable media. By default no floppy will be attached. All files
on removable media. By default, no floppy will be attached. All files
listed in this setting get placed into the root directory of the floppy
and teh floppy is attached as the first floppy device. Currently, no
support exists for sub-directories.
and the floppy is attached as the first floppy device. Currently, no
support exists for creating sub-directories on the floppy. Wildcard
characters (*, ?, and []) are allowed. Directory names are also allowed,
which will add all the files found in the directory to the floppy.
* `headless` (bool) - Packer defaults to building virtual machines by
launching a GUI that shows the console of the machine being built.
......
......@@ -85,12 +85,15 @@ Optional:
* `disk_size` (int) - The size, in megabytes, of the hard disk to create
for the VM. By default, this is 40000 (about 40 GB).
* `floppy_files` (array of strings) - A list of files to put onto a floppy
disk that is attached when the VM is booted for the first time. This is
most useful for unattended Windows installs, which look for an
`Autounattend.xml` file on removable media. By default no floppy will
be attached. The files listed in this configuration will all be put
into the root directory of the floppy disk; sub-directories are not supported.
* `floppy_files` (array of strings) - A list of files to place onto a floppy
disk that is attached when the VM is booted. This is most useful
for unattended Windows installs, which look for an `Autounattend.xml` file
on removable media. By default, no floppy will be attached. All files
listed in this setting get placed into the root directory of the floppy
and the floppy is attached as the first floppy device. Currently, no
support exists for creating sub-directories on the floppy. Wildcard
characters (*, ?, and []) are allowed. Directory names are also allowed,
which will add all the files found in the directory to the floppy.
* `format` (string) - Either "ovf" or "ova", this specifies the output
format of the exported virtual machine. This defaults to "ovf".
......
......@@ -52,12 +52,15 @@ Required:
Optional:
* `floppy_files` (array of strings) - A list of files to put onto a floppy
disk that is attached when the VM is booted for the first time. This is
most useful for unattended Windows installs, which look for an
`Autounattend.xml` file on removable media. By default no floppy will
be attached. The files listed in this configuration will all be put
into the root directory of the floppy disk; sub-directories are not supported.
* `floppy_files` (array of strings) - A list of files to place onto a floppy
disk that is attached when the VM is booted. This is most useful
for unattended Windows installs, which look for an `Autounattend.xml` file
on removable media. By default, no floppy will be attached. All files
listed in this setting get placed into the root directory of the floppy
and the floppy is attached as the first floppy device. Currently, no
support exists for creating sub-directories on the floppy. Wildcard
characters (*, ?, and []) are allowed. Directory names are also allowed,
which will add all the files found in the directory to the floppy.
* `format` (string) - Either "ovf" or "ova", this specifies the output
format of the exported virtual machine. This defaults to "ovf".
......
......@@ -95,12 +95,15 @@ Optional:
[Virtual Disk Manager User's Guide](http://www.vmware.com/pdf/VirtualDiskManager.pdf)
for desktop VMware clients. For ESXi, refer to the proper ESXi documentation.
* `floppy_files` (array of strings) - A list of files to put onto a floppy
disk that is attached when the VM is booted for the first time. This is
most useful for unattended Windows installs, which look for an
`Autounattend.xml` file on removable media. By default no floppy will
be attached. The files listed in this configuration will all be put
into the root directory of the floppy disk; sub-directories are not supported.
* `floppy_files` (array of strings) - A list of files to place onto a floppy
disk that is attached when the VM is booted. This is most useful
for unattended Windows installs, which look for an `Autounattend.xml` file
on removable media. By default, no floppy will be attached. All files
listed in this setting get placed into the root directory of the floppy
and the floppy is attached as the first floppy device. Currently, no
support exists for creating sub-directories on the floppy. Wildcard
characters (*, ?, and []) are allowed. Directory names are also allowed,
which will add all the files found in the directory to the floppy.
* `fusion_app_path` (string) - Path to "VMware Fusion.app". By default this
is "/Applications/VMware Fusion.app" but this setting allows you to
......@@ -186,7 +189,7 @@ Optional:
VM being prepared by some other process (kickstart, etc.).
* `ssh_host` (string) - Hostname or IP address of the host. By default, DHCP
is used to connect to the host and this field is not used.
is used to connect to the host and this field is not used.
* `ssh_password` (string) - The password for `ssh_username` to use to
authenticate with SSH. By default this is the empty string.
......
......@@ -57,12 +57,15 @@ Optional:
five seconds and one minute 30 seconds, respectively. If this isn't specified,
the default is 10 seconds.
* `floppy_files` (array of strings) - A list of files to put onto a floppy
disk that is attached when the VM is booted for the first time. This is
most useful for unattended Windows installs, which look for an
`Autounattend.xml` file on removable media. By default no floppy will
be attached. The files listed in this configuration will all be put
into the root directory of the floppy disk; sub-directories are not supported.
* `floppy_files` (array of strings) - A list of files to place onto a floppy
disk that is attached when the VM is booted. This is most useful
for unattended Windows installs, which look for an `Autounattend.xml` file
on removable media. By default, no floppy will be attached. All files
listed in this setting get placed into the root directory of the floppy
and the floppy is attached as the first floppy device. Currently, no
support exists for creating sub-directories on the floppy. Wildcard
characters (*, ?, and []) are allowed. Directory names are also allowed,
which will add all the files found in the directory to the floppy.
* `fusion_app_path` (string) - Path to "VMware Fusion.app". By default this
is "/Applications/VMware Fusion.app" but this setting allows you to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment