diff --git a/clone/builder.go b/clone/builder.go index 2d2c1b585..d0daf470f 100644 --- a/clone/builder.go +++ b/clone/builder.go @@ -52,6 +52,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe steps = append(steps, &common.StepRun{ Config: &b.config.RunConfig, + SetOrder: false, }, &common.StepWaitForIp{}, &communicator.StepConnect{ diff --git a/clone/builder_acc_test.go b/clone/builder_acc_test.go index 8ce956bd5..652f9634a 100644 --- a/clone/builder_acc_test.go +++ b/clone/builder_acc_test.go @@ -419,6 +419,7 @@ func TestCloneBuilderAcc_sshPassword(t *testing.T) { builderT.Test(t, builderT.TestCase{ Builder: &Builder{}, Template: sshPasswordConfig(), + Check: checkDefaultBootOrder(t), }) } @@ -430,6 +431,25 @@ func sshPasswordConfig() string { return commonT.RenderConfig(config) } +func checkDefaultBootOrder(t *testing.T) builderT.TestCheckFunc { + return func(artifacts []packer.Artifact) error { + d := commonT.TestConn(t) + vm := commonT.GetVM(t, d, artifacts) + + vmInfo, err := vm.Info("config.bootOptions") + if err != nil { + t.Fatalf("Cannot read VM properties: %v", err) + } + + order := vmInfo.Config.BootOptions.BootOrder + if order != nil { + t.Errorf("Boot order must be empty") + } + + return nil + } +} + func TestCloneBuilderAcc_sshKey(t *testing.T) { builderT.Test(t, builderT.TestCase{ Builder: &Builder{}, @@ -510,3 +530,41 @@ func checkTemplate(t *testing.T) builderT.TestCheckFunc { return nil } } + +func TestCloneBuilderAcc_bootOrder(t *testing.T) { + builderT.Test(t, builderT.TestCase{ + Builder: &Builder{}, + Template: bootOrderConfig(), + Check: checkBootOrder(t), + }) +} + +func bootOrderConfig() string { + config := defaultConfig() + config["communicator"] = "ssh" + config["ssh_username"] = "root" + config["ssh_password"] = "jetbrains" + + config["boot_order"] = "disk,cdrom,floppy" + + return commonT.RenderConfig(config) +} + +func checkBootOrder(t *testing.T) builderT.TestCheckFunc { + return func(artifacts []packer.Artifact) error { + d := commonT.TestConn(t) + vm := commonT.GetVM(t, d, artifacts) + + vmInfo, err := vm.Info("config.bootOptions") + if err != nil { + t.Fatalf("Cannot read VM properties: %v", err) + } + + order := vmInfo.Config.BootOptions.BootOrder + if order == nil { + t.Errorf("Boot order must not be empty") + } + + return nil + } +} diff --git a/common/step_run.go b/common/step_run.go index 82ba99f37..1f1ef57de 100644 --- a/common/step_run.go +++ b/common/step_run.go @@ -12,16 +12,9 @@ type RunConfig struct { BootOrder string `mapstructure:"boot_order"` // example: "floppy,cdrom,ethernet,disk" } -func (c *RunConfig) Prepare() []error { - if c.BootOrder == "" { - c.BootOrder = "disk,cdrom" - } - - return nil -} - type StepRun struct { Config *RunConfig + SetOrder bool } func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { @@ -35,6 +28,14 @@ func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.Ste state.Put("error", err) return multistep.ActionHalt } + } else { + if s.SetOrder { + ui.Say("Set boot order temporary...") + if err := vm.SetBootOrder([]string{"disk", "cdrom"}); err != nil { + state.Put("error", err) + return multistep.ActionHalt + } + } } ui.Say("Power on VM...") @@ -48,15 +49,23 @@ func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.Ste } func (s *StepRun) Cleanup(state multistep.StateBag) { + ui := state.Get("ui").(packer.Ui) + vm := state.Get("vm").(*driver.VirtualMachine) + + if s.Config.BootOrder == "" && s.SetOrder { + ui.Say("Clear boot order...") + if err := vm.SetBootOrder([]string{"-"}); err != nil { + state.Put("error", err) + return + } + } + _, cancelled := state.GetOk(multistep.StateCancelled) _, halted := state.GetOk(multistep.StateHalted) if !cancelled && !halted { return } - ui := state.Get("ui").(packer.Ui) - vm := state.Get("vm").(*driver.VirtualMachine) - ui.Say("Power off VM...") err := vm.PowerOff() diff --git a/iso/builder.go b/iso/builder.go index 04e253534..556c98539 100644 --- a/iso/builder.go +++ b/iso/builder.go @@ -64,6 +64,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe }, &common.StepRun{ Config: &b.config.RunConfig, + SetOrder: true, }, &StepBootCommand{ Config: &b.config.BootConfig, diff --git a/iso/builder_acc_test.go b/iso/builder_acc_test.go index 6d2ceec6a..1a7b15f7a 100644 --- a/iso/builder_acc_test.go +++ b/iso/builder_acc_test.go @@ -1,13 +1,13 @@ package iso import ( - builderT "github.com/hashicorp/packer/helper/builder/testing" - commonT "github.com/jetbrains-infra/packer-builder-vsphere/common/testing" - "testing" - "github.com/hashicorp/packer/packer" - "github.com/vmware/govmomi/vim25/types" "fmt" + builderT "github.com/hashicorp/packer/helper/builder/testing" + "github.com/hashicorp/packer/packer" + commonT "github.com/jetbrains-infra/packer-builder-vsphere/common/testing" + "github.com/vmware/govmomi/vim25/types" "io/ioutil" + "testing" ) func TestISOBuilderAcc_default(t *testing.T) { @@ -278,3 +278,111 @@ func createFloppyConfig(filePath string) string { config["floppy_files"] = []string{filePath} return commonT.RenderConfig(config) } + +func TestISOBuilderAcc_full(t *testing.T) { + config := fullConfig() + builderT.Test(t, builderT.TestCase{ + Builder: &Builder{}, + Template: commonT.RenderConfig(config), + Check: checkFull(t), + }) +} + +func fullConfig() map[string]interface{} { + config := map[string]interface{}{ + "vcenter_server": "vcenter.vsphere65.test", + "username": "root", + "password": "jetbrains", + "insecure_connection": true, + + "vm_name": commonT.NewVMName(), + "host": "esxi-1.vsphere65.test", + + "RAM": 1024, + "disk_controller_type": "pvscsi", + "disk_size": 4096, + "disk_thin_provisioned": true, + "network_card": "vmxnet3", + "guest_os_type": "ubuntu64Guest", + + "iso_paths": []string{ + "[datastore1] ISO/ubuntu-16.04.3-server-amd64.iso", + }, + "floppy_files": []string{ + "preseed.cfg", + }, + + "boot_command": []string{ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "/install/vmlinuz", + " initrd=/install/initrd.gz", + " priority=critical", + " locale=en_US", + " file=/media/preseed.cfg", + "", + }, + + "ssh_username": "jetbrains", + "ssh_password": "jetbrains", + } + + return config +} + +func checkFull(t *testing.T) builderT.TestCheckFunc { + return func(artifacts []packer.Artifact) error { + d := commonT.TestConn(t) + vm := commonT.GetVM(t, d, artifacts) + + vmInfo, err := vm.Info("config.bootOptions") + if err != nil { + t.Fatalf("Cannot read VM properties: %v", err) + } + + order := vmInfo.Config.BootOptions.BootOrder + if order != nil { + t.Errorf("Boot order must be empty") + } + + return nil + } +} + +func TestISOBuilderAcc_bootOrder(t *testing.T) { + config := fullConfig() + config["boot_order"] = "disk,cdrom,floppy" + + builderT.Test(t, builderT.TestCase{ + Builder: &Builder{}, + Template: commonT.RenderConfig(config), + Check: checkBootOrder(t), + }) +} + +func checkBootOrder(t *testing.T) builderT.TestCheckFunc { + return func(artifacts []packer.Artifact) error { + d := commonT.TestConn(t) + vm := commonT.GetVM(t, d, artifacts) + + vmInfo, err := vm.Info("config.bootOptions") + if err != nil { + t.Fatalf("Cannot read VM properties: %v", err) + } + + order := vmInfo.Config.BootOptions.BootOrder + if order == nil { + t.Errorf("Boot order must not be empty") + } + + return nil + } +} diff --git a/iso/config.go b/iso/config.go index ec522bb2b..a995767ff 100644 --- a/iso/config.go +++ b/iso/config.go @@ -47,7 +47,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs = packer.MultiErrorAppend(errs, c.LocationConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...) - errs = packer.MultiErrorAppend(errs, c.RunConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare()...) errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...) errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...) diff --git a/iso/preseed.cfg b/iso/preseed.cfg new file mode 100644 index 000000000..ec963b6b2 --- /dev/null +++ b/iso/preseed.cfg @@ -0,0 +1,16 @@ +d-i passwd/user-fullname string jetbrains +d-i passwd/username string jetbrains +d-i passwd/user-password password jetbrains +d-i passwd/user-password-again password jetbrains +d-i user-setup/allow-password-weak boolean true + +d-i partman-auto/disk string /dev/sda +d-i partman-auto/method string regular +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true + +d-i pkgsel/include string open-vm-tools openssh-server + +d-i finish-install/reboot_in_progress note diff --git a/test.sh b/test.sh index 48d55a97c..4df8d7782 100755 --- a/test.sh +++ b/test.sh @@ -4,4 +4,4 @@ set -eux export PACKER_ACC=1 -go test -v ./driver ./iso ./clone +go test -v -count 1 -timeout 20m ./driver ./iso ./clone