Merge pull request #3982 from artburkart/close_1195

Support remote ova downloads
This commit is contained in:
Matthew Hooker 2016-11-28 18:49:50 -08:00 committed by GitHub
commit 6c546d4d1f
7 changed files with 138 additions and 90 deletions

View File

@ -70,9 +70,17 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
GuestAdditionsSHA256: b.config.GuestAdditionsSHA256, GuestAdditionsSHA256: b.config.GuestAdditionsSHA256,
Ctx: b.config.ctx, Ctx: b.config.ctx,
}, },
&common.StepDownload{
Checksum: b.config.Checksum,
ChecksumType: b.config.ChecksumType,
Description: "OVF/OVA",
Extension: "ova",
ResultKey: "vm_path",
TargetPath: b.config.TargetPath,
Url: []string{b.config.SourcePath},
},
&StepImport{ &StepImport{
Name: b.config.VMName, Name: b.config.VMName,
SourcePath: b.config.SourcePath,
ImportFlags: b.config.ImportFlags, ImportFlags: b.config.ImportFlags,
}, },
&vboxcommon.StepAttachGuestAdditions{ &vboxcommon.StepAttachGuestAdditions{

View File

@ -2,7 +2,6 @@ package ovf
import ( import (
"fmt" "fmt"
"os"
"strings" "strings"
vboxcommon "github.com/mitchellh/packer/builder/virtualbox/common" vboxcommon "github.com/mitchellh/packer/builder/virtualbox/common"
@ -29,6 +28,9 @@ type Config struct {
BootCommand []string `mapstructure:"boot_command"` BootCommand []string `mapstructure:"boot_command"`
SourcePath string `mapstructure:"source_path"` SourcePath string `mapstructure:"source_path"`
Checksum string `mapstructure:"checksum"`
ChecksumType string `mapstructure:"checksum_type"`
TargetPath string `mapstructure:"target_path"`
GuestAdditionsMode string `mapstructure:"guest_additions_mode"` GuestAdditionsMode string `mapstructure:"guest_additions_mode"`
GuestAdditionsPath string `mapstructure:"guest_additions_path"` GuestAdditionsPath string `mapstructure:"guest_additions_path"`
GuestAdditionsURL string `mapstructure:"guest_additions_url"` GuestAdditionsURL string `mapstructure:"guest_additions_url"`
@ -87,12 +89,15 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
errs = packer.MultiErrorAppend(errs, c.VBoxManagePostConfig.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.VBoxManagePostConfig.Prepare(&c.ctx)...)
errs = packer.MultiErrorAppend(errs, c.VBoxVersionConfig.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.VBoxVersionConfig.Prepare(&c.ctx)...)
c.ChecksumType = strings.ToLower(c.ChecksumType)
c.Checksum = strings.ToLower(c.Checksum)
if c.SourcePath == "" { if c.SourcePath == "" {
errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is required")) errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is required"))
} else { } else {
if _, err := os.Stat(c.SourcePath); err != nil { c.SourcePath, err = common.DownloadableURL(c.SourcePath)
errs = packer.MultiErrorAppend(errs, if err != nil {
fmt.Errorf("source_path is invalid: %s", err)) errs = packer.MultiErrorAppend(errs, fmt.Errorf("source_path is invalid: %s", err))
} }
} }

View File

@ -30,24 +30,6 @@ func getTempFile(t *testing.T) *os.File {
return tf return tf
} }
func testConfigErr(t *testing.T, warns []string, err error) {
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should error")
}
}
func testConfigOk(t *testing.T, warns []string, err error) {
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad: %s", err)
}
}
func TestNewConfig_FloppyFiles(t *testing.T) { func TestNewConfig_FloppyFiles(t *testing.T) {
c := testConfig(t) c := testConfig(t)
floppies_path := "../../../common/test-fixtures/floppies" floppies_path := "../../../common/test-fixtures/floppies"
@ -72,17 +54,38 @@ func TestNewConfig_InvalidFloppies(t *testing.T) {
} }
func TestNewConfig_sourcePath(t *testing.T) { func TestNewConfig_sourcePath(t *testing.T) {
// Bad // Okay, because it gets caught during download
c := testConfig(t) c := testConfig(t)
delete(c, "source_path") delete(c, "source_path")
_, warns, errs := NewConfig(c) _, warns, err := NewConfig(c)
testConfigErr(t, warns, errs) if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatalf("should error with empty `source_path`")
}
// Okay, because it gets caught during download
c = testConfig(t)
c["source_path"] = "/i/dont/exist"
_, warns, err = NewConfig(c)
if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad: %s", err)
}
// Bad // Bad
c = testConfig(t) c = testConfig(t)
c["source_path"] = "/i/dont/exist" c["source_path"] = "ftp://i/dont/exist"
_, warns, errs = NewConfig(c) _, warns, err = NewConfig(c)
testConfigErr(t, warns, errs) if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should error")
}
// Good // Good
tf := getTempFile(t) tf := getTempFile(t)
@ -90,8 +93,13 @@ func TestNewConfig_sourcePath(t *testing.T) {
c = testConfig(t) c = testConfig(t)
c["source_path"] = tf.Name() c["source_path"] = tf.Name()
_, warns, errs = NewConfig(c) _, warns, err = NewConfig(c)
testConfigOk(t, warns, errs) if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad: %s", err)
}
} }
func TestNewConfig_shutdown_timeout(t *testing.T) { func TestNewConfig_shutdown_timeout(t *testing.T) {
@ -102,11 +110,21 @@ func TestNewConfig_shutdown_timeout(t *testing.T) {
// Expect this to fail // Expect this to fail
c["source_path"] = tf.Name() c["source_path"] = tf.Name()
c["shutdown_timeout"] = "NaN" c["shutdown_timeout"] = "NaN"
_, warns, errs := NewConfig(c) _, warns, err := NewConfig(c)
testConfigErr(t, warns, errs) if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err == nil {
t.Fatal("should error")
}
// Passes when given a valid time duration // Passes when given a valid time duration
c["shutdown_timeout"] = "10s" c["shutdown_timeout"] = "10s"
_, warns, errs = NewConfig(c) _, warns, err = NewConfig(c)
testConfigOk(t, warns, errs) if len(warns) > 0 {
t.Fatalf("bad: %#v", warns)
}
if err != nil {
t.Fatalf("bad: %s", err)
}
} }

View File

@ -10,7 +10,6 @@ import (
// This step imports an OVF VM into VirtualBox. // This step imports an OVF VM into VirtualBox.
type StepImport struct { type StepImport struct {
Name string Name string
SourcePath string
ImportFlags []string ImportFlags []string
vmName string vmName string
@ -19,9 +18,10 @@ type StepImport struct {
func (s *StepImport) Run(state multistep.StateBag) multistep.StepAction { func (s *StepImport) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(vboxcommon.Driver) driver := state.Get("driver").(vboxcommon.Driver)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
vmPath := state.Get("vm_path").(string)
ui.Say(fmt.Sprintf("Importing VM: %s", s.SourcePath)) ui.Say(fmt.Sprintf("Importing VM: %s", vmPath))
if err := driver.Import(s.Name, s.SourcePath, s.ImportFlags); err != nil { if err := driver.Import(s.Name, vmPath, s.ImportFlags); err != nil {
err := fmt.Errorf("Error importing VM: %s", err) err := fmt.Errorf("Error importing VM: %s", err)
state.Put("error", err) state.Put("error", err)
ui.Error(err.Error()) ui.Error(err.Error())

View File

@ -12,9 +12,9 @@ func TestStepImport_impl(t *testing.T) {
func TestStepImport(t *testing.T) { func TestStepImport(t *testing.T) {
state := testState(t) state := testState(t)
state.Put("vm_path", "foo")
step := new(StepImport) step := new(StepImport)
step.Name = "bar" step.Name = "bar"
step.SourcePath = "foo"
driver := state.Get("driver").(*vboxcommon.DriverMock) driver := state.Get("driver").(*vboxcommon.DriverMock)
@ -33,9 +33,6 @@ func TestStepImport(t *testing.T) {
if driver.ImportName != step.Name { if driver.ImportName != step.Name {
t.Fatalf("bad: %#v", driver.ImportName) t.Fatalf("bad: %#v", driver.ImportName)
} }
if driver.ImportPath != step.SourcePath {
t.Fatalf("bad: %#v", driver.ImportPath)
}
// Test output state // Test output state
if name, ok := state.GetOk("vmName"); !ok { if name, ok := state.GetOk("vmName"); !ok {

View File

@ -101,9 +101,10 @@ builder.
for the VM. By default, this is 40000 (about 40 GB). for the VM. By default, this is 40000 (about 40 GB).
- `export_opts` (array of strings) - Additional options to pass to the - `export_opts` (array of strings) - Additional options to pass to the
[VBoxManage export](https://www.virtualbox.org/manual/ch08.html#vboxmanage-export). [VBoxManage
This can be useful for passing product information to include in the export](https://www.virtualbox.org/manual/ch08.html#vboxmanage-export). This
resulting appliance file. Packer JSON configuration file example: can be useful for passing product information to include in the resulting
appliance file. Packer JSON configuration file example:
``` {.json} ``` {.json}
{ {
@ -119,12 +120,13 @@ builder.
} }
``` ```
A VirtualBox [VM description](https://www.virtualbox.org/manual/ch08.html#idm3756) A VirtualBox [VM
may contain arbitrary strings; the GUI interprets HTML formatting. description](https://www.virtualbox.org/manual/ch08.html#idm3756) may
However, the JSON format does not allow arbitrary newlines within a contain arbitrary strings; the GUI interprets HTML formatting. However, the
value. Add a multi-line description by preparing the string in the JSON format does not allow arbitrary newlines within a value. Add a
shell before the packer call like this (shell `>` continuation multi-line description by preparing the string in the shell before the
character snipped for easier copy & paste): packer call like this (shell `>` continuation character snipped for easier
copy & paste):
``` {.shell} ``` {.shell}
@ -228,8 +230,8 @@ builder.
to, defaults to "ide". When set to "sata", the drive is attached to an AHCI to, defaults to "ide". When set to "sata", the drive is attached to an AHCI
SATA controller. SATA controller.
- `iso_target_path` (string) - The path where the iso should be saved after - `iso_target_path` (string) - The path where the iso should be saved
download. By default will go in the packer cache, with a hash of the after download. By default will go in the packer cache, with a hash of the
original filename as its name. original filename as its name.
- `iso_urls` (array of strings) - Multiple URLs for the ISO to download. - `iso_urls` (array of strings) - Multiple URLs for the ISO to download.
@ -249,9 +251,9 @@ builder.
name of the build. name of the build.
- `post_shutdown_delay` (string) - The amount of time to wait after shutting - `post_shutdown_delay` (string) - The amount of time to wait after shutting
down the virtual machine. If you get the error `Error removing floppy down the virtual machine. If you get the error
controller`, you might need to set this to `5m` or so. By default, the `Error removing floppy controller`, you might need to set this to `5m`
delay is `0s`, or disabled. or so. By default, the delay is `0s`, or disabled.
- `shutdown_command` (string) - The command to use to gracefully shut down the - `shutdown_command` (string) - The command to use to gracefully shut down the
machine once all the provisioning is done. By default this is an empty machine once all the provisioning is done. By default this is an empty
@ -301,16 +303,15 @@ builder.
machine, without the file extension. By default this is "packer-BUILDNAME", machine, without the file extension. By default this is "packer-BUILDNAME",
where "BUILDNAME" is the name of the build. where "BUILDNAME" is the name of the build.
- `vrdp_bind_address` (string / IP address) - The IP address that should be binded - `vrdp_bind_address` (string / IP address) - The IP address that should be
to for VRDP. By default packer will use 127.0.0.1 for this. If you wish to bind binded to for VRDP. By default packer will use 127.0.0.1 for this. If you
to all interfaces use 0.0.0.0 wish to bind to all interfaces use 0.0.0.0
- `vrdp_port_min` and `vrdp_port_max` (integer) - The minimum and maximum port - `vrdp_port_min` and `vrdp_port_max` (integer) - The minimum and maximum port
to use for VRDP access to the virtual machine. Packer uses a randomly chosen to use for VRDP access to the virtual machine. Packer uses a randomly chosen
port in this range that appears available. By default this is 5900 to 6000. port in this range that appears available. By default this is 5900 to 6000.
The minimum and maximum ports are inclusive. The minimum and maximum ports are inclusive.
## Boot Command ## Boot Command
The `boot_command` configuration is very important: it specifies the keys to The `boot_command` configuration is very important: it specifies the keys to
@ -357,9 +358,11 @@ by the proper key:
- `<leftAltOn>` `<rightAltOn>` - Simulates pressing and holding the alt key. - `<leftAltOn>` `<rightAltOn>` - Simulates pressing and holding the alt key.
- `<leftCtrlOn>` `<rightCtrlOn>` - Simulates pressing and holding the ctrl key. - `<leftCtrlOn>` `<rightCtrlOn>` - Simulates pressing and holding the
ctrl key.
- `<leftShiftOn>` `<rightShiftOn>` - Simulates pressing and holding the shift key. - `<leftShiftOn>` `<rightShiftOn>` - Simulates pressing and holding the
shift key.
- `<leftAltOff>` `<rightAltOff>` - Simulates releasing a held alt key. - `<leftAltOff>` `<rightAltOff>` - Simulates releasing a held alt key.

View File

@ -62,7 +62,7 @@ builder.
### Required: ### Required:
- `source_path` (string) - The path to an OVF or OVA file that acts as the - `source_path` (string) - The path to an OVF or OVA file that acts as the
source of this build. source of this build. It can also be a URL.
- `ssh_username` (string) - The username to use to SSH into the machine once - `ssh_username` (string) - The username to use to SSH into the machine once
the OS is installed. the OS is installed.
@ -82,10 +82,20 @@ builder.
five seconds and one minute 30 seconds, respectively. If this isn't five seconds and one minute 30 seconds, respectively. If this isn't
specified, the default is 10 seconds. specified, the default is 10 seconds.
- `checksum` (string) - The checksum for the OVA file. The type of the
checksum is specified with `checksum_type`, documented below.
- `checksum_type` (string) - The type of the checksum specified in `checksum`.
Valid values are "none", "md5", "sha1", "sha256", or "sha512". Although the
checksum will not be verified when `checksum_type` is set to "none", this is
not recommended since OVA files can be very large and corruption does happen
from time to time.
- `export_opts` (array of strings) - Additional options to pass to the - `export_opts` (array of strings) - Additional options to pass to the
[VBoxManage export](https://www.virtualbox.org/manual/ch08.html#vboxmanage-export). [VBoxManage
This can be useful for passing product information to include in the export](https://www.virtualbox.org/manual/ch08.html#vboxmanage-export). This
resulting appliance file. Packer JSON configuration file example: can be useful for passing product information to include in the resulting
appliance file. Packer JSON configuration file example:
``` {.json} ``` {.json}
{ {
@ -101,12 +111,13 @@ builder.
} }
``` ```
A VirtualBox [VM description](https://www.virtualbox.org/manual/ch08.html#idm3756) A VirtualBox [VM
may contain arbitrary strings; the GUI interprets HTML formatting. description](https://www.virtualbox.org/manual/ch08.html#idm3756) may
However, the JSON format does not allow arbitrary newlines within a contain arbitrary strings; the GUI interprets HTML formatting. However, the
value. Add a multi-line description by preparing the string in the JSON format does not allow arbitrary newlines within a value. Add a
shell before the packer call like this (shell `>` continuation multi-line description by preparing the string in the shell before the
character snipped for easier copy & paste): packer call like this (shell `>` continuation character snipped for easier
copy & paste):
``` {.shell} ``` {.shell}
@ -132,11 +143,11 @@ builder.
and \[\]) are allowed. Directory names are also allowed, which will add all and \[\]) are allowed. Directory names are also allowed, which will add all
the files found in the directory to the floppy. the files found in the directory to the floppy.
- `floppy_dirs` (array of strings) - A list of directories to place onto - `floppy_dirs` (array of strings) - A list of directories to place onto the
the floppy disk recursively. This is similar to the `floppy_files` option floppy disk recursively. This is similar to the `floppy_files` option except
except that the directory structure is preserved. This is useful for when that the directory structure is preserved. This is useful for when your
your floppy disk includes drivers or if you just want to organize it's floppy disk includes drivers or if you just want to organize it's contents
contents as a hierarchy. Wildcard characters (\*, ?, and \[\]) are allowed. as a hierarchy. Wildcard characters (\*, ?, and \[\]) are allowed.
- `format` (string) - Either "ovf" or "ova", this specifies the output format - `format` (string) - Either "ovf" or "ova", this specifies the output format
of the exported virtual machine. This defaults to "ovf". of the exported virtual machine. This defaults to "ovf".
@ -201,9 +212,9 @@ builder.
name of the build. name of the build.
- `post_shutdown_delay` (string) - The amount of time to wait after shutting - `post_shutdown_delay` (string) - The amount of time to wait after shutting
down the virtual machine. If you get the error `Error removing floppy down the virtual machine. If you get the error
controller`, you might need to set this to `5m` or so. By default, the `Error removing floppy controller`, you might need to set this to `5m`
delay is `0s`, or disabled. or so. By default, the delay is `0s`, or disabled.
- `shutdown_command` (string) - The command to use to gracefully shut down the - `shutdown_command` (string) - The command to use to gracefully shut down the
machine once all the provisioning is done. By default this is an empty machine once all the provisioning is done. By default this is an empty
@ -228,6 +239,10 @@ builder.
does not setup forwarded port mapping for SSH requests and uses `ssh_port` does not setup forwarded port mapping for SSH requests and uses `ssh_port`
on the host to communicate to the virtual machine on the host to communicate to the virtual machine
- `target_path` (string) - The path where the OVA should be saved
after download. By default, it will go in the packer cache, with a hash of
the original filename as its name.
- `vboxmanage` (array of array of strings) - Custom `VBoxManage` commands to - `vboxmanage` (array of array of strings) - Custom `VBoxManage` commands to
execute in order to further customize the virtual machine being created. The execute in order to further customize the virtual machine being created. The
value of this is an array of commands to execute. The commands are executed value of this is an array of commands to execute. The commands are executed
@ -254,8 +269,8 @@ builder.
is exported. By default this is "packer-BUILDNAME", where "BUILDNAME" is the is exported. By default this is "packer-BUILDNAME", where "BUILDNAME" is the
name of the build. name of the build.
- `vrdp_bind_address` (string / IP address) - The IP address that should be binded - `vrdp_bind_address` (string / IP address) - The IP address that should be
to for VRDP. By default packer will use 127.0.0.1 for this. binded to for VRDP. By default packer will use 127.0.0.1 for this.
- `vrdp_port_min` and `vrdp_port_max` (integer) - The minimum and maximum port - `vrdp_port_min` and `vrdp_port_max` (integer) - The minimum and maximum port
to use for VRDP access to the virtual machine. Packer uses a randomly chosen to use for VRDP access to the virtual machine. Packer uses a randomly chosen
@ -307,9 +322,11 @@ by the proper key:
- `<leftAltOn>` `<rightAltOn>` - Simulates pressing and holding the alt key. - `<leftAltOn>` `<rightAltOn>` - Simulates pressing and holding the alt key.
- `<leftCtrlOn>` `<rightCtrlOn>` - Simulates pressing and holding the ctrl key. - `<leftCtrlOn>` `<rightCtrlOn>` - Simulates pressing and holding the
ctrl key.
- `<leftShiftOn>` `<rightShiftOn>` - Simulates pressing and holding the shift key. - `<leftShiftOn>` `<rightShiftOn>` - Simulates pressing and holding the
shift key.
- `<leftAltOff>` `<rightAltOff>` - Simulates releasing a held alt key. - `<leftAltOff>` `<rightAltOff>` - Simulates releasing a held alt key.