From 469f033c36e3c34cebb5cec1dded6a0505140933 Mon Sep 17 00:00:00 2001 From: Sylvia Moss Date: Wed, 21 Apr 2021 16:32:34 +0200 Subject: [PATCH] remove and vendor hyperv (#10952) --- CODEOWNERS | 3 - builder/hyperv/common/artifact.go | 73 - builder/hyperv/common/artifact_test.go | 47 - builder/hyperv/common/config.go | 434 ----- builder/hyperv/common/driver.go | 133 -- builder/hyperv/common/driver_mock.go | 647 ------- builder/hyperv/common/driver_ps_4.go | 394 ---- builder/hyperv/common/output_config.go | 30 - .../hyperv/common/output_config.hcl2spec.go | 31 - builder/hyperv/common/output_config_test.go | 47 - .../hyperv/common/powershell/hyperv/hyperv.go | 1585 ----------------- .../common/powershell/hyperv/hyperv_test.go | 131 -- .../hyperv/common/powershell/powershell.go | 371 ---- .../common/powershell/powershell_test.go | 69 - .../hyperv/common/powershell/scriptbuilder.go | 29 - builder/hyperv/common/ssh.go | 33 - builder/hyperv/common/ssh_config.go | 14 - builder/hyperv/common/step_clone_vm.go | 183 -- .../hyperv/common/step_collate_artifacts.go | 69 - .../common/step_collate_artifacts_test.go | 92 - builder/hyperv/common/step_compact_disk.go | 50 - .../hyperv/common/step_compact_disk_test.go | 63 - builder/hyperv/common/step_configure_ip.go | 77 - builder/hyperv/common/step_configure_vlan.go | 53 - .../hyperv/common/step_create_build_dir.go | 68 - .../common/step_create_build_dir_test.go | 113 -- .../common/step_create_external_switch.go | 107 -- builder/hyperv/common/step_create_switch.go | 80 - builder/hyperv/common/step_create_vm.go | 197 -- builder/hyperv/common/step_create_vm_test.go | 58 - builder/hyperv/common/step_disable_vlan.go | 37 - .../common/step_enable_integration_service.go | 37 - builder/hyperv/common/step_export_vm.go | 54 - builder/hyperv/common/step_export_vm_test.go | 87 - builder/hyperv/common/step_mount_dvddrive.go | 121 -- .../hyperv/common/step_mount_floppydrive.go | 120 -- .../common/step_mount_guest_additions.go | 95 - .../common/step_mount_secondary_dvd_images.go | 107 -- .../common/step_polling_installation.go | 80 - builder/hyperv/common/step_reboot_vm.go | 42 - builder/hyperv/common/step_run.go | 77 - builder/hyperv/common/step_set_boot_order.go | 37 - .../hyperv/common/step_set_boot_order_test.go | 48 - .../common/step_set_first_boot_device.go | 160 -- .../common/step_set_first_boot_device_test.go | 170 -- builder/hyperv/common/step_shutdown.go | 90 - builder/hyperv/common/step_sleep.go | 31 - builder/hyperv/common/step_test.go | 28 - .../hyperv/common/step_type_boot_command.go | 88 - .../hyperv/common/step_unmount_dvddrive.go | 57 - .../hyperv/common/step_unmount_floppydrive.go | 40 - .../common/step_unmount_guest_additions.go | 57 - .../step_unmount_secondary_dvd_images.go | 59 - .../step_wait_for_install_to_complete.go | 92 - builder/hyperv/iso/builder.go | 377 ---- builder/hyperv/iso/builder.hcl2spec.go | 247 --- builder/hyperv/iso/builder_test.go | 658 ------- builder/hyperv/version/version.go | 13 - builder/hyperv/vmcx/builder.go | 397 ----- builder/hyperv/vmcx/builder.hcl2spec.go | 251 --- builder/hyperv/vmcx/builder_test.go | 521 ------ command/plugin.go | 4 - command/vendored_plugins.go | 6 +- go.mod | 9 +- go.sum | 15 +- .../content/docs/builders/hyperv/index.mdx | 22 - website/content/docs/builders/hyperv/iso.mdx | 860 --------- website/content/docs/builders/hyperv/vmcx.mdx | 881 --------- .../common/CommonConfig-not-required.mdx | 141 -- .../common/OutputConfig-not-required.mdx | 11 - .../partials/builder/hyperv/iso/Builder.mdx | 6 - .../hyperv/iso/Config-not-required.mdx | 24 - .../partials/builder/hyperv/vmcx/Builder.mdx | 6 - .../hyperv/vmcx/Config-not-required.mdx | 25 - website/data/docs-nav-data.json | 17 - website/data/docs-remote-plugins.json | 7 + 76 files changed, 27 insertions(+), 11566 deletions(-) delete mode 100644 builder/hyperv/common/artifact.go delete mode 100644 builder/hyperv/common/artifact_test.go delete mode 100644 builder/hyperv/common/config.go delete mode 100644 builder/hyperv/common/driver.go delete mode 100644 builder/hyperv/common/driver_mock.go delete mode 100644 builder/hyperv/common/driver_ps_4.go delete mode 100644 builder/hyperv/common/output_config.go delete mode 100644 builder/hyperv/common/output_config.hcl2spec.go delete mode 100644 builder/hyperv/common/output_config_test.go delete mode 100644 builder/hyperv/common/powershell/hyperv/hyperv.go delete mode 100644 builder/hyperv/common/powershell/hyperv/hyperv_test.go delete mode 100644 builder/hyperv/common/powershell/powershell.go delete mode 100644 builder/hyperv/common/powershell/powershell_test.go delete mode 100644 builder/hyperv/common/powershell/scriptbuilder.go delete mode 100644 builder/hyperv/common/ssh.go delete mode 100644 builder/hyperv/common/ssh_config.go delete mode 100644 builder/hyperv/common/step_clone_vm.go delete mode 100644 builder/hyperv/common/step_collate_artifacts.go delete mode 100644 builder/hyperv/common/step_collate_artifacts_test.go delete mode 100644 builder/hyperv/common/step_compact_disk.go delete mode 100644 builder/hyperv/common/step_compact_disk_test.go delete mode 100644 builder/hyperv/common/step_configure_ip.go delete mode 100644 builder/hyperv/common/step_configure_vlan.go delete mode 100644 builder/hyperv/common/step_create_build_dir.go delete mode 100644 builder/hyperv/common/step_create_build_dir_test.go delete mode 100644 builder/hyperv/common/step_create_external_switch.go delete mode 100644 builder/hyperv/common/step_create_switch.go delete mode 100644 builder/hyperv/common/step_create_vm.go delete mode 100644 builder/hyperv/common/step_create_vm_test.go delete mode 100644 builder/hyperv/common/step_disable_vlan.go delete mode 100644 builder/hyperv/common/step_enable_integration_service.go delete mode 100644 builder/hyperv/common/step_export_vm.go delete mode 100644 builder/hyperv/common/step_export_vm_test.go delete mode 100644 builder/hyperv/common/step_mount_dvddrive.go delete mode 100644 builder/hyperv/common/step_mount_floppydrive.go delete mode 100644 builder/hyperv/common/step_mount_guest_additions.go delete mode 100644 builder/hyperv/common/step_mount_secondary_dvd_images.go delete mode 100644 builder/hyperv/common/step_polling_installation.go delete mode 100644 builder/hyperv/common/step_reboot_vm.go delete mode 100644 builder/hyperv/common/step_run.go delete mode 100644 builder/hyperv/common/step_set_boot_order.go delete mode 100644 builder/hyperv/common/step_set_boot_order_test.go delete mode 100644 builder/hyperv/common/step_set_first_boot_device.go delete mode 100644 builder/hyperv/common/step_set_first_boot_device_test.go delete mode 100644 builder/hyperv/common/step_shutdown.go delete mode 100644 builder/hyperv/common/step_sleep.go delete mode 100644 builder/hyperv/common/step_test.go delete mode 100644 builder/hyperv/common/step_type_boot_command.go delete mode 100644 builder/hyperv/common/step_unmount_dvddrive.go delete mode 100644 builder/hyperv/common/step_unmount_floppydrive.go delete mode 100644 builder/hyperv/common/step_unmount_guest_additions.go delete mode 100644 builder/hyperv/common/step_unmount_secondary_dvd_images.go delete mode 100644 builder/hyperv/common/step_wait_for_install_to_complete.go delete mode 100644 builder/hyperv/iso/builder.go delete mode 100644 builder/hyperv/iso/builder.hcl2spec.go delete mode 100644 builder/hyperv/iso/builder_test.go delete mode 100644 builder/hyperv/version/version.go delete mode 100644 builder/hyperv/vmcx/builder.go delete mode 100644 builder/hyperv/vmcx/builder.hcl2spec.go delete mode 100644 builder/hyperv/vmcx/builder_test.go delete mode 100644 website/content/docs/builders/hyperv/index.mdx delete mode 100644 website/content/docs/builders/hyperv/iso.mdx delete mode 100644 website/content/docs/builders/hyperv/vmcx.mdx delete mode 100644 website/content/partials/builder/hyperv/common/CommonConfig-not-required.mdx delete mode 100644 website/content/partials/builder/hyperv/common/OutputConfig-not-required.mdx delete mode 100644 website/content/partials/builder/hyperv/iso/Builder.mdx delete mode 100644 website/content/partials/builder/hyperv/iso/Config-not-required.mdx delete mode 100644 website/content/partials/builder/hyperv/vmcx/Builder.mdx delete mode 100644 website/content/partials/builder/hyperv/vmcx/Config-not-required.mdx diff --git a/CODEOWNERS b/CODEOWNERS index a028e34bc..922c4bea2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -13,9 +13,6 @@ /builder/digitalocean/ @andrewsomething /website/pages/docs/builders/digitalocean* @andrewsomething -/builder/hyperv/ @taliesins -/website/pages/docs/builders/hyperv* @taliesins - /examples/jdcloud/ @XiaohanLiang @remrain /builder/jdcloud/ @XiaohanLiang @remrain /website/pages/docs/builders/jdcloud* @XiaohanLiang @remrain diff --git a/builder/hyperv/common/artifact.go b/builder/hyperv/common/artifact.go deleted file mode 100644 index a6cbd5428..000000000 --- a/builder/hyperv/common/artifact.go +++ /dev/null @@ -1,73 +0,0 @@ -package common - -import ( - "fmt" - "os" - "path/filepath" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -// This is the common builder ID to all of these artifacts. -const BuilderId = "MSOpenTech.hyperv" - -// Artifact is the result of running the hyperv builder, namely a set -// of files associated with the resulting machine. -type artifact struct { - dir string - f []string - - // StateData should store data such as GeneratedData - // to be shared with post-processors - StateData map[string]interface{} -} - -// NewArtifact returns a hyperv artifact containing the files -// in the given directory. -func NewArtifact(dir string, generatedData map[string]interface{}) (packersdk.Artifact, error) { - files := make([]string, 0, 5) - visit := func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() { - files = append(files, path) - } - - return nil - } - - if err := filepath.Walk(dir, visit); err != nil { - return nil, err - } - - return &artifact{ - dir: dir, - f: files, - StateData: generatedData, - }, nil -} - -func (*artifact) BuilderId() string { - return BuilderId -} - -func (a *artifact) Files() []string { - return a.f -} - -func (*artifact) Id() string { - return "VM" -} - -func (a *artifact) String() string { - return fmt.Sprintf("VM files in directory: %s", a.dir) -} - -func (a *artifact) State(name string) interface{} { - return a.StateData[name] -} - -func (a *artifact) Destroy() error { - return os.RemoveAll(a.dir) -} diff --git a/builder/hyperv/common/artifact_test.go b/builder/hyperv/common/artifact_test.go deleted file mode 100644 index e01726ad3..000000000 --- a/builder/hyperv/common/artifact_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package common - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" - - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -func TestArtifact_impl(t *testing.T) { - var _ packersdk.Artifact = new(artifact) -} - -func TestNewArtifact(t *testing.T) { - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - - err = ioutil.WriteFile(filepath.Join(td, "a"), []byte("foo"), 0644) - if err != nil { - t.Fatalf("err: %s", err) - } - - if err := os.Mkdir(filepath.Join(td, "b"), 0755); err != nil { - t.Fatalf("err: %s", err) - } - - generatedData := map[string]interface{}{"generated_data": "data"} - a, err := NewArtifact(td, generatedData) - if err != nil { - t.Fatalf("err: %s", err) - } - - if a.BuilderId() != BuilderId { - t.Fatalf("bad: %#v", a.BuilderId()) - } - if len(a.Files()) != 1 { - t.Fatalf("should length 1: %d", len(a.Files())) - } - if a.State("generated_data") != "data" { - t.Fatalf("bad: should length have generated_data: %s", a.State("generated_data")) - } -} diff --git a/builder/hyperv/common/config.go b/builder/hyperv/common/config.go deleted file mode 100644 index 5bf91232d..000000000 --- a/builder/hyperv/common/config.go +++ /dev/null @@ -1,434 +0,0 @@ -//go:generate packer-sdc struct-markdown - -package common - -import ( - "fmt" - "log" - "os" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" - powershell "github.com/hashicorp/packer/builder/hyperv/common/powershell" - "github.com/hashicorp/packer/builder/hyperv/common/powershell/hyperv" -) - -const ( - DefaultDiskSize = 40 * 1024 // ~40GB - MinDiskSize = 256 // 256MB - MaxDiskSize = 64 * 1024 * 1024 // 64TB - MaxVHDSize = 2040 * 1024 // 2040GB - - DefaultDiskBlockSize = 32 // 32MB - MinDiskBlockSize = 1 // 1MB - MaxDiskBlockSize = 256 // 256MB - - DefaultRamSize = 1 * 1024 // 1GB - MinRamSize = 32 // 32MB - MaxRamSize = 32 * 1024 // 32GB - MinNestedVirtualizationRamSize = 4 * 1024 // 4GB - - LowRam = 256 // 256MB - - DefaultUsername = "" - DefaultPassword = "" -) - -type CommonConfig struct { - commonsteps.FloppyConfig `mapstructure:",squash"` - commonsteps.CDConfig `mapstructure:",squash"` - // The block size of the VHD to be created. - // Recommended disk block size for Linux hyper-v guests is 1 MiB. This - // defaults to "32" MiB. - DiskBlockSize uint `mapstructure:"disk_block_size" required:"false"` - // The amount, in megabytes, of RAM to assign to the - // VM. By default, this is 1 GB. - RamSize uint `mapstructure:"memory" required:"false"` - // A list of ISO paths to - // attach to a VM when it is booted. This is most useful for unattended - // Windows installs, which look for an Autounattend.xml file on removable - // media. By default, no secondary ISO will be attached. - SecondaryDvdImages []string `mapstructure:"secondary_iso_images" required:"false"` - // The size or sizes of any - // additional hard disks for the VM in megabytes. If this is not specified - // then the VM will only contain a primary hard disk. Additional drives - // will be attached to the SCSI interface only. The builder uses - // expandable rather than fixed-size virtual hard disks, so the actual - // file representing the disk will not use the full size unless it is - // full. - AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false"` - // If set to attach then attach and - // mount the ISO image specified in guest_additions_path. If set to - // none then guest additions are not attached and mounted; This is the - // default. - GuestAdditionsMode string `mapstructure:"guest_additions_mode" required:"false"` - // The path to the ISO image for guest - // additions. - GuestAdditionsPath string `mapstructure:"guest_additions_path" required:"false"` - // This is the name of the new virtual machine, - // without the file extension. By default this is "packer-BUILDNAME", - // where "BUILDNAME" is the name of the build. - VMName string `mapstructure:"vm_name" required:"false"` - // The name of the switch to connect the virtual - // machine to. By default, leaving this value unset will cause Packer to - // try and determine the switch to use by looking for an external switch - // that is up and running. - SwitchName string `mapstructure:"switch_name" required:"false"` - // This is the VLAN of the virtual switch's - // network card. By default none is set. If none is set then a VLAN is not - // set on the switch's network card. If this value is set it should match - // the VLAN specified in by vlan_id. - SwitchVlanId string `mapstructure:"switch_vlan_id" required:"false"` - // This allows a specific MAC address to be used on - // the default virtual network card. The MAC address must be a string with - // no delimiters, for example "0000deadbeef". - MacAddress string `mapstructure:"mac_address" required:"false"` - // This is the VLAN of the virtual machine's network - // card for the new virtual machine. By default none is set. If none is set - // then VLANs are not set on the virtual machine's network card. - VlanId string `mapstructure:"vlan_id" required:"false"` - // The number of CPUs the virtual machine should use. If - // this isn't specified, the default is 1 CPU. - Cpu uint `mapstructure:"cpus" required:"false"` - // The Hyper-V generation for the virtual machine. By - // default, this is 1. Generation 2 Hyper-V virtual machines do not support - // floppy drives. In this scenario use secondary_iso_images instead. Hard - // drives and DVD drives will also be SCSI and not IDE. - Generation uint `mapstructure:"generation" required:"false"` - // If true enable MAC address spoofing - // for the virtual machine. This defaults to false. - EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing" required:"false"` - // If true enable dynamic memory for - // the virtual machine. This defaults to false. - EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory" required:"false"` - // If true enable secure boot for the - // virtual machine. This defaults to false. See secure_boot_template - // below for additional settings. - EnableSecureBoot bool `mapstructure:"enable_secure_boot" required:"false"` - // The secure boot template to be - // configured. Valid values are "MicrosoftWindows" (Windows) or - // "MicrosoftUEFICertificateAuthority" (Linux). This only takes effect if - // enable_secure_boot is set to "true". This defaults to "MicrosoftWindows". - SecureBootTemplate string `mapstructure:"secure_boot_template" required:"false"` - // If true enable - // virtualization extensions for the virtual machine. This defaults to - // false. For nested virtualization you need to enable MAC spoofing, - // disable dynamic memory and have at least 4GB of RAM assigned to the - // virtual machine. - EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions" required:"false"` - // The location under which Packer will create a directory to house all the - // VM files and folders during the build. By default `%TEMP%` is used - // which, for most systems, will evaluate to - // `%USERPROFILE%/AppData/Local/Temp`. - // - // The build directory housed under `temp_path` will have a name similar to - // `packerhv1234567`. The seven digit number at the end of the name is - // automatically generated by Packer to ensure the directory name is - // unique. - TempPath string `mapstructure:"temp_path" required:"false"` - // This allows you to set the vm version when calling New-VM to generate - // the vm. - Version string `mapstructure:"configuration_version" required:"false"` - // If "true", Packer will not delete the VM from - // The Hyper-V manager. - KeepRegistered bool `mapstructure:"keep_registered" required:"false"` - // If true skip compacting the hard disk for - // the virtual machine when exporting. This defaults to false. - SkipCompaction bool `mapstructure:"skip_compaction" required:"false"` - // If true Packer will skip the export of the VM. - // If you are interested only in the VHD/VHDX files, you can enable this - // option. The resulting VHD/VHDX file will be output to - // /Virtual Hard Disks. By default this option is false - // and Packer will export the VM to output_directory. - SkipExport bool `mapstructure:"skip_export" required:"false"` - // Packer defaults to building Hyper-V virtual - // machines by launching a GUI that shows the console of the machine being - // built. When this value is set to true, the machine will start without a - // console. - Headless bool `mapstructure:"headless" required:"false"` - // When configured, determines the device or device type that is given preferential - // treatment when choosing a boot device. - // - // For Generation 1: - // - `IDE` - // - `CD` *or* `DVD` - // - `Floppy` - // - `NET` - // - // For Generation 2: - // - `IDE:x:y` - // - `SCSI:x:y` - // - `CD` *or* `DVD` - // - `NET` - FirstBootDevice string `mapstructure:"first_boot_device" required:"false"` - // When configured, the boot order determines the order of the devices - // from which to boot. - // - // The device name must be in the form of `SCSI:x:y`, for example, - // to boot from the first scsi device use `SCSI:0:0`. - // - // **NB** You should also set `first_boot_device` (e.g. `DVD`). - // - // **NB** Although the VM will have this initial boot order, the OS can - // change it, for example, Ubuntu 18.04 will modify the boot order to - // include itself as the first boot option. - // - // **NB** This only works for Generation 2 machines. - BootOrder []string `mapstructure:"boot_order" required:"false"` -} - -func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) ([]error, []string) { - // Accumulate any errors and warns - var errs []error - var warns []string - - if c.VMName == "" { - c.VMName = fmt.Sprintf("packer-%s", pc.PackerBuildName) - log.Println(fmt.Sprintf("%s: %v", "VMName", c.VMName)) - } - - if c.SwitchName == "" { - c.SwitchName = c.detectSwitchName(pc.PackerBuildName) - log.Println(fmt.Sprintf("Using switch %s", c.SwitchName)) - } - - if c.Generation < 1 || c.Generation > 2 { - c.Generation = 1 - } - - if c.Generation == 2 { - if len(c.FloppyFiles) > 0 || len(c.FloppyDirectories) > 0 { - err := fmt.Errorf("Generation 2 vms don't support floppy drives. Use ISO image instead.") - errs = append(errs, err) - } - } - - if len(c.AdditionalDiskSize) > 64 { - errs = append(errs, fmt.Errorf("VM's currently support a maximum of 64 additional SCSI attached disks.")) - } - - // Errors - errs = append(errs, c.FloppyConfig.Prepare(ctx)...) - errs = append(errs, c.CDConfig.Prepare(ctx)...) - if c.GuestAdditionsMode == "" { - if c.GuestAdditionsPath != "" { - c.GuestAdditionsMode = "attach" - } else { - c.GuestAdditionsPath = os.Getenv("WINDIR") + "\\system32\\vmguest.iso" - - if _, err := os.Stat(c.GuestAdditionsPath); os.IsNotExist(err) { - if err != nil { - c.GuestAdditionsPath = "" - c.GuestAdditionsMode = "none" - } else { - c.GuestAdditionsMode = "attach" - } - } - } - } - - if c.GuestAdditionsPath == "" && c.GuestAdditionsMode == "attach" { - c.GuestAdditionsPath = os.Getenv("WINDIR") + "\\system32\\vmguest.iso" - - if _, err := os.Stat(c.GuestAdditionsPath); os.IsNotExist(err) { - if err != nil { - c.GuestAdditionsPath = "" - } - } - } - - for _, isoPath := range c.SecondaryDvdImages { - if _, err := os.Stat(isoPath); os.IsNotExist(err) { - if err != nil { - errs = append( - errs, fmt.Errorf("Secondary Dvd image does not exist: %s", err)) - } - } - } - - numberOfIsos := len(c.SecondaryDvdImages) - - if c.GuestAdditionsMode == "attach" { - if _, err := os.Stat(c.GuestAdditionsPath); os.IsNotExist(err) { - if err != nil { - errs = append( - errs, fmt.Errorf("Guest additions iso does not exist: %s", err)) - } - } - - numberOfIsos = numberOfIsos + 1 - } - - if c.Generation < 2 && numberOfIsos > 2 { - if c.GuestAdditionsMode == "attach" { - errs = append(errs, fmt.Errorf("There are only 2 ide controllers available, so "+ - "we can't support guest additions and these secondary dvds: %s", - strings.Join(c.SecondaryDvdImages, ", "))) - } else { - errs = append(errs, fmt.Errorf("There are only 2 ide controllers available, so "+ - "we can't support these secondary dvds: %s", - strings.Join(c.SecondaryDvdImages, ", "))) - } - } else if c.Generation > 1 && len(c.SecondaryDvdImages) > 16 { - if c.GuestAdditionsMode == "attach" { - errs = append(errs, fmt.Errorf("There are not enough drive letters available for "+ - "scsi (limited to 16), so we can't support guest additions and these secondary dvds: %s", - strings.Join(c.SecondaryDvdImages, ", "))) - } else { - errs = append(errs, fmt.Errorf("There are not enough drive letters available for "+ - "scsi (limited to 16), so we can't support these secondary dvds: %s", - strings.Join(c.SecondaryDvdImages, ", "))) - } - } - - if c.EnableVirtualizationExtensions { - hasVirtualMachineVirtualizationExtensions, err := powershell.HasVirtualMachineVirtualizationExtensions() - if err != nil { - errs = append(errs, fmt.Errorf("Failed detecting virtual machine virtualization "+ - "extensions support: %s", err)) - } else { - if !hasVirtualMachineVirtualizationExtensions { - errs = append(errs, fmt.Errorf("This version of Hyper-V does not support "+ - "virtual machine virtualization extension. Please use Windows 10 or Windows Server 2016 "+ - "or newer.")) - } - } - } - - if c.FirstBootDevice != "" { - _, _, _, err := ParseBootDeviceIdentifier(c.FirstBootDevice, c.Generation) - if err != nil { - errs = append(errs, fmt.Errorf("first_boot_device: %s", err)) - } - } - - if c.EnableVirtualizationExtensions { - if c.EnableDynamicMemory { - warning := fmt.Sprintf("For nested virtualization, when virtualization extension is enabled, " + - "dynamic memory should not be allowed.") - warns = Appendwarns(warns, warning) - } - - if !c.EnableMacSpoofing { - warning := fmt.Sprintf("For nested virtualization, when virtualization extension is enabled, " + - "mac spoofing should be allowed.") - warns = Appendwarns(warns, warning) - } - - if c.RamSize < MinNestedVirtualizationRamSize { - warning := fmt.Sprintf("For nested virtualization, when virtualization extension is enabled, " + - "there should be 4GB or more memory set for the vm, otherwise Hyper-V may fail to start " + - "any nested VMs.") - warns = Appendwarns(warns, warning) - } - } - - if c.SwitchVlanId != "" { - if c.SwitchVlanId != c.VlanId { - warning := fmt.Sprintf("Switch network adaptor vlan should match virtual machine network adaptor " + - "vlan. The switch will not be able to see traffic from the VM.") - warns = Appendwarns(warns, warning) - } - } - - err := c.checkDiskBlockSize() - if err != nil { - errs = append(errs, err) - } - err = c.checkRamSize() - if err != nil { - errs = append(errs, err) - } - - // warns - warning := c.checkHostAvailableMemory() - if warning != "" { - warns = Appendwarns(warns, warning) - } - - if errs != nil && len(errs) > 0 { - return errs, warns - } - - return nil, warns -} - -func (c *CommonConfig) checkDiskBlockSize() error { - if c.DiskBlockSize == 0 { - c.DiskBlockSize = DefaultDiskBlockSize - } - - log.Println(fmt.Sprintf("%s: %v", "DiskBlockSize", c.DiskBlockSize)) - - if c.DiskBlockSize < MinDiskBlockSize { - return fmt.Errorf("disk_block_size: Virtual machine requires disk block size >= %v MB, but defined: %v", - MinDiskBlockSize, c.DiskBlockSize) - } else if c.DiskBlockSize > MaxDiskBlockSize { - return fmt.Errorf("disk_block_size: Virtual machine requires disk block size <= %v MB, but defined: %v", - MaxDiskBlockSize, c.DiskBlockSize) - } - - return nil -} - -func (c *CommonConfig) checkHostAvailableMemory() string { - powershellAvailable, _, _ := powershell.IsPowershellAvailable() - - if powershellAvailable { - freeMB := powershell.GetHostAvailableMemory() - - if (freeMB - float64(c.RamSize)) < LowRam { - return fmt.Sprintf("Hyper-V might fail to create a VM if there is not enough free memory in the system.") - } - } - - return "" -} - -func (c *CommonConfig) checkRamSize() error { - if c.RamSize == 0 { - c.RamSize = DefaultRamSize - } - - log.Println(fmt.Sprintf("%s: %v", "RamSize", c.RamSize)) - - if c.RamSize < MinRamSize { - return fmt.Errorf("memory: Virtual machine requires memory size >= %v MB, but defined: %v", - MinRamSize, c.RamSize) - } else if c.RamSize > MaxRamSize { - return fmt.Errorf("memory: Virtual machine requires memory size <= %v MB, but defined: %v", - MaxRamSize, c.RamSize) - } - - return nil -} - -func (c *CommonConfig) detectSwitchName(buildName string) string { - powershellAvailable, _, _ := powershell.IsPowershellAvailable() - - if powershellAvailable { - // no switch name, try to get one attached to a online network adapter - onlineSwitchName, err := hyperv.GetExternalOnlineVirtualSwitch() - if onlineSwitchName != "" && err == nil { - return onlineSwitchName - } - } - - return fmt.Sprintf("packer-%s", buildName) -} - -func Appendwarns(slice []string, data ...string) []string { - m := len(slice) - n := m + len(data) - if n > cap(slice) { // if necessary, reallocate - // allocate double what's needed, for future growth. - newSlice := make([]string, (n+1)*2) - copy(newSlice, slice) - slice = newSlice - } - slice = slice[0:n] - copy(slice[m:n], data) - return slice -} diff --git a/builder/hyperv/common/driver.go b/builder/hyperv/common/driver.go deleted file mode 100644 index 90ae2c9aa..000000000 --- a/builder/hyperv/common/driver.go +++ /dev/null @@ -1,133 +0,0 @@ -package common - -import ( - "context" -) - -// A driver is able to talk to HyperV and perform certain -// operations with it. Some of the operations on here may seem overly -// specific, but they were built specifically in mind to handle features -// of the HyperV builder for Packer, and to abstract differences in -// versions out of the builder steps, so sometimes the methods are -// extremely specific. -type Driver interface { - - // Checks if the VM named is running. - IsRunning(string) (bool, error) - - // Checks if the VM named is off. - IsOff(string) (bool, error) - - //How long has VM been on - Uptime(vmName string) (uint64, error) - - // Start starts a VM specified by the name given. - Start(string) error - - // Stop stops a VM specified by the name given. - Stop(string) error - - // Verify checks to make sure that this driver should function - // properly. If there is any indication the driver can't function, - // this will return an error. - Verify() error - - // Finds the MAC address of the NIC nic0 - Mac(string) (string, error) - - // Finds the IP address of a VM connected that uses DHCP by its MAC address - IpAddress(string) (string, error) - - // Finds the hostname for the ip address - GetHostName(string) (string, error) - - // Finds the IP address of a host adapter connected to switch - GetHostAdapterIpAddressForSwitch(string) (string, error) - - // Type scan codes to virtual keyboard of vm - TypeScanCodes(string, string) error - - //Get the ip address for network adaptor - GetVirtualMachineNetworkAdapterAddress(string) (string, error) - - //Set the vlan to use for switch - SetNetworkAdapterVlanId(string, string) error - - //Set the vlan to use for machine - SetVirtualMachineVlanId(string, string) error - - SetVmNetworkAdapterMacAddress(string, string) error - - //Replace the network adapter with a (non-)legacy adapter - ReplaceVirtualMachineNetworkAdapter(string, bool) error - - UntagVirtualMachineNetworkAdapterVlan(string, string) error - - CreateExternalVirtualSwitch(string, string) error - - GetVirtualMachineSwitchName(string) (string, error) - - ConnectVirtualMachineNetworkAdapterToSwitch(string, string) error - - CreateVirtualSwitch(string, string) (bool, error) - - DeleteVirtualSwitch(string) error - - CheckVMName(string) error - - CreateVirtualMachine(string, string, string, int64, int64, int64, string, uint, bool, bool, string) error - - AddVirtualMachineHardDrive(string, string, string, int64, int64, string) error - - CloneVirtualMachine(string, string, string, bool, string, string, string, int64, string, bool) error - - DeleteVirtualMachine(string) error - - GetVirtualMachineGeneration(string) (uint, error) - - SetVirtualMachineCpuCount(string, uint) error - - SetVirtualMachineMacSpoofing(string, bool) error - - SetVirtualMachineDynamicMemory(string, bool) error - - SetVirtualMachineSecureBoot(string, bool, string) error - - SetVirtualMachineVirtualizationExtensions(string, bool) error - - EnableVirtualMachineIntegrationService(string, string) error - - ExportVirtualMachine(string, string) error - - PreserveLegacyExportBehaviour(string, string) error - - MoveCreatedVHDsToOutputDir(string, string) error - - CompactDisks(string) (string, error) - - RestartVirtualMachine(string) error - - CreateDvdDrive(string, string, uint) (uint, uint, error) - - MountDvdDrive(string, string, uint, uint) error - - SetBootDvdDrive(string, uint, uint, uint) error - - SetFirstBootDevice(string, string, uint, uint, uint) error - - SetBootOrder(string, []string) error - - UnmountDvdDrive(string, uint, uint) error - - DeleteDvdDrive(string, uint, uint) error - - MountFloppyDrive(string, string) error - - UnmountFloppyDrive(string) error - - // Connect connects to a VM specified by the name given. - Connect(string) (context.CancelFunc, error) - - // Disconnect disconnects to a VM specified by the context cancel function. - Disconnect(context.CancelFunc) -} diff --git a/builder/hyperv/common/driver_mock.go b/builder/hyperv/common/driver_mock.go deleted file mode 100644 index 24a9f022b..000000000 --- a/builder/hyperv/common/driver_mock.go +++ /dev/null @@ -1,647 +0,0 @@ -package common - -import ( - "context" -) - -type DriverMock struct { - IsRunning_Called bool - IsRunning_VmName string - IsRunning_Return bool - IsRunning_Err error - - IsOff_Called bool - IsOff_VmName string - IsOff_Return bool - IsOff_Err error - - Uptime_Called bool - Uptime_VmName string - Uptime_Return uint64 - Uptime_Err error - - Start_Called bool - Start_VmName string - Start_Err error - - Stop_Called bool - Stop_VmName string - Stop_Err error - - Verify_Called bool - Verify_Err error - - Mac_Called bool - Mac_VmName string - Mac_Return string - Mac_Err error - - IpAddress_Called bool - IpAddress_Mac string - IpAddress_Return string - IpAddress_Err error - - GetHostName_Called bool - GetHostName_Ip string - GetHostName_Return string - GetHostName_Err error - - GetVirtualMachineGeneration_Called bool - GetVirtualMachineGeneration_VmName string - GetVirtualMachineGeneration_Return uint - GetVirtualMachineGeneration_Err error - - GetHostAdapterIpAddressForSwitch_Called bool - GetHostAdapterIpAddressForSwitch_SwitchName string - GetHostAdapterIpAddressForSwitch_Return string - GetHostAdapterIpAddressForSwitch_Err error - - TypeScanCodes_Called bool - TypeScanCodes_VmName string - TypeScanCodes_ScanCodes string - TypeScanCodes_Err error - - GetVirtualMachineNetworkAdapterAddress_Called bool - GetVirtualMachineNetworkAdapterAddress_VmName string - GetVirtualMachineNetworkAdapterAddress_Return string - GetVirtualMachineNetworkAdapterAddress_Err error - - ReplaceVirtualMachineNetworkAdapter_Called bool - ReplaceVirtualMachineNetworkAdapter_VmName string - ReplaceVirtualMachineNetworkAdapter_Replace bool - ReplaceVirtualMachineNetworkAdapter_Err error - - SetNetworkAdapterVlanId_Called bool - SetNetworkAdapterVlanId_SwitchName string - SetNetworkAdapterVlanId_VlanId string - SetNetworkAdapterVlanId_Err error - - SetVmNetworkAdapterMacAddress_Called bool - SetVmNetworkAdapterMacAddress_VmName string - SetVmNetworkAdapterMacAddress_Mac string - SetVmNetworkAdapterMacAddress_Err error - - SetVirtualMachineVlanId_Called bool - SetVirtualMachineVlanId_VmName string - SetVirtualMachineVlanId_VlanId string - SetVirtualMachineVlanId_Err error - - UntagVirtualMachineNetworkAdapterVlan_Called bool - UntagVirtualMachineNetworkAdapterVlan_VmName string - UntagVirtualMachineNetworkAdapterVlan_SwitchName string - UntagVirtualMachineNetworkAdapterVlan_Err error - - CreateExternalVirtualSwitch_Called bool - CreateExternalVirtualSwitch_VmName string - CreateExternalVirtualSwitch_SwitchName string - CreateExternalVirtualSwitch_Err error - - GetVirtualMachineSwitchName_Called bool - GetVirtualMachineSwitchName_VmName string - GetVirtualMachineSwitchName_Return string - GetVirtualMachineSwitchName_Err error - - ConnectVirtualMachineNetworkAdapterToSwitch_Called bool - ConnectVirtualMachineNetworkAdapterToSwitch_VmName string - ConnectVirtualMachineNetworkAdapterToSwitch_SwitchName string - ConnectVirtualMachineNetworkAdapterToSwitch_Err error - - DeleteVirtualSwitch_Called bool - DeleteVirtualSwitch_SwitchName string - DeleteVirtualSwitch_Err error - - CheckVMName_Called bool - CheckVMName_Err error - - CreateVirtualSwitch_Called bool - CreateVirtualSwitch_SwitchName string - CreateVirtualSwitch_SwitchType string - CreateVirtualSwitch_Return bool - CreateVirtualSwitch_Err error - - AddVirtualMachineHardDrive_Called bool - AddVirtualMachineHardDrive_VmName string - AddVirtualMachineHardDrive_VhdFile string - AddVirtualMachineHardDrive_VhdName string - AddVirtualMachineHardDrive_VhdSizeBytes int64 - AddVirtualMachineHardDrive_VhdBlockSize int64 - AddVirtualMachineHardDrive_ControllerType string - AddVirtualMachineHardDrive_Err error - - CreateVirtualMachine_Called bool - CreateVirtualMachine_VmName string - CreateVirtualMachine_Path string - CreateVirtualMachine_HarddrivePath string - CreateVirtualMachine_Ram int64 - CreateVirtualMachine_DiskSize int64 - CreateVirtualMachine_DiskBlockSize int64 - CreateVirtualMachine_SwitchName string - CreateVirtualMachine_Generation uint - CreateVirtualMachine_DifferentialDisk bool - CreateVirtualMachine_FixedVHD bool - CreateVirtualMachine_Version string - CreateVirtualMachine_Err error - - CloneVirtualMachine_Called bool - CloneVirtualMachine_CloneFromVmcxPath string - CloneVirtualMachine_CloneFromVmName string - CloneVirtualMachine_CloneFromSnapshotName string - CloneVirtualMachine_CloneAllSnapshots bool - CloneVirtualMachine_VmName string - CloneVirtualMachine_Path string - CloneVirtualMachine_HarddrivePath string - CloneVirtualMachine_Ram int64 - CloneVirtualMachine_SwitchName string - CloneVirtualMachine_Copy bool - CloneVirtualMachine_Err error - - DeleteVirtualMachine_Called bool - DeleteVirtualMachine_VmName string - DeleteVirtualMachine_Err error - - SetVirtualMachineCpuCount_Called bool - SetVirtualMachineCpuCount_VmName string - SetVirtualMachineCpuCount_Cpu uint - SetVirtualMachineCpuCount_Err error - - SetVirtualMachineMacSpoofing_Called bool - SetVirtualMachineMacSpoofing_VmName string - SetVirtualMachineMacSpoofing_Enable bool - SetVirtualMachineMacSpoofing_Err error - - SetVirtualMachineDynamicMemory_Called bool - SetVirtualMachineDynamicMemory_VmName string - SetVirtualMachineDynamicMemory_Enable bool - SetVirtualMachineDynamicMemory_Err error - - SetVirtualMachineSecureBoot_Called bool - SetVirtualMachineSecureBoot_VmName string - SetVirtualMachineSecureBoot_TemplateName string - SetVirtualMachineSecureBoot_Enable bool - SetVirtualMachineSecureBoot_Err error - - SetVirtualMachineVirtualizationExtensions_Called bool - SetVirtualMachineVirtualizationExtensions_VmName string - SetVirtualMachineVirtualizationExtensions_Enable bool - SetVirtualMachineVirtualizationExtensions_Err error - - EnableVirtualMachineIntegrationService_Called bool - EnableVirtualMachineIntegrationService_VmName string - EnableVirtualMachineIntegrationService_IntegrationServiceName string - EnableVirtualMachineIntegrationService_Err error - - ExportVirtualMachine_Called bool - ExportVirtualMachine_VmName string - ExportVirtualMachine_Path string - ExportVirtualMachine_Err error - - PreserveLegacyExportBehaviour_Called bool - PreserveLegacyExportBehaviour_SrcPath string - PreserveLegacyExportBehaviour_DstPath string - PreserveLegacyExportBehaviour_Err error - - MoveCreatedVHDsToOutputDir_Called bool - MoveCreatedVHDsToOutputDir_SrcPath string - MoveCreatedVHDsToOutputDir_DstPath string - MoveCreatedVHDsToOutputDir_Err error - - CompactDisks_Called bool - CompactDisks_Path string - CompactDisks_Result string - CompactDisks_Err error - - RestartVirtualMachine_Called bool - RestartVirtualMachine_VmName string - RestartVirtualMachine_Err error - - CreateDvdDrive_Called bool - CreateDvdDrive_VmName string - CreateDvdDrive_IsoPath string - CreateDvdDrive_Generation uint - CreateDvdDrive_ControllerNumber uint - CreateDvdDrive_ControllerLocation uint - CreateDvdDrive_Err error - - MountDvdDrive_Called bool - MountDvdDrive_VmName string - MountDvdDrive_Path string - MountDvdDrive_ControllerNumber uint - MountDvdDrive_ControllerLocation uint - MountDvdDrive_Err error - - SetBootDvdDrive_Called bool - SetBootDvdDrive_VmName string - SetBootDvdDrive_ControllerNumber uint - SetBootDvdDrive_ControllerLocation uint - SetBootDvdDrive_Generation uint - SetBootDvdDrive_Err error - - SetFirstBootDevice_Called bool - SetFirstBootDevice_VmName string - SetFirstBootDevice_ControllerType string - SetFirstBootDevice_ControllerNumber uint - SetFirstBootDevice_ControllerLocation uint - SetFirstBootDevice_Generation uint - SetFirstBootDevice_Err error - - SetBootOrder_Called bool - SetBootOrder_VmName string - SetBootOrder_BootOrder []string - SetBootOrder_Err error - - UnmountDvdDrive_Called bool - UnmountDvdDrive_VmName string - UnmountDvdDrive_ControllerNumber uint - UnmountDvdDrive_ControllerLocation uint - UnmountDvdDrive_Err error - - DeleteDvdDrive_Called bool - DeleteDvdDrive_VmName string - DeleteDvdDrive_ControllerNumber uint - DeleteDvdDrive_ControllerLocation uint - DeleteDvdDrive_Err error - - MountFloppyDrive_Called bool - MountFloppyDrive_VmName string - MountFloppyDrive_Path string - MountFloppyDrive_Err error - - UnmountFloppyDrive_Called bool - UnmountFloppyDrive_VmName string - UnmountFloppyDrive_Err error - - Connect_Called bool - Connect_VmName string - Connect_Cancel context.CancelFunc - Connect_Err error - - Disconnect_Called bool - Disconnect_Cancel context.CancelFunc -} - -func (d *DriverMock) IsRunning(vmName string) (bool, error) { - d.IsRunning_Called = true - d.IsRunning_VmName = vmName - return d.IsRunning_Return, d.IsRunning_Err -} - -func (d *DriverMock) IsOff(vmName string) (bool, error) { - d.IsOff_Called = true - d.IsOff_VmName = vmName - return d.IsOff_Return, d.IsOff_Err -} - -func (d *DriverMock) Uptime(vmName string) (uint64, error) { - d.Uptime_Called = true - d.Uptime_VmName = vmName - return d.Uptime_Return, d.Uptime_Err -} - -func (d *DriverMock) Start(vmName string) error { - d.Start_Called = true - d.Start_VmName = vmName - return d.Start_Err -} - -func (d *DriverMock) Stop(vmName string) error { - d.Stop_Called = true - d.Stop_VmName = vmName - return d.Stop_Err -} - -func (d *DriverMock) Verify() error { - d.Verify_Called = true - return d.Verify_Err -} - -func (d *DriverMock) Mac(vmName string) (string, error) { - d.Mac_Called = true - d.Mac_VmName = vmName - return d.Mac_Return, d.Mac_Err -} - -func (d *DriverMock) IpAddress(mac string) (string, error) { - d.IpAddress_Called = true - d.IpAddress_Mac = mac - return d.IpAddress_Return, d.IpAddress_Err -} - -func (d *DriverMock) GetHostName(ip string) (string, error) { - d.GetHostName_Called = true - d.GetHostName_Ip = ip - return d.GetHostName_Return, d.GetHostName_Err -} - -func (d *DriverMock) GetVirtualMachineGeneration(vmName string) (uint, error) { - d.GetVirtualMachineGeneration_Called = true - d.GetVirtualMachineGeneration_VmName = vmName - return d.GetVirtualMachineGeneration_Return, d.GetVirtualMachineGeneration_Err -} - -func (d *DriverMock) GetHostAdapterIpAddressForSwitch(switchName string) (string, error) { - d.GetHostAdapterIpAddressForSwitch_Called = true - d.GetHostAdapterIpAddressForSwitch_SwitchName = switchName - return d.GetHostAdapterIpAddressForSwitch_Return, d.GetHostAdapterIpAddressForSwitch_Err -} - -func (d *DriverMock) TypeScanCodes(vmName string, scanCodes string) error { - d.TypeScanCodes_Called = true - d.TypeScanCodes_VmName = vmName - d.TypeScanCodes_ScanCodes = scanCodes - return d.TypeScanCodes_Err -} - -func (d *DriverMock) GetVirtualMachineNetworkAdapterAddress(vmName string) (string, error) { - d.GetVirtualMachineNetworkAdapterAddress_Called = true - d.GetVirtualMachineNetworkAdapterAddress_VmName = vmName - return d.GetVirtualMachineNetworkAdapterAddress_Return, d.GetVirtualMachineNetworkAdapterAddress_Err -} - -func (d *DriverMock) ReplaceVirtualMachineNetworkAdapter(vmName string, replace bool) error { - d.ReplaceVirtualMachineNetworkAdapter_Called = true - d.ReplaceVirtualMachineNetworkAdapter_VmName = vmName - d.ReplaceVirtualMachineNetworkAdapter_Replace = replace - return d.ReplaceVirtualMachineNetworkAdapter_Err -} - -func (d *DriverMock) SetNetworkAdapterVlanId(switchName string, vlanId string) error { - d.SetNetworkAdapterVlanId_Called = true - d.SetNetworkAdapterVlanId_SwitchName = switchName - d.SetNetworkAdapterVlanId_VlanId = vlanId - return d.SetNetworkAdapterVlanId_Err -} - -func (d *DriverMock) SetVmNetworkAdapterMacAddress(vmName string, mac string) error { - d.SetVmNetworkAdapterMacAddress_Called = true - d.SetVmNetworkAdapterMacAddress_VmName = vmName - d.SetVmNetworkAdapterMacAddress_Mac = mac - return d.SetVmNetworkAdapterMacAddress_Err -} - -func (d *DriverMock) SetVirtualMachineVlanId(vmName string, vlanId string) error { - d.SetVirtualMachineVlanId_Called = true - d.SetVirtualMachineVlanId_VmName = vmName - d.SetVirtualMachineVlanId_VlanId = vlanId - return d.SetVirtualMachineVlanId_Err -} - -func (d *DriverMock) UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { - d.UntagVirtualMachineNetworkAdapterVlan_Called = true - d.UntagVirtualMachineNetworkAdapterVlan_VmName = vmName - d.UntagVirtualMachineNetworkAdapterVlan_SwitchName = switchName - return d.UntagVirtualMachineNetworkAdapterVlan_Err -} - -func (d *DriverMock) CreateExternalVirtualSwitch(vmName string, switchName string) error { - d.CreateExternalVirtualSwitch_Called = true - d.CreateExternalVirtualSwitch_VmName = vmName - d.CreateExternalVirtualSwitch_SwitchName = switchName - return d.CreateExternalVirtualSwitch_Err -} - -func (d *DriverMock) GetVirtualMachineSwitchName(vmName string) (string, error) { - d.GetVirtualMachineSwitchName_Called = true - d.GetVirtualMachineSwitchName_VmName = vmName - return d.GetVirtualMachineSwitchName_Return, d.GetVirtualMachineSwitchName_Err -} - -func (d *DriverMock) ConnectVirtualMachineNetworkAdapterToSwitch(vmName string, switchName string) error { - d.ConnectVirtualMachineNetworkAdapterToSwitch_Called = true - d.ConnectVirtualMachineNetworkAdapterToSwitch_VmName = vmName - d.ConnectVirtualMachineNetworkAdapterToSwitch_SwitchName = switchName - return d.ConnectVirtualMachineNetworkAdapterToSwitch_Err -} - -func (d *DriverMock) DeleteVirtualSwitch(switchName string) error { - d.DeleteVirtualSwitch_Called = true - d.DeleteVirtualSwitch_SwitchName = switchName - return d.DeleteVirtualSwitch_Err -} - -func (d *DriverMock) CreateVirtualSwitch(switchName string, switchType string) (bool, error) { - d.CreateVirtualSwitch_Called = true - d.CreateVirtualSwitch_SwitchName = switchName - d.CreateVirtualSwitch_SwitchType = switchType - return d.CreateVirtualSwitch_Return, d.CreateVirtualSwitch_Err -} - -func (d *DriverMock) AddVirtualMachineHardDrive(vmName string, vhdFile string, vhdName string, - vhdSizeBytes int64, vhdDiskBlockSize int64, controllerType string) error { - d.AddVirtualMachineHardDrive_Called = true - d.AddVirtualMachineHardDrive_VmName = vmName - d.AddVirtualMachineHardDrive_VhdFile = vhdFile - d.AddVirtualMachineHardDrive_VhdName = vhdName - d.AddVirtualMachineHardDrive_VhdSizeBytes = vhdSizeBytes - d.AddVirtualMachineHardDrive_VhdSizeBytes = vhdDiskBlockSize - d.AddVirtualMachineHardDrive_ControllerType = controllerType - return d.AddVirtualMachineHardDrive_Err -} - -func (d *DriverMock) CheckVMName(vmName string) error { - d.CheckVMName_Called = true - return d.CheckVMName_Err -} - -func (d *DriverMock) CreateVirtualMachine(vmName string, path string, harddrivePath string, - ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, - diffDisks bool, fixedVHD bool, version string) error { - d.CreateVirtualMachine_Called = true - d.CreateVirtualMachine_VmName = vmName - d.CreateVirtualMachine_Path = path - d.CreateVirtualMachine_HarddrivePath = harddrivePath - d.CreateVirtualMachine_Ram = ram - d.CreateVirtualMachine_DiskSize = diskSize - d.CreateVirtualMachine_DiskBlockSize = diskBlockSize - d.CreateVirtualMachine_SwitchName = switchName - d.CreateVirtualMachine_Generation = generation - d.CreateVirtualMachine_DifferentialDisk = diffDisks - d.CreateVirtualMachine_Version = version - return d.CreateVirtualMachine_Err -} - -func (d *DriverMock) CloneVirtualMachine(cloneFromVmcxPath string, cloneFromVmName string, - cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, - harddrivePath string, ram int64, switchName string, copyTF bool) error { - d.CloneVirtualMachine_Called = true - d.CloneVirtualMachine_CloneFromVmcxPath = cloneFromVmcxPath - d.CloneVirtualMachine_CloneFromVmName = cloneFromVmName - d.CloneVirtualMachine_CloneFromSnapshotName = cloneFromSnapshotName - d.CloneVirtualMachine_CloneAllSnapshots = cloneAllSnapshots - d.CloneVirtualMachine_VmName = vmName - d.CloneVirtualMachine_Path = path - d.CloneVirtualMachine_HarddrivePath = harddrivePath - d.CloneVirtualMachine_Ram = ram - d.CloneVirtualMachine_SwitchName = switchName - d.CloneVirtualMachine_Copy = copyTF - - return d.CloneVirtualMachine_Err -} - -func (d *DriverMock) DeleteVirtualMachine(vmName string) error { - d.DeleteVirtualMachine_Called = true - d.DeleteVirtualMachine_VmName = vmName - return d.DeleteVirtualMachine_Err -} - -func (d *DriverMock) SetVirtualMachineCpuCount(vmName string, cpu uint) error { - d.SetVirtualMachineCpuCount_Called = true - d.SetVirtualMachineCpuCount_VmName = vmName - d.SetVirtualMachineCpuCount_Cpu = cpu - return d.SetVirtualMachineCpuCount_Err -} - -func (d *DriverMock) SetVirtualMachineMacSpoofing(vmName string, enable bool) error { - d.SetVirtualMachineMacSpoofing_Called = true - d.SetVirtualMachineMacSpoofing_VmName = vmName - d.SetVirtualMachineMacSpoofing_Enable = enable - return d.SetVirtualMachineMacSpoofing_Err -} - -func (d *DriverMock) SetVirtualMachineDynamicMemory(vmName string, enable bool) error { - d.SetVirtualMachineDynamicMemory_Called = true - d.SetVirtualMachineDynamicMemory_VmName = vmName - d.SetVirtualMachineDynamicMemory_Enable = enable - return d.SetVirtualMachineDynamicMemory_Err -} - -func (d *DriverMock) SetVirtualMachineSecureBoot(vmName string, enable bool, templateName string) error { - d.SetVirtualMachineSecureBoot_Called = true - d.SetVirtualMachineSecureBoot_VmName = vmName - d.SetVirtualMachineSecureBoot_Enable = enable - d.SetVirtualMachineSecureBoot_TemplateName = templateName - return d.SetVirtualMachineSecureBoot_Err -} - -func (d *DriverMock) SetVirtualMachineVirtualizationExtensions(vmName string, enable bool) error { - d.SetVirtualMachineVirtualizationExtensions_Called = true - d.SetVirtualMachineVirtualizationExtensions_VmName = vmName - d.SetVirtualMachineVirtualizationExtensions_Enable = enable - return d.SetVirtualMachineVirtualizationExtensions_Err -} - -func (d *DriverMock) EnableVirtualMachineIntegrationService(vmName string, integrationServiceName string) error { - d.EnableVirtualMachineIntegrationService_Called = true - d.EnableVirtualMachineIntegrationService_VmName = vmName - d.EnableVirtualMachineIntegrationService_IntegrationServiceName = integrationServiceName - return d.EnableVirtualMachineIntegrationService_Err -} - -func (d *DriverMock) ExportVirtualMachine(vmName string, path string) error { - d.ExportVirtualMachine_Called = true - d.ExportVirtualMachine_VmName = vmName - d.ExportVirtualMachine_Path = path - return d.ExportVirtualMachine_Err -} - -func (d *DriverMock) PreserveLegacyExportBehaviour(srcPath string, dstPath string) error { - d.PreserveLegacyExportBehaviour_Called = true - d.PreserveLegacyExportBehaviour_SrcPath = srcPath - d.PreserveLegacyExportBehaviour_DstPath = dstPath - return d.PreserveLegacyExportBehaviour_Err -} - -func (d *DriverMock) MoveCreatedVHDsToOutputDir(srcPath string, dstPath string) error { - d.MoveCreatedVHDsToOutputDir_Called = true - d.MoveCreatedVHDsToOutputDir_SrcPath = srcPath - d.MoveCreatedVHDsToOutputDir_DstPath = dstPath - return d.MoveCreatedVHDsToOutputDir_Err -} - -func (d *DriverMock) CompactDisks(path string) (result string, err error) { - d.CompactDisks_Called = true - d.CompactDisks_Path = path - d.CompactDisks_Result = "Mock compact result msg: mockdisk.vhdx. Disk size reduced by 20%" - return d.CompactDisks_Result, d.CompactDisks_Err -} - -func (d *DriverMock) RestartVirtualMachine(vmName string) error { - d.RestartVirtualMachine_Called = true - d.RestartVirtualMachine_VmName = vmName - return d.RestartVirtualMachine_Err -} - -func (d *DriverMock) CreateDvdDrive(vmName string, isoPath string, generation uint) (uint, uint, error) { - d.CreateDvdDrive_Called = true - d.CreateDvdDrive_VmName = vmName - d.CreateDvdDrive_IsoPath = isoPath - d.CreateDvdDrive_Generation = generation - return d.CreateDvdDrive_ControllerNumber, d.CreateDvdDrive_ControllerLocation, d.CreateDvdDrive_Err -} - -func (d *DriverMock) MountDvdDrive(vmName string, path string, controllerNumber uint, - controllerLocation uint) error { - d.MountDvdDrive_Called = true - d.MountDvdDrive_VmName = vmName - d.MountDvdDrive_Path = path - d.MountDvdDrive_ControllerNumber = controllerNumber - d.MountDvdDrive_ControllerLocation = controllerLocation - return d.MountDvdDrive_Err -} - -func (d *DriverMock) SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint, - generation uint) error { - d.SetBootDvdDrive_Called = true - d.SetBootDvdDrive_VmName = vmName - d.SetBootDvdDrive_ControllerNumber = controllerNumber - d.SetBootDvdDrive_ControllerLocation = controllerLocation - d.SetBootDvdDrive_Generation = generation - return d.SetBootDvdDrive_Err -} - -func (d *DriverMock) SetFirstBootDevice(vmName string, controllerType string, controllerNumber uint, - controllerLocation uint, generation uint) error { - d.SetFirstBootDevice_Called = true - d.SetFirstBootDevice_VmName = vmName - d.SetFirstBootDevice_ControllerType = controllerType - d.SetFirstBootDevice_ControllerNumber = controllerNumber - d.SetFirstBootDevice_ControllerLocation = controllerLocation - d.SetFirstBootDevice_Generation = generation - return d.SetFirstBootDevice_Err -} - -func (d *DriverMock) SetBootOrder(vmName string, bootOrder []string) error { - d.SetBootOrder_Called = true - d.SetBootOrder_VmName = vmName - d.SetBootOrder_BootOrder = bootOrder - return d.SetBootOrder_Err -} - -func (d *DriverMock) UnmountDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { - d.UnmountDvdDrive_Called = true - d.UnmountDvdDrive_VmName = vmName - d.UnmountDvdDrive_ControllerNumber = controllerNumber - d.UnmountDvdDrive_ControllerLocation = controllerLocation - return d.UnmountDvdDrive_Err -} - -func (d *DriverMock) DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { - d.DeleteDvdDrive_Called = true - d.DeleteDvdDrive_VmName = vmName - d.DeleteDvdDrive_ControllerNumber = controllerNumber - d.DeleteDvdDrive_ControllerLocation = controllerLocation - return d.DeleteDvdDrive_Err -} - -func (d *DriverMock) MountFloppyDrive(vmName string, path string) error { - d.MountFloppyDrive_Called = true - d.MountFloppyDrive_VmName = vmName - d.MountFloppyDrive_Path = path - return d.MountFloppyDrive_Err -} - -func (d *DriverMock) UnmountFloppyDrive(vmName string) error { - d.UnmountFloppyDrive_Called = true - d.UnmountFloppyDrive_VmName = vmName - return d.UnmountFloppyDrive_Err -} - -func (d *DriverMock) Connect(vmName string) (context.CancelFunc, error) { - d.Connect_Called = true - d.Connect_VmName = vmName - return d.Connect_Cancel, d.Connect_Err -} - -func (d *DriverMock) Disconnect(cancel context.CancelFunc) { - d.Disconnect_Called = true - d.Disconnect_Cancel = cancel -} diff --git a/builder/hyperv/common/driver_ps_4.go b/builder/hyperv/common/driver_ps_4.go deleted file mode 100644 index e8e8faf29..000000000 --- a/builder/hyperv/common/driver_ps_4.go +++ /dev/null @@ -1,394 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "runtime" - "strconv" - "strings" - - "github.com/hashicorp/packer/builder/hyperv/common/powershell" - "github.com/hashicorp/packer/builder/hyperv/common/powershell/hyperv" -) - -type HypervPS4Driver struct { -} - -func NewHypervPS4Driver() (Driver, error) { - appliesTo := "Applies to Windows 8.1, Windows PowerShell 4.0, Windows Server 2012 R2 only" - - // Check this is Windows - if runtime.GOOS != "windows" { - err := fmt.Errorf("%s", appliesTo) - return nil, err - } - - ps4Driver := &HypervPS4Driver{} - - if err := ps4Driver.Verify(); err != nil { - return nil, err - } - - return ps4Driver, nil -} - -func (d *HypervPS4Driver) IsRunning(vmName string) (bool, error) { - return hyperv.IsRunning(vmName) -} - -func (d *HypervPS4Driver) IsOff(vmName string) (bool, error) { - return hyperv.IsOff(vmName) -} - -func (d *HypervPS4Driver) Uptime(vmName string) (uint64, error) { - return hyperv.Uptime(vmName) -} - -// Start starts a VM specified by the name given. -func (d *HypervPS4Driver) Start(vmName string) error { - return hyperv.StartVirtualMachine(vmName) -} - -// Stop stops a VM specified by the name given. -func (d *HypervPS4Driver) Stop(vmName string) error { - return hyperv.StopVirtualMachine(vmName) -} - -func (d *HypervPS4Driver) Verify() error { - - if err := d.verifyPSVersion(); err != nil { - return err - } - - if err := d.verifyPSHypervModule(); err != nil { - return err - } - - if err := d.verifyHypervPermissions(); err != nil { - return err - } - - return nil -} - -// Get mac address for VM. -func (d *HypervPS4Driver) Mac(vmName string) (string, error) { - res, err := hyperv.Mac(vmName) - - if err != nil { - return res, err - } - - if res == "" { - err := fmt.Errorf("%s", "No mac address.") - return res, err - } - - return res, err -} - -// Get ip address for mac address. -func (d *HypervPS4Driver) IpAddress(mac string) (string, error) { - res, err := hyperv.IpAddress(mac) - - if err != nil { - return res, err - } - - if res == "" { - err := fmt.Errorf("%s", "No ip address.") - return res, err - } - return res, err -} - -// Get host name from ip address -func (d *HypervPS4Driver) GetHostName(ip string) (string, error) { - return powershell.GetHostName(ip) -} - -func (d *HypervPS4Driver) GetVirtualMachineGeneration(vmName string) (uint, error) { - return hyperv.GetVirtualMachineGeneration(vmName) -} - -// Finds the IP address of a host adapter connected to switch -func (d *HypervPS4Driver) GetHostAdapterIpAddressForSwitch(switchName string) (string, error) { - res, err := hyperv.GetHostAdapterIpAddressForSwitch(switchName) - - if err != nil { - return res, err - } - - if res == "" { - err := fmt.Errorf("%s", "No ip address.") - return res, err - } - return res, err -} - -// Type scan codes to virtual keyboard of vm -func (d *HypervPS4Driver) TypeScanCodes(vmName string, scanCodes string) error { - return hyperv.TypeScanCodes(vmName, scanCodes) -} - -// Get network adapter address -func (d *HypervPS4Driver) GetVirtualMachineNetworkAdapterAddress(vmName string) (string, error) { - return hyperv.GetVirtualMachineNetworkAdapterAddress(vmName) -} - -//Set the vlan to use for switch -func (d *HypervPS4Driver) SetNetworkAdapterVlanId(switchName string, vlanId string) error { - return hyperv.SetNetworkAdapterVlanId(switchName, vlanId) -} - -//Set the vlan to use for machine -func (d *HypervPS4Driver) SetVirtualMachineVlanId(vmName string, vlanId string) error { - return hyperv.SetVirtualMachineVlanId(vmName, vlanId) -} - -func (d *HypervPS4Driver) SetVmNetworkAdapterMacAddress(vmName string, mac string) error { - return hyperv.SetVmNetworkAdapterMacAddress(vmName, mac) -} - -//Replace the network adapter with a (non-)legacy adapter -func (d *HypervPS4Driver) ReplaceVirtualMachineNetworkAdapter(vmName string, virtual bool) error { - return hyperv.ReplaceVirtualMachineNetworkAdapter(vmName, virtual) -} - -func (d *HypervPS4Driver) UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { - return hyperv.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName) -} - -func (d *HypervPS4Driver) CreateExternalVirtualSwitch(vmName string, switchName string) error { - return hyperv.CreateExternalVirtualSwitch(vmName, switchName) -} - -func (d *HypervPS4Driver) GetVirtualMachineSwitchName(vmName string) (string, error) { - return hyperv.GetVirtualMachineSwitchName(vmName) -} - -func (d *HypervPS4Driver) ConnectVirtualMachineNetworkAdapterToSwitch(vmName string, switchName string) error { - return hyperv.ConnectVirtualMachineNetworkAdapterToSwitch(vmName, switchName) -} - -func (d *HypervPS4Driver) DeleteVirtualSwitch(switchName string) error { - return hyperv.DeleteVirtualSwitch(switchName) -} - -func (d *HypervPS4Driver) CreateVirtualSwitch(switchName string, switchType string) (bool, error) { - return hyperv.CreateVirtualSwitch(switchName, switchType) -} - -func (d *HypervPS4Driver) AddVirtualMachineHardDrive(vmName string, vhdFile string, vhdName string, - vhdSizeBytes int64, diskBlockSize int64, controllerType string) error { - return hyperv.AddVirtualMachineHardDiskDrive(vmName, vhdFile, vhdName, vhdSizeBytes, - diskBlockSize, controllerType) -} - -func (d *HypervPS4Driver) CheckVMName(vmName string) error { - return hyperv.CheckVMName(vmName) -} - -func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, ram int64, - diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool, - fixedVHD bool, version string) error { - return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, ram, diskSize, diskBlockSize, switchName, - generation, diffDisks, fixedVHD, version) -} - -func (d *HypervPS4Driver) CloneVirtualMachine(cloneFromVmcxPath string, cloneFromVmName string, - cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string, - ram int64, switchName string, copyTF bool) error { - return hyperv.CloneVirtualMachine(cloneFromVmcxPath, cloneFromVmName, cloneFromSnapshotName, - cloneAllSnapshots, vmName, path, harddrivePath, ram, switchName, copyTF) -} - -func (d *HypervPS4Driver) DeleteVirtualMachine(vmName string) error { - return hyperv.DeleteVirtualMachine(vmName) -} - -func (d *HypervPS4Driver) SetVirtualMachineCpuCount(vmName string, cpu uint) error { - return hyperv.SetVirtualMachineCpuCount(vmName, cpu) -} - -func (d *HypervPS4Driver) SetVirtualMachineMacSpoofing(vmName string, enable bool) error { - return hyperv.SetVirtualMachineMacSpoofing(vmName, enable) -} - -func (d *HypervPS4Driver) SetVirtualMachineDynamicMemory(vmName string, enable bool) error { - return hyperv.SetVirtualMachineDynamicMemory(vmName, enable) -} - -func (d *HypervPS4Driver) SetVirtualMachineSecureBoot(vmName string, enable bool, templateName string) error { - return hyperv.SetVirtualMachineSecureBoot(vmName, enable, templateName) -} - -func (d *HypervPS4Driver) SetVirtualMachineVirtualizationExtensions(vmName string, enable bool) error { - return hyperv.SetVirtualMachineVirtualizationExtensions(vmName, enable) -} - -func (d *HypervPS4Driver) EnableVirtualMachineIntegrationService(vmName string, - integrationServiceName string) error { - return hyperv.EnableVirtualMachineIntegrationService(vmName, integrationServiceName) -} - -func (d *HypervPS4Driver) ExportVirtualMachine(vmName string, path string) error { - return hyperv.ExportVirtualMachine(vmName, path) -} - -func (d *HypervPS4Driver) PreserveLegacyExportBehaviour(srcPath string, dstPath string) error { - return hyperv.PreserveLegacyExportBehaviour(srcPath, dstPath) -} - -func (d *HypervPS4Driver) MoveCreatedVHDsToOutputDir(srcPath string, dstPath string) error { - return hyperv.MoveCreatedVHDsToOutputDir(srcPath, dstPath) -} - -func (d *HypervPS4Driver) CompactDisks(path string) (result string, err error) { - return hyperv.CompactDisks(path) -} - -func (d *HypervPS4Driver) RestartVirtualMachine(vmName string) error { - return hyperv.RestartVirtualMachine(vmName) -} - -func (d *HypervPS4Driver) CreateDvdDrive(vmName string, isoPath string, generation uint) (uint, uint, error) { - return hyperv.CreateDvdDrive(vmName, isoPath, generation) -} - -func (d *HypervPS4Driver) MountDvdDrive(vmName string, path string, controllerNumber uint, - controllerLocation uint) error { - return hyperv.MountDvdDrive(vmName, path, controllerNumber, controllerLocation) -} - -func (d *HypervPS4Driver) SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint, - generation uint) error { - return hyperv.SetBootDvdDrive(vmName, controllerNumber, controllerLocation, generation) -} - -func (d *HypervPS4Driver) SetFirstBootDevice(vmName string, controllerType string, controllerNumber uint, - controllerLocation uint, generation uint) error { - return hyperv.SetFirstBootDevice(vmName, controllerType, controllerNumber, controllerLocation, generation) -} - -func (d *HypervPS4Driver) SetBootOrder(vmName string, bootOrder []string) error { - return hyperv.SetBootOrder(vmName, bootOrder) -} - -func (d *HypervPS4Driver) UnmountDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { - return hyperv.UnmountDvdDrive(vmName, controllerNumber, controllerLocation) -} - -func (d *HypervPS4Driver) DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { - return hyperv.DeleteDvdDrive(vmName, controllerNumber, controllerLocation) -} - -func (d *HypervPS4Driver) MountFloppyDrive(vmName string, path string) error { - return hyperv.MountFloppyDrive(vmName, path) -} - -func (d *HypervPS4Driver) UnmountFloppyDrive(vmName string) error { - return hyperv.UnmountFloppyDrive(vmName) -} - -func (d *HypervPS4Driver) verifyPSVersion() error { - - log.Printf("Enter method: %s", "verifyPSVersion") - // check PS is available and is of proper version - versionCmd := "$host.version.Major" - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(versionCmd) - if err != nil { - return err - } - - versionOutput := strings.TrimSpace(cmdOut) - log.Printf("%s output: %s", versionCmd, versionOutput) - - ver, err := strconv.ParseInt(versionOutput, 10, 32) - - if err != nil { - return err - } - - if ver < 4 { - err := fmt.Errorf("%s", "Windows PowerShell version 4.0 or higher is expected") - return err - } - - return nil -} - -func (d *HypervPS4Driver) verifyPSHypervModule() error { - - log.Printf("Enter method: %s", "verifyPSHypervModule") - - versionCmd := "function foo(){try{ $commands = Get-Command -Module Hyper-V;if($commands.Length -eq 0){return $false} }catch{return $false}; return $true} foo" - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(versionCmd) - if err != nil { - return err - } - - if powershell.IsFalse(cmdOut) { - err := fmt.Errorf("%s", "PS Hyper-V module is not loaded. Make sure Hyper-V feature is on.") - return err - } - - return nil -} - -func (d *HypervPS4Driver) isCurrentUserAHyperVAdministrator() (bool, error) { - //SID:S-1-5-32-578 = 'BUILTIN\Hyper-V Administrators' - //https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems - - var script = ` -$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() -$principal = new-object System.Security.Principal.WindowsPrincipal($identity) -$hypervrole = [System.Security.Principal.SecurityIdentifier]"S-1-5-32-578" -return $principal.IsInRole($hypervrole) -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script) - if err != nil { - return false, err - } - - return powershell.IsTrue(cmdOut), nil -} - -func (d *HypervPS4Driver) verifyHypervPermissions() error { - - log.Printf("Enter method: %s", "verifyHypervPermissions") - - hyperVAdmin, err := d.isCurrentUserAHyperVAdministrator() - if err != nil { - log.Printf("Error discovering if current is is a Hyper-V Admin: %s", err) - } - if !hyperVAdmin { - - isAdmin, _ := powershell.IsCurrentUserAnAdministrator() - - if !isAdmin { - err := fmt.Errorf("%s", "Current user is not a member of 'Hyper-V Administrators' or 'Administrators' group") - return err - } - } - - return nil -} - -// Connect connects to a VM specified by the name given. -func (d *HypervPS4Driver) Connect(vmName string) (context.CancelFunc, error) { - return hyperv.ConnectVirtualMachine(vmName) -} - -// Disconnect disconnects to a VM specified by calling the context cancel function returned -// from Connect. -func (d *HypervPS4Driver) Disconnect(cancel context.CancelFunc) { - hyperv.DisconnectVirtualMachine(cancel) -} diff --git a/builder/hyperv/common/output_config.go b/builder/hyperv/common/output_config.go deleted file mode 100644 index 4f6387951..000000000 --- a/builder/hyperv/common/output_config.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:generate packer-sdc struct-markdown -//go:generate packer-sdc mapstructure-to-hcl2 -type OutputConfig - -package common - -import ( - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -type OutputConfig struct { - // This setting specifies the directory that - // artifacts from the build, such as the virtual machine files and disks, - // will be output to. The path to the directory may be relative or - // absolute. If relative, the path is relative to the working directory - // packer is executed from. This directory must not exist or, if - // created, must be empty prior to running the builder. By default this is - // "output-BUILDNAME" where "BUILDNAME" is the name of the build. - OutputDir string `mapstructure:"output_directory" required:"false"` -} - -func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error { - if c.OutputDir == "" { - c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName) - } - - return nil -} diff --git a/builder/hyperv/common/output_config.hcl2spec.go b/builder/hyperv/common/output_config.hcl2spec.go deleted file mode 100644 index 45dfb665b..000000000 --- a/builder/hyperv/common/output_config.hcl2spec.go +++ /dev/null @@ -1,31 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package common - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatOutputConfig is an auto-generated flat version of OutputConfig. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatOutputConfig struct { - OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` -} - -// FlatMapstructure returns a new FlatOutputConfig. -// FlatOutputConfig is an auto-generated flat version of OutputConfig. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*OutputConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatOutputConfig) -} - -// HCL2Spec returns the hcl spec of a OutputConfig. -// This spec is used by HCL to read the fields of OutputConfig. -// The decoded values from this spec will then be applied to a FlatOutputConfig. -func (*FlatOutputConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, - } - return s -} diff --git a/builder/hyperv/common/output_config_test.go b/builder/hyperv/common/output_config_test.go deleted file mode 100644 index 0e1567629..000000000 --- a/builder/hyperv/common/output_config_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package common - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -func TestOutputConfigPrepare(t *testing.T) { - c := new(OutputConfig) - if c.OutputDir != "" { - t.Fatalf("what: %s", c.OutputDir) - } - - pc := &common.PackerConfig{PackerBuildName: "foo"} - errs := c.Prepare(interpolate.NewContext(), pc) - if len(errs) > 0 { - t.Fatalf("err: %#v", errs) - } - - if c.OutputDir == "" { - t.Fatal("should have output dir") - } -} - -func TestOutputConfigPrepare_exists(t *testing.T) { - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - - c := new(OutputConfig) - c.OutputDir = td - - pc := &common.PackerConfig{ - PackerBuildName: "foo", - PackerForce: false, - } - errs := c.Prepare(interpolate.NewContext(), pc) - if len(errs) != 0 { - t.Fatal("should not have errors") - } -} diff --git a/builder/hyperv/common/powershell/hyperv/hyperv.go b/builder/hyperv/common/powershell/hyperv/hyperv.go deleted file mode 100644 index 1c49343b2..000000000 --- a/builder/hyperv/common/powershell/hyperv/hyperv.go +++ /dev/null @@ -1,1585 +0,0 @@ -package hyperv - -import ( - "bytes" - "context" - "errors" - "fmt" - "os/exec" - "regexp" - "strconv" - "strings" - "text/template" - - "github.com/hashicorp/packer/builder/hyperv/common/powershell" -) - -type scriptOptions struct { - Version string - VMName string - VHDX string - Path string - HardDrivePath string - MemoryStartupBytes int64 - NewVHDSizeBytes int64 - VHDBlockSizeBytes int64 - SwitchName string - Generation uint - DiffDisks bool - FixedVHD bool -} - -func GetHostAdapterIpAddressForSwitch(switchName string) (string, error) { - var script = ` -param([string]$switchName, [int]$addressIndex) -$HostVMAdapter = Hyper-V\Get-VMNetworkAdapter -ManagementOS -SwitchName $switchName | Select-Object -First 1 -if ($HostVMAdapter){ - $HostNetAdapter = Get-NetAdapter | Where-Object { $_.DeviceId -eq $HostVMAdapter.DeviceId } - if ($HostNetAdapter){ - $HostNetAdapterIfIndex = @() - $HostNetAdapterIfIndex += $HostNetAdapter.ifIndex - $HostNetAdapterConfiguration = @(get-wmiobject win32_networkadapterconfiguration -filter "IPEnabled = 'TRUE'") | Where-Object { $HostNetAdapterIfIndex.Contains($_.InterfaceIndex)} - if ($HostNetAdapterConfiguration){ - return @($HostNetAdapterConfiguration.IpAddress)[$addressIndex] - } - } -} else { - $HostNetAdapterConfiguration=@(Get-NetIPAddress -CimSession $env:computername -AddressFamily IPv4 | Where-Object { ( $_.InterfaceAlias -notmatch 'Loopback' ) -and ( $_.SuffixOrigin -notmatch "Link" )}) - if ($HostNetAdapterConfiguration) { - return @($HostNetAdapterConfiguration.IpAddress)[$addressIndex] - } else { - return $false - } -} -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, switchName, "0") - - return cmdOut, err -} - -func GetVirtualMachineNetworkAdapterAddress(vmName string) (string, error) { - - var script = ` -param([string]$vmName, [int]$addressIndex) -try { - $adapter = Hyper-V\Get-VMNetworkAdapter -VMName $vmName -ErrorAction SilentlyContinue - if ($adapter.IPAddresses) { - $ip = $adapter.IPAddresses[$addressIndex] - } else { - $vm = Get-CimInstance -ClassName Msvm_ComputerSystem -Namespace root\virtualization\v2 -Filter "ElementName='$vmName'" - $ip_details = (Get-CimAssociatedInstance -InputObject $vm -ResultClassName Msvm_KvpExchangeComponent).GuestIntrinsicExchangeItems | %{ [xml]$_ } | ?{ $_.SelectSingleNode("/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text()='NetworkAddressIPv4']") } - - if ($null -eq $ip_details) { - return $false - } - - $ip_addresses = $ip_details.SelectSingleNode("/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()").Value - $ip = ($ip_addresses -split ";")[0] - } -} catch { - return $false -} -$ip -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, vmName, "0") - - return cmdOut, err -} - -func CreateDvdDrive(vmName string, isoPath string, generation uint) (uint, uint, error) { - var ps powershell.PowerShellCmd - var script string - - script = ` -param([string]$vmName, [string]$isoPath) -$dvdController = Hyper-V\Add-VMDvdDrive -VMName $vmName -path $isoPath -Passthru -$dvdController | Hyper-V\Set-VMDvdDrive -path $null -$result = "$($dvdController.ControllerNumber),$($dvdController.ControllerLocation)" -$result -` - - cmdOut, err := ps.Output(script, vmName, isoPath) - if err != nil { - return 0, 0, err - } - - cmdOutArray := strings.Split(cmdOut, ",") - if len(cmdOutArray) != 2 { - return 0, 0, errors.New("Did not return controller number and controller location") - } - - controllerNumberTemp, err := strconv.ParseUint(strings.TrimSpace(cmdOutArray[0]), 10, 64) - if err != nil { - return 0, 0, err - } - controllerNumber := uint(controllerNumberTemp) - - controllerLocationTemp, err := strconv.ParseUint(strings.TrimSpace(cmdOutArray[1]), 10, 64) - if err != nil { - return controllerNumber, 0, err - } - controllerLocation := uint(controllerLocationTemp) - - return controllerNumber, controllerLocation, err -} - -func MountDvdDrive(vmName string, path string, controllerNumber uint, controllerLocation uint) error { - - var script = ` -param([string]$vmName,[string]$path,[string]$controllerNumber,[string]$controllerLocation) -$vmDvdDrive = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -if (!$vmDvdDrive) {throw 'unable to find dvd drive'} -Hyper-V\Set-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -Path $path -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, path, strconv.FormatInt(int64(controllerNumber), 10), - strconv.FormatInt(int64(controllerLocation), 10)) - return err -} - -func UnmountDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { - var script = ` -param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation) -$vmDvdDrive = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -if (!$vmDvdDrive) {throw 'unable to find dvd drive'} -Hyper-V\Set-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -Path $null -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), - strconv.FormatInt(int64(controllerLocation), 10)) - return err -} - -func SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint, generation uint) error { - - if generation < 2 { - script := ` -param([string]$vmName) -Hyper-V\Set-VMBios -VMName $vmName -StartupOrder @("IDE","CD","LegacyNetworkAdapter","Floppy") -` - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err - } else { - script := ` -param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation) -$vmDvdDrive = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -if (!$vmDvdDrive) {throw 'unable to find dvd drive'} -Hyper-V\Set-VMFirmware -VMName $vmName -FirstBootDevice $vmDvdDrive -ErrorAction SilentlyContinue -` - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), - strconv.FormatInt(int64(controllerLocation), 10)) - return err - } -} - -func SetFirstBootDeviceGen1(vmName string, controllerType string) error { - - // for Generation 1 VMs, we read the value of the VM's boot order, strip the value specified in - // controllerType and insert that value back at the beginning of the list. - // - // controllerType must be 'NET', 'DVD', 'IDE' or 'FLOPPY' (case sensitive) - // The 'NET' value is always replaced with 'LegacyNetworkAdapter' - - if controllerType == "NET" { - controllerType = "LegacyNetworkAdapter" - } - - script := ` -param([string] $vmName, [string] $controllerType) - $vmBootOrder = Hyper-V\Get-VMBios -VMName $vmName | Select-Object -ExpandProperty StartupOrder | Where-Object { $_ -ne $controllerType } - Hyper-V\Set-VMBios -VMName $vmName -StartupOrder (@($controllerType) + $vmBootOrder) -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, controllerType) - return err -} - -func SetFirstBootDeviceGen2(vmName string, controllerType string, controllerNumber uint, controllerLocation uint) error { - - script := `param ([string] $vmName, [string] $controllerType, [int] $controllerNumber, [int] $controllerLocation)` - - switch { - - case controllerType == "CD": - // for CDs we have to use Get-VMDvdDrive to find the device - script += ` -$vmDevice = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -ErrorAction SilentlyContinue` - - case controllerType == "NET": - // for "NET" device, we select the first network adapter on the VM - script += ` -$vmDevice = Hyper-V\Get-VMNetworkAdapter -VMName $vmName -ErrorAction SilentlyContinue | Select-Object -First 1` - - default: - script += ` -$vmDevice = @(Hyper-V\Get-VMIdeController -VMName $vmName -ErrorAction SilentlyContinue) + - @(Hyper-V\Get-VMScsiController -VMName $vmName -ErrorAction SilentlyContinue) | - Select-Object -ExpandProperty Drives | - Where-Object { $_.ControllerType -eq $controllerType } | - Where-Object { ($_.ControllerNumber -eq $controllerNumber) -and ($_.ControllerLocation -eq $controllerLocation) } -` - - } - - script += ` -if ($vmDevice -eq $null) { throw 'unable to find boot device' } -Hyper-V\Set-VMFirmware -VMName $vmName -FirstBootDevice $vmDevice -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, controllerType, strconv.FormatInt(int64(controllerNumber), 10), strconv.FormatInt(int64(controllerLocation), 10)) - return err -} - -func SetFirstBootDevice(vmName string, controllerType string, controllerNumber uint, controllerLocation uint, generation uint) error { - - if generation == 1 { - return SetFirstBootDeviceGen1(vmName, controllerType) - } else { - return SetFirstBootDeviceGen2(vmName, controllerType, controllerNumber, controllerLocation) - } -} - -func SetBootOrder(vmName string, bootOrder []string) error { - var script = ` -param([string]$vmName, [Parameter(ValueFromRemainingArguments=$true)]$bootOrder) - -$bootOrderDrives = $bootOrder | ForEach-Object { - if ($_ -match 'SCSI:([0-9]+):([0-9]+)') { - $controllerNumber = $Matches[1] - $controllerLocation = $Matches[2] - $controller = Hyper-V\Get-VMScsiController -ControllerNumber $controllerNumber $vmName - $controller.Drives | Where-Object {$_.ControllerLocation -eq $controllerLocation} | Select-Object -First 1 - } -} - -Hyper-V\Set-VMFirmware $vmName -BootOrder $bootOrderDrives -` - var ps powershell.PowerShellCmd - params := append([]string{vmName}, bootOrder...) - err := ps.Run(script, params...) - return err -} - -func DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error { - var script = ` -param([string]$vmName,[int]$controllerNumber,[int]$controllerLocation) -$vmDvdDrive = Hyper-V\Get-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -if (!$vmDvdDrive) {throw 'unable to find dvd drive'} -Hyper-V\Remove-VMDvdDrive -VMName $vmName -ControllerNumber $controllerNumber -ControllerLocation $controllerLocation -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, strconv.FormatInt(int64(controllerNumber), 10), - strconv.FormatInt(int64(controllerLocation), 10)) - return err -} - -func DeleteAllDvdDrives(vmName string) error { - var script = ` -param([string]$vmName) -Hyper-V\Get-VMDvdDrive -VMName $vmName | Hyper-V\Remove-VMDvdDrive -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func MountFloppyDrive(vmName string, path string) error { - var script = ` -param([string]$vmName, [string]$path) -Hyper-V\Set-VMFloppyDiskDrive -VMName $vmName -Path $path -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, path) - return err -} - -func UnmountFloppyDrive(vmName string) error { - - var script = ` -param([string]$vmName) -Hyper-V\Set-VMFloppyDiskDrive -VMName $vmName -Path $null -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -// This was created as a proof of concept for moving logic out of the powershell -// scripting so that we can test the pathways activated by our variables. -// Rather than creating a powershell script with several conditionals, this will -// generate a conditional-free script which already sets all of the necessary -// variables inline. -// -// For examples of what this template will generate, you can look at the -// test cases in ./hyperv_test.go -// -func getCreateVMScript(opts *scriptOptions) (string, error) { - - if opts.FixedVHD && opts.Generation == 2 { - return "", fmt.Errorf("Generation 2 VMs don't support fixed disks.") - } - - opts.VHDX = opts.VMName + ".vhdx" - if opts.FixedVHD { - opts.VHDX = opts.VMName + ".vhd" - } - - var tpl = template.Must(template.New("createVM").Parse(` -$vhdPath = Join-Path -Path "{{ .Path }}" -ChildPath "{{ .VHDX }}" - -{{ if ne .HardDrivePath "" -}} - {{- if .DiffDisks -}} - Hyper-V\New-VHD -Path $vhdPath -ParentPath "{{ .HardDrivePath }}" -Differencing -BlockSizeBytes {{ .VHDBlockSizeBytes }} - {{- else -}} - Copy-Item -Path "{{ .HardDrivePath }}" -Destination $vhdPath - {{- end -}} -{{- else -}} - {{- if .FixedVHD -}} - Hyper-V\New-VHD -Path $vhdPath -Fixed -SizeBytes {{ .NewVHDSizeBytes }} - {{- else -}} - Hyper-V\New-VHD -Path $vhdPath -SizeBytes {{ .NewVHDSizeBytes }} -BlockSizeBytes {{ .VHDBlockSizeBytes }} - {{- end -}} -{{- end }} - -Hyper-V\New-VM -Name "{{ .VMName }}" -Path "{{ .Path }}" -MemoryStartupBytes {{ .MemoryStartupBytes }} -VHDPath $vhdPath -SwitchName "{{ .SwitchName }}" -{{- if eq .Generation 2}} -Generation {{ .Generation }} {{- end -}} -{{- if ne .Version ""}} -Version {{ .Version }} {{- end -}} -`)) - - var b bytes.Buffer - err := tpl.Execute(&b, opts) - if err != nil { - return "", err - } - - // Tidy away the excess newlines left over by the template - regex, err := regexp.Compile("^\n") - if err != nil { - return "", err - } - final := regex.ReplaceAllString(b.String(), "") - regex, err = regexp.Compile("\n\n") - if err != nil { - return "", err - } - final = regex.ReplaceAllString(final, "\n") - - return final, nil -} - -func CheckVMName(vmName string) error { - // Check that no vm with the same name is registered, to prevent - // namespace collisions - var gs powershell.PowerShellCmd - getVMCmd := fmt.Sprintf(`Hyper-V\Get-VM -Name "%s"`, vmName) - if err := gs.Run(getVMCmd); err == nil { - return fmt.Errorf("A virtual machine with the name %s is already"+ - " defined in Hyper-V. To avoid a name collision, please set your "+ - "vm_name to a unique value", vmName) - } - - return nil -} - -func CreateVirtualMachine(vmName string, path string, harddrivePath string, ram int64, - diskSize int64, diskBlockSize int64, switchName string, generation uint, - diffDisks bool, fixedVHD bool, version string) error { - opts := scriptOptions{ - Version: version, - VMName: vmName, - Path: path, - HardDrivePath: harddrivePath, - MemoryStartupBytes: ram, - NewVHDSizeBytes: diskSize, - VHDBlockSizeBytes: diskBlockSize, - SwitchName: switchName, - Generation: generation, - DiffDisks: diffDisks, - FixedVHD: fixedVHD, - } - - script, err := getCreateVMScript(&opts) - if err != nil { - return err - } - - var ps powershell.PowerShellCmd - if err = ps.Run(script); err != nil { - return err - } - - if err := DisableAutomaticCheckpoints(vmName); err != nil { - return err - } - if generation != 2 { - return DeleteAllDvdDrives(vmName) - } - return nil -} - -func DisableAutomaticCheckpoints(vmName string) error { - var script = ` -param([string]$vmName) -if ((Get-Command Hyper-V\Set-Vm).Parameters["AutomaticCheckpointsEnabled"]) { - Hyper-V\Set-Vm -Name $vmName -AutomaticCheckpointsEnabled $false } -` - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func ExportVmcxVirtualMachine(exportPath string, vmName string, snapshotName string, allSnapshots bool) error { - var script = ` -param([string]$exportPath, [string]$vmName, [string]$snapshotName, [string]$allSnapshotsString) - -$WorkingPath = Join-Path $exportPath $vmName - -if (Test-Path $WorkingPath) { - throw "Export path working directory: $WorkingPath already exists!" -} - -$allSnapshots = [System.Boolean]::Parse($allSnapshotsString) - -if ($snapshotName) { - $snapshot = Hyper-V\Get-VMSnapshot -VMName $vmName -Name $snapshotName - Hyper-V\Export-VMSnapshot -VMSnapshot $snapshot -Path $exportPath -ErrorAction Stop -} else { - if (!$allSnapshots) { - #Use last snapshot if one was not specified - $snapshot = Hyper-V\Get-VMSnapshot -VMName $vmName | Select -Last 1 - } else { - $snapshot = $null - } - - if (!$snapshot) { - #No snapshot clone - Hyper-V\Export-VM -Name $vmName -Path $exportPath -ErrorAction Stop - } else { - #Snapshot clone - Hyper-V\Export-VMSnapshot -VMSnapshot $snapshot -Path $exportPath -ErrorAction Stop - } -} - -$result = Get-ChildItem -Path $WorkingPath | Move-Item -Destination $exportPath -Force -$result = Remove-Item -Path $WorkingPath - ` - - allSnapshotsString := "False" - if allSnapshots { - allSnapshotsString = "True" - } - - var ps powershell.PowerShellCmd - err := ps.Run(script, exportPath, vmName, snapshotName, allSnapshotsString) - - return err -} - -func CopyVmcxVirtualMachine(exportPath string, cloneFromVmcxPath string) error { - var script = ` -param([string]$exportPath, [string]$cloneFromVmcxPath) -if (!(Test-Path $cloneFromVmcxPath)){ - throw "Clone from vmcx directory: $cloneFromVmcxPath does not exist!" -} - -if (!(Test-Path $exportPath)){ - New-Item -ItemType Directory -Force -Path $exportPath -} -$cloneFromVmcxPath = Join-Path $cloneFromVmcxPath '\*' -Copy-Item $cloneFromVmcxPath $exportPath -Recurse -Force - ` - - var ps powershell.PowerShellCmd - err := ps.Run(script, exportPath, cloneFromVmcxPath) - - return err -} - -func SetVmNetworkAdapterMacAddress(vmName string, mac string) error { - var script = ` -param([string]$vmName, [string]$mac) -Hyper-V\Set-VMNetworkAdapter $vmName -staticmacaddress $mac - ` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, mac) - - return err -} - -func ImportVmcxVirtualMachine(importPath string, vmName string, harddrivePath string, - ram int64, switchName string, copyTF bool) error { - - var script = ` -param([string]$importPath, [string]$vmName, [string]$harddrivePath, [long]$memoryStartupBytes, [string]$switchName, [string]$copy) - -$VirtualHarddisksPath = Join-Path -Path $importPath -ChildPath 'Virtual Hard Disks' -if (!(Test-Path $VirtualHarddisksPath)) { - New-Item -ItemType Directory -Force -Path $VirtualHarddisksPath -} - -$vhdPath = "" -if ($harddrivePath){ - $vhdx = $vmName + '.vhdx' - $vhdPath = Join-Path -Path $VirtualHarddisksPath -ChildPath $vhdx -} - -$VirtualMachinesPath = Join-Path $importPath 'Virtual Machines' -if (!(Test-Path $VirtualMachinesPath)) { - New-Item -ItemType Directory -Force -Path $VirtualMachinesPath -} - -$VirtualMachinePath = Get-ChildItem -Path $VirtualMachinesPath -Filter *.vmcx -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName} -if (!$VirtualMachinePath){ - $VirtualMachinePath = Get-ChildItem -Path $VirtualMachinesPath -Filter *.xml -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName} -} -if (!$VirtualMachinePath){ - $VirtualMachinePath = Get-ChildItem -Path $importPath -Filter *.xml -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName} -} - -$copyBool = $false -switch($copy) { - "true" { $copyBool = $true } - default { $copyBool = $false } -} - -$compatibilityReport = Hyper-V\Compare-VM -Path $VirtualMachinePath -VirtualMachinePath $importPath -SmartPagingFilePath $importPath -SnapshotFilePath $importPath -VhdDestinationPath $VirtualHarddisksPath -GenerateNewId -Copy:$false -if ($vhdPath){ - Copy-Item -Path $harddrivePath -Destination $vhdPath - $existingFirstHarddrive = $compatibilityReport.VM.HardDrives | Select -First 1 - if ($existingFirstHarddrive) { - $existingFirstHarddrive | Hyper-V\Set-VMHardDiskDrive -Path $vhdPath - } else { - Hyper-V\Add-VMHardDiskDrive -VM $compatibilityReport.VM -Path $vhdPath - } -} -Hyper-V\Set-VMMemory -VM $compatibilityReport.VM -StartupBytes $memoryStartupBytes -$networkAdaptor = $compatibilityReport.VM.NetworkAdapters | Select -First 1 -Hyper-V\Disconnect-VMNetworkAdapter -VMNetworkAdapter $networkAdaptor -Hyper-V\Connect-VMNetworkAdapter -VMNetworkAdapter $networkAdaptor -SwitchName $switchName -$vm = Hyper-V\Import-VM -CompatibilityReport $compatibilityReport - -if ($vm) { - $result = Hyper-V\Rename-VM -VM $vm -NewName $VMName -} - ` - var ps powershell.PowerShellCmd - err := ps.Run(script, importPath, vmName, harddrivePath, strconv.FormatInt(ram, 10), switchName, strconv.FormatBool(copyTF)) - - return err -} - -func CloneVirtualMachine(cloneFromVmcxPath string, cloneFromVmName string, - cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, - path string, harddrivePath string, ram int64, switchName string, copyTF bool) error { - - if cloneFromVmName != "" { - if err := ExportVmcxVirtualMachine(path, cloneFromVmName, - cloneFromSnapshotName, cloneAllSnapshots); err != nil { - return err - } - } - - if cloneFromVmcxPath != "" { - if err := CopyVmcxVirtualMachine(path, cloneFromVmcxPath); err != nil { - return err - } - } - - if err := ImportVmcxVirtualMachine(path, vmName, harddrivePath, ram, switchName, copyTF); err != nil { - return err - } - - return DeleteAllDvdDrives(vmName) -} - -func GetVirtualMachineGeneration(vmName string) (uint, error) { - var script = ` -param([string]$vmName) -$generation = Hyper-V\Get-Vm -Name $vmName | %{$_.Generation} -if (!$generation){ - $generation = 1 -} -return $generation -` - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - - if err != nil { - return 0, err - } - - generationUint32, err := strconv.ParseUint(strings.TrimSpace(string(cmdOut)), 10, 32) - - if err != nil { - return 0, err - } - - generation := uint(generationUint32) - - return generation, err -} - -func SetVirtualMachineCpuCount(vmName string, cpu uint) error { - - var script = ` -param([string]$vmName, [int]$cpu) -Hyper-V\Set-VMProcessor -VMName $vmName -Count $cpu -` - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, strconv.FormatInt(int64(cpu), 10)) - return err -} - -func SetVirtualMachineVirtualizationExtensions(vmName string, enableVirtualizationExtensions bool) error { - - var script = ` -param([string]$vmName, [string]$exposeVirtualizationExtensionsString) -$exposeVirtualizationExtensions = [System.Boolean]::Parse($exposeVirtualizationExtensionsString) -Hyper-V\Set-VMProcessor -VMName $vmName -ExposeVirtualizationExtensions $exposeVirtualizationExtensions -` - exposeVirtualizationExtensionsString := "False" - if enableVirtualizationExtensions { - exposeVirtualizationExtensionsString = "True" - } - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, exposeVirtualizationExtensionsString) - return err -} - -func SetVirtualMachineDynamicMemory(vmName string, enableDynamicMemory bool) error { - - var script = ` -param([string]$vmName, [string]$enableDynamicMemoryString) -$enableDynamicMemory = [System.Boolean]::Parse($enableDynamicMemoryString) -Hyper-V\Set-VMMemory -VMName $vmName -DynamicMemoryEnabled $enableDynamicMemory -` - enableDynamicMemoryString := "False" - if enableDynamicMemory { - enableDynamicMemoryString = "True" - } - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, enableDynamicMemoryString) - return err -} - -func SetVirtualMachineMacSpoofing(vmName string, enableMacSpoofing bool) error { - var script = ` -param([string]$vmName, $enableMacSpoofing) -Hyper-V\Set-VMNetworkAdapter -VMName $vmName -MacAddressSpoofing $enableMacSpoofing -` - - var ps powershell.PowerShellCmd - - enableMacSpoofingString := "Off" - if enableMacSpoofing { - enableMacSpoofingString = "On" - } - - err := ps.Run(script, vmName, enableMacSpoofingString) - return err -} - -func SetVirtualMachineSecureBoot(vmName string, enableSecureBoot bool, templateName string) error { - var script = ` -param([string]$vmName, [string]$enableSecureBootString, [string]$templateName) -$cmdlet = Get-Command Hyper-V\Set-VMFirmware -# The SecureBootTemplate parameter is only available in later versions -if ($cmdlet.Parameters.SecureBootTemplate) { - Hyper-V\Set-VMFirmware -VMName $vmName -EnableSecureBoot $enableSecureBootString -SecureBootTemplate $templateName -} else { - Hyper-V\Set-VMFirmware -VMName $vmName -EnableSecureBoot $enableSecureBootString -} -` - - var ps powershell.PowerShellCmd - - enableSecureBootString := "Off" - if enableSecureBoot { - enableSecureBootString = "On" - } - - if templateName == "" { - templateName = "MicrosoftWindows" - } - - err := ps.Run(script, vmName, enableSecureBootString, templateName) - return err -} - -func DeleteVirtualMachine(vmName string) error { - - var script = ` -param([string]$vmName) - -$vm = Hyper-V\Get-VM -Name $vmName -if (($vm.State -ne [Microsoft.HyperV.PowerShell.VMState]::Off) -and ($vm.State -ne [Microsoft.HyperV.PowerShell.VMState]::OffCritical)) { - Hyper-V\Stop-VM -VM $vm -TurnOff -Force -Confirm:$false -} - -Hyper-V\Remove-VM -Name $vmName -Force -Confirm:$false -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func ExportVirtualMachine(vmName string, path string) error { - - var script = ` -param([string]$vmName, [string]$path) -Hyper-V\Export-VM -Name $vmName -Path $path - -if (Test-Path -Path ([IO.Path]::Combine($path, $vmName, 'Virtual Machines', '*.VMCX'))) -{ - $vm = Hyper-V\Get-VM -Name $vmName - $vm_adapter = Hyper-V\Get-VMNetworkAdapter -VM $vm | Select -First 1 - - $config = [xml]@" - - - - $($vm.Generation - 1) - $($vm.Name) - - - - $($vm.ProcessorCount) - - - - $($vm.DynamicMemoryEnabled) - $($vm.MemoryMaximum / 1MB) - $($vm.MemoryMinimum / 1MB) - $($vm.MemoryStartup / 1MB) - - - - $($vm_adapter.SwitchName) - - Optical - - False - MicrosoftWindows - $($vm.Notes) - - -"@ - - if ($vm.Generation -eq 1) - { - $vm_controllers = Hyper-V\Get-VMIdeController -VM $vm - $controller_type = $config.SelectSingleNode('/configuration/vm-controllers') - # IDE controllers are not stored in a special XML container - } - else - { - $vm_controllers = Hyper-V\Get-VMScsiController -VM $vm - $controller_type = $config.CreateElement('scsi') - $controller_type.SetAttribute('ChannelInstanceGuid', 'x') - # SCSI controllers are stored in the scsi XML container - if ((Hyper-V\Get-VMFirmware -VM $vm).SecureBoot -eq [Microsoft.HyperV.PowerShell.OnOffState]::On) - { - $config.configuration.secure_boot_enabled.'#text' = 'True' - $config.configuration.secure_boot_template.'#text' = (Hyper-V\Get-VMFirmware -VM $vm).SecureBootTemplate - } - else - { - $config.configuration.secure_boot_enabled.'#text' = 'False' - } - } - - $vm_controllers | ForEach { - $controller = $config.CreateElement('controller' + $_.ControllerNumber) - $_.Drives | ForEach { - $drive = $config.CreateElement('drive' + ($_.DiskNumber + 0)) - $drive_path = $config.CreateElement('pathname') - $drive_path.SetAttribute('type', 'string') - $drive_path.AppendChild($config.CreateTextNode($_.Path)) - $drive_type = $config.CreateElement('type') - $drive_type.SetAttribute('type', 'string') - if ($_ -is [Microsoft.HyperV.PowerShell.HardDiskDrive]) - { - $drive_type.AppendChild($config.CreateTextNode('VHD')) - } - elseif ($_ -is [Microsoft.HyperV.PowerShell.DvdDrive]) - { - $drive_type.AppendChild($config.CreateTextNode('ISO')) - } - else - { - $drive_type.AppendChild($config.CreateTextNode('NONE')) - } - $drive.AppendChild($drive_path) - $drive.AppendChild($drive_type) - $controller.AppendChild($drive) - } - $controller_type.AppendChild($controller) - } - if ($controller_type.Name -ne 'vm-controllers') - { - $config.SelectSingleNode('/configuration/vm-controllers').AppendChild($controller_type) - } - - $config.Save([IO.Path]::Combine($path, $vm.Name, 'Virtual Machines', 'box.xml')) -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, path) - return err -} - -func PreserveLegacyExportBehaviour(srcPath, dstPath string) error { - - var script = ` -param([string]$srcPath, [string]$dstPath) - -# Validate the paths returning an error if they are empty or don't exist -$srcPath, $dstPath | % { - if ($_) { - if (! (Test-Path $_)) { - [System.Console]::Error.WriteLine("Path $_ does not exist") - exit - } - } else { - [System.Console]::Error.WriteLine("A supplied path is empty") - exit - } -} - -# Export-VM should just create directories at the root of the export path -# but, just in case, move all files as well... -Move-Item -Path (Join-Path (Get-Item $srcPath).FullName "*.*") -Destination (Get-Item $dstPath).FullName - -# Move directories with content; Delete empty directories -$dirObj = Get-ChildItem $srcPath -Directory | % { - New-Object PSObject -Property @{ - FullName=$_.FullName; - HasContent=$(if ($_.GetFileSystemInfos().Count -gt 0) {$true} else {$false}) - } -} -foreach ($directory in $dirObj) { - if ($directory.HasContent) { - Move-Item -Path $directory.FullName -Destination (Get-Item $dstPath).FullName - } else { - Remove-Item -Path $directory.FullName - } -} - -# Only remove the source directory if it is now empty -if ( $((Get-Item $srcPath).GetFileSystemInfos().Count) -eq 0 ) { - Remove-Item -Path $srcPath -} else { - # 'Return' an error message to PowerShellCmd as the directory should - # always be empty at the end of the script. The check is here to stop - # the Remove-Item command from doing any damage if some unforeseen - # error has occured - [System.Console]::Error.WriteLine("Refusing to remove $srcPath as it is not empty") - exit -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, srcPath, dstPath) - - return err -} - -func MoveCreatedVHDsToOutputDir(srcPath, dstPath string) error { - - var script = ` -param([string]$srcPath, [string]$dstPath) - -# Validate the paths returning an error if the supplied path is empty -# or if the paths don't exist -$srcPath, $dstPath | % { - if ($_) { - if (! (Test-Path $_)) { - [System.Console]::Error.WriteLine("Path $_ does not exist") - exit - } - } else { - [System.Console]::Error.WriteLine("A supplied path is empty") - exit - } -} - -# Convert to absolute paths if required -$srcPathAbs = (Get-Item($srcPath)).FullName -$dstPathAbs = (Get-Item($dstPath)).FullName - -# Get the full path to all disks under the directory or exit if none are found -$disks = Get-ChildItem -Path $srcPathAbs -Recurse -Filter *.vhd* -ErrorAction SilentlyContinue | % { $_.FullName } -if ($disks.Length -eq 0) { - [System.Console]::Error.WriteLine("No disks found under $srcPathAbs") - exit -} - -# Set up directory for VHDs in the destination directory -$vhdDstDir = Join-Path -Path $dstPathAbs -ChildPath 'Virtual Hard Disks' -if (! (Test-Path $vhdDstDir)) { - New-Item -ItemType Directory -Force -Path $vhdDstDir -} - -# Move the disks -foreach ($disk in $disks) { - Move-Item -Path $disk -Destination $vhdDstDir -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, srcPath, dstPath) - - return err -} - -func CompactDisks(path string) (result string, err error) { - var script = ` -param([string]$srcPath) - -$disks = Get-ChildItem -Path $srcPath -Recurse -ErrorAction SilentlyContinue |where {$_.extension -in ".vhdx",".vhd"} |foreach { $_.FullName } -# Failure to find any disks is treated as a 'soft' error. Simply print out -# a warning and exit -if ($disks.Length -eq 0) { - Write-Output "WARNING: No disks found under $srcPath" - exit -} - -foreach ($disk in $disks) { - Write-Output "Compacting disk: $(Split-Path $disk -leaf)" - - $sizeBefore = (Get-Item -Path $disk).Length - Optimize-VHD -Path $disk -Mode Full - $sizeAfter = (Get-Item -Path $disk).Length - - # Calculate the percentage change in disk size - if ($sizeAfter -gt 0) { # Protect against division by zero - $percentChange = ( ( $sizeAfter / $sizeBefore ) * 100 ) - 100 - switch($percentChange) { - {$_ -lt 0} {Write-Output "Disk size reduced by: $(([math]::Abs($_)).ToString("#.#"))%"} - {$_ -eq 0} {Write-Output "Disk size is unchanged"} - {$_ -gt 0} {Write-Output "WARNING: Disk size increased by: $($_.ToString("#.#"))%"} - } - } -} -` - - var ps powershell.PowerShellCmd - result, err = ps.Output(script, path) - return -} - -func CreateVirtualSwitch(switchName string, switchType string) (bool, error) { - - var script = ` -param([string]$switchName,[string]$switchType) -$switches = Hyper-V\Get-VMSwitch -Name $switchName -ErrorAction SilentlyContinue -if ($switches.Count -eq 0) { - Hyper-V\New-VMSwitch -Name $switchName -SwitchType $switchType - return $true -} -return $false -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, switchName, switchType) - var created = strings.TrimSpace(cmdOut) == "True" - return created, err -} - -func DeleteVirtualSwitch(switchName string) error { - - var script = ` -param([string]$switchName) -$switch = Hyper-V\Get-VMSwitch -Name $switchName -ErrorAction SilentlyContinue -if ($switch -ne $null) { - $switch | Hyper-V\Remove-VMSwitch -Force -Confirm:$false -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, switchName) - return err -} - -func StartVirtualMachine(vmName string) error { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue -if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Off) { - Hyper-V\Start-VM -Name $vmName -Confirm:$false -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func RestartVirtualMachine(vmName string) error { - - var script = ` -param([string]$vmName) -Hyper-V\Restart-VM $vmName -Force -Confirm:$false -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func StopVirtualMachine(vmName string) error { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { - Hyper-V\Stop-VM -VM $vm -Force -Confirm:$false -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func EnableVirtualMachineIntegrationService(vmName string, integrationServiceName string) error { - - integrationServiceId := "" - switch integrationServiceName { - case "Time Synchronization": - integrationServiceId = "2497F4DE-E9FA-4204-80E4-4B75C46419C0" - case "Heartbeat": - integrationServiceId = "84EAAE65-2F2E-45F5-9BB5-0E857DC8EB47" - case "Key-Value Pair Exchange": - integrationServiceId = "2A34B1C2-FD73-4043-8A5B-DD2159BC743F" - case "Shutdown": - integrationServiceId = "9F8233AC-BE49-4C79-8EE3-E7E1985B2077" - case "VSS": - integrationServiceId = "5CED1297-4598-4915-A5FC-AD21BB4D02A4" - case "Guest Service Interface": - integrationServiceId = "6C09BB55-D683-4DA0-8931-C9BF705F6480" - default: - panic("unrecognized Integration Service Name") - } - - var script = ` -param([string]$vmName,[string]$integrationServiceId) -Hyper-V\Get-VMIntegrationService -VmName $vmName | ?{$_.Id -match $integrationServiceId} | Hyper-V\Enable-VMIntegrationService -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, integrationServiceId) - return err -} - -func SetNetworkAdapterVlanId(switchName string, vlanId string) error { - - var script = ` -param([string]$networkAdapterName,[string]$vlanId) -Hyper-V\Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $networkAdapterName -Access -VlanId $vlanId -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, switchName, vlanId) - return err -} - -func SetVirtualMachineVlanId(vmName string, vlanId string) error { - - var script = ` -param([string]$vmName,[string]$vlanId) -Hyper-V\Set-VMNetworkAdapterVlan -VMName $vmName -Access -VlanId $vlanId -` - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, vlanId) - return err -} - -func ReplaceVirtualMachineNetworkAdapter(vmName string, legacy bool) error { - - var script = ` -param([string]$vmName,[string]$legacyString) -$legacy = [System.Boolean]::Parse($legacyString) -$switch = (Get-VMNetworkAdapter -VMName $vmName).SwitchName -Remove-VMNetworkAdapter -VMName $vmName -Add-VMNetworkAdapter -VMName $vmName -SwitchName $switch -Name $vmName -IsLegacy $legacy -` - legacyString := "False" - if legacy { - legacyString = "True" - } - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, legacyString) - return err -} - -func GetExternalOnlineVirtualSwitch() (string, error) { - - var script = ` -$adapters = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq 'Up' } | Sort-Object -Descending -Property Speed -foreach ($adapter in $adapters) { - $switch = Hyper-V\Get-VMSwitch -SwitchType External | Where-Object { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription } - - if ($switch -ne $null) { - $switch.Name - break - } -} -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script) - if err != nil { - return "", err - } - - var switchName = strings.TrimSpace(cmdOut) - return switchName, nil -} - -func CreateExternalVirtualSwitch(vmName string, switchName string) error { - - var script = ` -param([string]$vmName,[string]$switchName) -$switch = $null -$names = @('ethernet','wi-fi','lan') -$adapters = foreach ($name in $names) { - Get-NetAdapter -Physical -Name $name -ErrorAction SilentlyContinue | where status -eq 'up' -} - -foreach ($adapter in $adapters) { - $switch = Hyper-V\Get-VMSwitch -SwitchType External | where { $_.NetAdapterInterfaceDescription -eq $adapter.InterfaceDescription } - - if ($switch -eq $null) { - $switch = Hyper-V\New-VMSwitch -Name $switchName -NetAdapterName $adapter.Name -AllowManagementOS $true -Notes 'Parent OS, VMs, WiFi' - } - - if ($switch -ne $null) { - break - } -} - -if($switch -ne $null) { - Hyper-V\Get-VMNetworkAdapter -VMName $vmName | Hyper-V\Connect-VMNetworkAdapter -VMSwitch $switch -} else { - Write-Error 'No internet adapters found' -} -` - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, switchName) - return err -} - -func GetVirtualMachineSwitchName(vmName string) (string, error) { - - var script = ` -param([string]$vmName) -(Hyper-V\Get-VMNetworkAdapter -VMName $vmName).SwitchName -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - if err != nil { - return "", err - } - - return strings.TrimSpace(cmdOut), nil -} - -func ConnectVirtualMachineNetworkAdapterToSwitch(vmName string, switchName string) error { - - var script = ` -param([string]$vmName,[string]$switchName) -Hyper-V\Get-VMNetworkAdapter -VMName $vmName | Hyper-V\Connect-VMNetworkAdapter -SwitchName $switchName -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, switchName) - return err -} - -func AddVirtualMachineHardDiskDrive(vmName string, vhdRoot string, vhdName string, vhdSizeBytes int64, - vhdBlockSize int64, controllerType string) error { - - var script = ` -param([string]$vmName,[string]$vhdRoot, [string]$vhdName, [string]$vhdSizeInBytes, [string]$vhdBlockSizeInByte, [string]$controllerType) -$vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdName -Hyper-V\New-VHD -path $vhdPath -SizeBytes $vhdSizeInBytes -BlockSizeBytes $vhdBlockSizeInByte -Hyper-V\Add-VMHardDiskDrive -VMName $vmName -path $vhdPath -controllerType $controllerType -` - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, vhdRoot, vhdName, strconv.FormatInt(vhdSizeBytes, 10), strconv.FormatInt(vhdBlockSize, 10), controllerType) - return err -} - -func UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error { - - var script = ` -param([string]$vmName,[string]$switchName) -Hyper-V\Set-VMNetworkAdapterVlan -VMName $vmName -Untagged -Hyper-V\Set-VMNetworkAdapterVlan -ManagementOS -VMNetworkAdapterName $switchName -Untagged -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, switchName) - return err -} - -func IsRunning(vmName string) (bool, error) { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue -$vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - - if err != nil { - return false, err - } - - var isRunning = strings.TrimSpace(cmdOut) == "True" - return isRunning, err -} - -func IsOff(vmName string) (bool, error) { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue -$vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Off -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - - if err != nil { - return false, err - } - - var isRunning = strings.TrimSpace(cmdOut) == "True" - return isRunning, err -} - -func Uptime(vmName string) (uint64, error) { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue -$vm.Uptime.TotalSeconds -` - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - - if err != nil { - return 0, err - } - - uptime, err := strconv.ParseUint(strings.TrimSpace(cmdOut), 10, 64) - - return uptime, err -} - -func Mac(vmName string) (string, error) { - var script = ` -param([string]$vmName, [int]$adapterIndex) -try { - $adapter = Hyper-V\Get-VMNetworkAdapter -VMName $vmName -ErrorAction SilentlyContinue - $mac = $adapter[$adapterIndex].MacAddress - if($mac -eq $null) { - return "" - } -} catch { - return "" -} -$mac -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, vmName, "0") - - return cmdOut, err -} - -func IpAddress(mac string) (string, error) { - var script = ` -param([string]$mac, [int]$addressIndex) -try { - $vm = Hyper-V\Get-VM | ?{$_.NetworkAdapters.MacAddress -eq $mac} - if ($vm.NetworkAdapters.IpAddresses) { - $ipAddresses = $vm.NetworkAdapters.IPAddresses - if ($ipAddresses -isnot [array]) { - $ipAddresses = @($ipAddresses) - } - $ip = $ipAddresses[$addressIndex] - } else { - $vm_info = Get-CimInstance -ClassName Msvm_ComputerSystem -Namespace root\virtualization\v2 -Filter "ElementName='$($vm.Name)'" - $ip_details = (Get-CimAssociatedInstance -InputObject $vm_info -ResultClassName Msvm_KvpExchangeComponent).GuestIntrinsicExchangeItems | %{ [xml]$_ } | ?{ $_.SelectSingleNode("/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text()='NetworkAddressIPv4']") } - - if ($null -eq $ip_details) { - return "" - } - - $ip_addresses = $ip_details.SelectSingleNode("/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()").Value - $ip = ($ip_addresses -split ";")[0] - } -} catch { - return "" -} -$ip -` - - var ps powershell.PowerShellCmd - cmdOut, err := ps.Output(script, mac, "0") - - return cmdOut, err -} - -func TurnOff(vmName string) error { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue -if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { - Hyper-V\Stop-VM -Name $vmName -TurnOff -Force -Confirm:$false -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func ShutDown(vmName string) error { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue -if ($vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running) { - Hyper-V\Stop-VM -Name $vmName -Force -Confirm:$false -} -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName) - return err -} - -func TypeScanCodes(vmName string, scanCodes string) error { - if len(scanCodes) == 0 { - return nil - } - - var script = ` -param([string]$vmName, [string]$scanCodes) - #Requires -Version 3 - - function Hyper-V\Get-VMConsole - { - [CmdletBinding()] - param ( - [Parameter(Mandatory)] - [string] $VMName - ) - - $ErrorActionPreference = "Stop" - - $vm = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_ComputerSystem -ErrorAction Ignore -Verbose:$false | where ElementName -eq $VMName | select -first 1 - if ($vm -eq $null){ - Write-Error ("VirtualMachine({0}) is not found!" -f $VMName) - } - - $vmKeyboard = $vm | Get-CimAssociatedInstance -ResultClassName "Msvm_Keyboard" -ErrorAction Ignore -Verbose:$false - - if ($vmKeyboard -eq $null) { - $vmKeyboard = Get-CimInstance -Namespace "root\virtualization\v2" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1 - } - - if ($vmKeyboard -eq $null) { - $vmKeyboard = Get-CimInstance -Namespace "root\virtualization" -ClassName Msvm_Keyboard -ErrorAction Ignore -Verbose:$false | where SystemName -eq $vm.Name | select -first 1 - } - - if ($vmKeyboard -eq $null){ - Write-Error ("VirtualMachine({0}) keyboard class is not found!" -f $VMName) - } - - #TODO: It may be better using New-Module -AsCustomObject to return console object? - - #Console object to return - $console = [pscustomobject] @{ - Msvm_ComputerSystem = $vm - Msvm_Keyboard = $vmKeyboard - } - - #Need to import assembly to use System.Windows.Input.Key - Add-Type -AssemblyName WindowsBase - - #region Add Console Members - $console | Add-Member -MemberType ScriptMethod -Name TypeText -Value { - [OutputType([bool])] - param ( - [ValidateNotNullOrEmpty()] - [Parameter(Mandatory)] - [string] $AsciiText - ) - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeText" -Arguments @{ asciiText = $AsciiText } - return (0 -eq $result.ReturnValue) - } - - #Define method:TypeCtrlAltDel - $console | Add-Member -MemberType ScriptMethod -Name TypeCtrlAltDel -Value { - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeCtrlAltDel" - return (0 -eq $result.ReturnValue) - } - - #Define method:TypeKey - $console | Add-Member -MemberType ScriptMethod -Name TypeKey -Value { - [OutputType([bool])] - param ( - [Parameter(Mandatory)] - [Windows.Input.Key] $Key, - [Windows.Input.ModifierKeys] $ModifierKey = [Windows.Input.ModifierKeys]::None - ) - - $keyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey($Key) - - switch ($ModifierKey) - { - ([Windows.Input.ModifierKeys]::Control){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftCtrl)} - ([Windows.Input.ModifierKeys]::Alt){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftAlt)} - ([Windows.Input.ModifierKeys]::Shift){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LeftShift)} - ([Windows.Input.ModifierKeys]::Windows){ $modifierKeyCode = [Windows.Input.KeyInterop]::VirtualKeyFromKey([Windows.Input.Key]::LWin)} - } - - if ($ModifierKey -eq [Windows.Input.ModifierKeys]::None) - { - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } - } - else - { - $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "PressKey" -Arguments @{ keyCode = $modifierKeyCode } - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeKey" -Arguments @{ keyCode = $keyCode } - $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "ReleaseKey" -Arguments @{ keyCode = $modifierKeyCode } - } - $result = return (0 -eq $result.ReturnValue) - } - - #Define method:Scancodes - $console | Add-Member -MemberType ScriptMethod -Name TypeScancodes -Value { - [OutputType([bool])] - param ( - [Parameter(Mandatory)] - [byte[]] $ScanCodes - ) - $result = $this.Msvm_Keyboard | Invoke-CimMethod -MethodName "TypeScancodes" -Arguments @{ ScanCodes = $ScanCodes } - return (0 -eq $result.ReturnValue) - } - - #Define method:ExecCommand - $console | Add-Member -MemberType ScriptMethod -Name ExecCommand -Value { - param ( - [Parameter(Mandatory)] - [string] $Command - ) - if ([String]::IsNullOrEmpty($Command)){ - return - } - - $console.TypeText($Command) > $null - $console.TypeKey([Windows.Input.Key]::Enter) > $null - #sleep -Milliseconds 100 - } - - #Define method:Dispose - $console | Add-Member -MemberType ScriptMethod -Name Dispose -Value { - $this.Msvm_ComputerSystem.Dispose() - $this.Msvm_Keyboard.Dispose() - } - - - #endregion - - return $console - } - - $vmConsole = Hyper-V\Get-VMConsole -VMName $vmName - $scanCodesToSend = '' - $scanCodes.Split(' ') | %{ - $scanCode = $_ - - if ($scanCode.StartsWith('wait')){ - $timeToWait = $scanCode.Substring(4) - if (!$timeToWait){ - $timeToWait = "1" - } - - if ($scanCodesToSend){ - $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) - - $scanCodesToSendByteArray | %{ - $vmConsole.TypeScancodes($_) - } - } - - write-host "Special code found, will sleep $timeToWait second(s) at this point." - Start-Sleep -s $timeToWait - - $scanCodesToSend = '' - } else { - if ($scanCodesToSend){ - write-host "Sending special code '$scanCodesToSend' '$scanCode'" - $scanCodesToSend = "$scanCodesToSend $scanCode" - } else { - write-host "Sending char '$scanCode'" - $scanCodesToSend = "$scanCode" - } - } - } - if ($scanCodesToSend){ - $scanCodesToSendByteArray = [byte[]]@($scanCodesToSend.Split(' ') | %{"0x$_"}) - - $scanCodesToSendByteArray | %{ - $vmConsole.TypeScancodes($_) - } - } -` - - var ps powershell.PowerShellCmd - err := ps.Run(script, vmName, scanCodes) - return err -} - -func ConnectVirtualMachine(vmName string) (context.CancelFunc, error) { - ctx, cancel := context.WithCancel(context.Background()) - cmd := exec.CommandContext(ctx, "vmconnect.exe", "localhost", vmName) - err := cmd.Start() - if err != nil { - // Failed to start so cancel function not required - cancel = nil - } - return cancel, err -} - -func DisconnectVirtualMachine(cancel context.CancelFunc) { - cancel() -} diff --git a/builder/hyperv/common/powershell/hyperv/hyperv_test.go b/builder/hyperv/common/powershell/hyperv/hyperv_test.go deleted file mode 100644 index d5a14661b..000000000 --- a/builder/hyperv/common/powershell/hyperv/hyperv_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package hyperv - -import ( - "strings" - "testing" -) - -func Test_getCreateVMScript(t *testing.T) { - opts := scriptOptions{ - Version: "5.0", - VMName: "myvm", - Path: "C://mypath", - HardDrivePath: "C://harddrivepath", - MemoryStartupBytes: int64(1024), - NewVHDSizeBytes: int64(8192), - VHDBlockSizeBytes: int64(10), - SwitchName: "hyperv-vmx-switch", - Generation: uint(1), - DiffDisks: true, - FixedVHD: true, - } - - // Check Fixed VHD conditional set - scriptString, err := getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - - expected := `$vhdPath = Join-Path -Path "C://mypath" -ChildPath "myvm.vhd" -Hyper-V\New-VHD -Path $vhdPath -ParentPath "C://harddrivepath" -Differencing -BlockSizeBytes 10 -Hyper-V\New-VM -Name "myvm" -Path "C://mypath" -MemoryStartupBytes 1024 -VHDPath $vhdPath -SwitchName "hyperv-vmx-switch" -Version 5.0` - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } - - // We should never get here thanks to good template validation, but it's - // good to fail rather than trying to run the ps script and erroring. - opts.Generation = uint(2) - scriptString, err = getCreateVMScript(&opts) - if err == nil { - t.Fatalf("Should have Error: %s", err.Error()) - } - - // Check VHDX conditional set - opts.FixedVHD = false - scriptString, err = getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - - expected = `$vhdPath = Join-Path -Path "C://mypath" -ChildPath "myvm.vhdx" -Hyper-V\New-VHD -Path $vhdPath -ParentPath "C://harddrivepath" -Differencing -BlockSizeBytes 10 -Hyper-V\New-VM -Name "myvm" -Path "C://mypath" -MemoryStartupBytes 1024 -VHDPath $vhdPath -SwitchName "hyperv-vmx-switch" -Generation 2 -Version 5.0` - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } - - // Check generation 1 no fixed VHD - opts.FixedVHD = false - opts.Generation = uint(1) - scriptString, err = getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - - expected = `$vhdPath = Join-Path -Path "C://mypath" -ChildPath "myvm.vhdx" -Hyper-V\New-VHD -Path $vhdPath -ParentPath "C://harddrivepath" -Differencing -BlockSizeBytes 10 -Hyper-V\New-VM -Name "myvm" -Path "C://mypath" -MemoryStartupBytes 1024 -VHDPath $vhdPath -SwitchName "hyperv-vmx-switch" -Version 5.0` - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } - - // Check that we use generation one template even if generation is unset - opts.Generation = uint(0) - scriptString, err = getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - // same "expected" as above - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } - - opts.Version = "" - scriptString, err = getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - expected = `$vhdPath = Join-Path -Path "C://mypath" -ChildPath "myvm.vhdx" -Hyper-V\New-VHD -Path $vhdPath -ParentPath "C://harddrivepath" -Differencing -BlockSizeBytes 10 -Hyper-V\New-VM -Name "myvm" -Path "C://mypath" -MemoryStartupBytes 1024 -VHDPath $vhdPath -SwitchName "hyperv-vmx-switch"` - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } - - opts.DiffDisks = false - scriptString, err = getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - expected = `$vhdPath = Join-Path -Path "C://mypath" -ChildPath "myvm.vhdx" -Copy-Item -Path "C://harddrivepath" -Destination $vhdPath -Hyper-V\New-VM -Name "myvm" -Path "C://mypath" -MemoryStartupBytes 1024 -VHDPath $vhdPath -SwitchName "hyperv-vmx-switch"` - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } - - opts.HardDrivePath = "" - scriptString, err = getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - expected = `$vhdPath = Join-Path -Path "C://mypath" -ChildPath "myvm.vhdx" -Hyper-V\New-VHD -Path $vhdPath -SizeBytes 8192 -BlockSizeBytes 10 -Hyper-V\New-VM -Name "myvm" -Path "C://mypath" -MemoryStartupBytes 1024 -VHDPath $vhdPath -SwitchName "hyperv-vmx-switch"` - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } - - opts.FixedVHD = true - scriptString, err = getCreateVMScript(&opts) - if err != nil { - t.Fatalf("Error: %s", err.Error()) - } - expected = `$vhdPath = Join-Path -Path "C://mypath" -ChildPath "myvm.vhd" -Hyper-V\New-VHD -Path $vhdPath -Fixed -SizeBytes 8192 -Hyper-V\New-VM -Name "myvm" -Path "C://mypath" -MemoryStartupBytes 1024 -VHDPath $vhdPath -SwitchName "hyperv-vmx-switch"` - if ok := strings.Compare(scriptString, expected); ok != 0 { - t.Fatalf("EXPECTED: \n%s\n\n RECEIVED: \n%s\n\n", expected, scriptString) - } -} diff --git a/builder/hyperv/common/powershell/powershell.go b/builder/hyperv/common/powershell/powershell.go deleted file mode 100644 index 706b2f41b..000000000 --- a/builder/hyperv/common/powershell/powershell.go +++ /dev/null @@ -1,371 +0,0 @@ -package powershell - -import ( - "bytes" - "fmt" - "io" - "log" - "os" - "os/exec" - "strconv" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/tmp" -) - -const ( - powerShellFalse = "False" - powerShellTrue = "True" -) - -func IsTrue(s string) bool { - return strings.TrimSpace(s) == powerShellTrue -} - -func IsFalse(s string) bool { - return strings.TrimSpace(s) == powerShellFalse -} - -type PowerShellCmd struct { - Stdout io.Writer - Stderr io.Writer -} - -func (ps *PowerShellCmd) Run(fileContents string, params ...string) error { - _, err := ps.Output(fileContents, params...) - return err -} - -// Output runs the PowerShell command and returns its standard output. -func (ps *PowerShellCmd) Output(fileContents string, params ...string) (string, error) { - path, err := ps.getPowerShellPath() - if err != nil { - return "", fmt.Errorf("Cannot find PowerShell in the path") - } - - filename, err := saveScript(fileContents) - if err != nil { - return "", err - } - - debug := os.Getenv("PACKER_POWERSHELL_DEBUG") != "" - verbose := debug || os.Getenv("PACKER_POWERSHELL_VERBOSE") != "" - - if !debug { - defer os.Remove(filename) - } - - args := createArgs(filename, params...) - - if verbose { - log.Printf("Run: %s %s", path, args) - } - - var stdout, stderr bytes.Buffer - command := exec.Command(path, args...) - command.Stdout = &stdout - command.Stderr = &stderr - - err = command.Run() - - if ps.Stdout != nil { - stdout.WriteTo(ps.Stdout) - } - - if ps.Stderr != nil { - stderr.WriteTo(ps.Stderr) - } - - stderrString := strings.TrimSpace(stderr.String()) - - if _, ok := err.(*exec.ExitError); ok { - err = fmt.Errorf("PowerShell error: %s", stderrString) - } - - if len(stderrString) > 0 { - err = fmt.Errorf("PowerShell error: %s", stderrString) - } - - stdoutString := strings.TrimSpace(stdout.String()) - - if verbose && stdoutString != "" { - log.Printf("stdout: %s", stdoutString) - } - - // only write the stderr string if verbose because - // the error string will already be in the err return value. - if verbose && stderrString != "" { - log.Printf("stderr: %s", stderrString) - } - - return stdoutString, err -} - -func IsPowershellAvailable() (bool, string, error) { - path, err := exec.LookPath("powershell") - if err != nil { - return false, "", err - } else { - return true, path, err - } -} - -func (ps *PowerShellCmd) getPowerShellPath() (string, error) { - powershellAvailable, path, err := IsPowershellAvailable() - if err != nil { - log.Fatalf("IsPowershellAvailable: %v", err) - } - if !powershellAvailable { - log.Fatal("Cannot find PowerShell in the path") - return "", err - } - - return path, nil -} - -func saveScript(fileContents string) (string, error) { - file, err := tmp.File("powershell") - if err != nil { - return "", err - } - - _, err = file.Write([]byte(fileContents)) - if err != nil { - return "", err - } - - err = file.Close() - if err != nil { - return "", err - } - - newFilename := file.Name() + ".ps1" - err = os.Rename(file.Name(), newFilename) - if err != nil { - return "", err - } - - return newFilename, nil -} - -func createArgs(filename string, params ...string) []string { - args := make([]string, len(params)+5) - args[0] = "-ExecutionPolicy" - args[1] = "Bypass" - - args[2] = "-NoProfile" - - args[3] = "-File" - args[4] = filename - - for key, value := range params { - args[key+5] = value - } - - return args -} - -func GetHostAvailableMemory() float64 { - - var script = "(Get-WmiObject Win32_OperatingSystem).FreePhysicalMemory / 1024" - - var ps PowerShellCmd - output, _ := ps.Output(script) - - freeMB, _ := strconv.ParseFloat(output, 64) - - return freeMB -} - -func GetHostName(ip string) (string, error) { - - var script = ` -param([string]$ip) -try { - $HostName = [System.Net.Dns]::GetHostEntry($ip).HostName - if ($HostName -ne $null) { - $HostName = $HostName.Split('.')[0] - } - $HostName -} catch { } -` - - // - var ps PowerShellCmd - cmdOut, err := ps.Output(script, ip) - if err != nil { - return "", err - } - - return cmdOut, nil -} - -func IsCurrentUserAnAdministrator() (bool, error) { - var script = ` -$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent() -$principal = new-object System.Security.Principal.WindowsPrincipal($identity) -$administratorRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator -return $principal.IsInRole($administratorRole) -` - - var ps PowerShellCmd - cmdOut, err := ps.Output(script) - if err != nil { - return false, err - } - - res := strings.TrimSpace(cmdOut) - return res == powerShellTrue, nil -} - -func ModuleExists(moduleName string) (bool, error) { - - var script = ` -param([string]$moduleName) -(Get-Module -Name $moduleName) -ne $null -` - var ps PowerShellCmd - cmdOut, err := ps.Output(script) - if err != nil { - return false, err - } - - res := strings.TrimSpace(cmdOut) - - if res == powerShellFalse { - err := fmt.Errorf("PowerShell %s module is not loaded. Make sure %s feature is on.", moduleName, moduleName) - return false, err - } - - return true, nil -} - -func HasVirtualMachineVirtualizationExtensions() (bool, error) { - - var script = ` -(GET-Command Hyper-V\Set-VMProcessor).parameters.keys -contains "ExposeVirtualizationExtensions" -` - - var ps PowerShellCmd - cmdOut, err := ps.Output(script) - - if err != nil { - return false, err - } - - var hasVirtualMachineVirtualizationExtensions = strings.TrimSpace(cmdOut) == "True" - return hasVirtualMachineVirtualizationExtensions, err -} - -func DoesVirtualMachineExist(vmName string) (bool, error) { - - var script = ` -param([string]$vmName) -return (Hyper-V\Get-VM -Name $vmName | ?{$_.Name -eq $vmName}) -ne $null -` - - var ps PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - - if err != nil { - return false, err - } - - var exists = strings.TrimSpace(cmdOut) == "True" - return exists, err -} - -func DoesVirtualMachineSnapshotExist(vmName string, snapshotName string) (bool, error) { - - var script = ` -param([string]$vmName, [string]$snapshotName) -return (Hyper-V\Get-VMSnapshot -VMName $vmName | ?{$_.Name -eq $snapshotName}) -ne $null -` - - var ps PowerShellCmd - cmdOut, err := ps.Output(script, vmName, snapshotName) - - if err != nil { - return false, err - } - - var exists = strings.TrimSpace(cmdOut) == "True" - return exists, err -} - -func IsVirtualMachineOn(vmName string) (bool, error) { - - var script = ` -param([string]$vmName) -$vm = Hyper-V\Get-VM -Name $vmName -ErrorAction SilentlyContinue -$vm.State -eq [Microsoft.HyperV.PowerShell.VMState]::Running -` - - var ps PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - - if err != nil { - return false, err - } - - var isRunning = strings.TrimSpace(cmdOut) == "True" - return isRunning, err -} - -func GetVirtualMachineGeneration(vmName string) (uint, error) { - var script = ` -param([string]$vmName) -$generation = Hyper-V\Get-Vm -Name $vmName | %{$_.Generation} -if (!$generation){ - $generation = 1 -} -return $generation -` - var ps PowerShellCmd - cmdOut, err := ps.Output(script, vmName) - - if err != nil { - return 0, err - } - - generationUint32, err := strconv.ParseUint(strings.TrimSpace(string(cmdOut)), 10, 32) - - if err != nil { - return 0, err - } - - generation := uint(generationUint32) - - return generation, err -} - -func SetUnattendedProductKey(path string, productKey string) error { - - var script = ` -param([string]$path,[string]$productKey) - -$unattend = [xml](Get-Content -Path $path) -$ns = @{ un = 'urn:schemas-microsoft-com:unattend' } - -$setupNode = $unattend | - Select-Xml -XPath '//un:settings[@pass = "specialize"]/un:component[@name = "Microsoft-Windows-Shell-Setup"]' -Namespace $ns | - Select-Object -ExpandProperty Node - -$productKeyNode = $setupNode | - Select-Xml -XPath '//un:ProductKey' -Namespace $ns | - Select-Object -ExpandProperty Node - -if ($productKeyNode -eq $null) { - $productKeyNode = $unattend.CreateElement('ProductKey', $ns.un) - [Void]$setupNode.AppendChild($productKeyNode) -} - -$productKeyNode.InnerText = $productKey - -$unattend.Save($path) -` - - var ps PowerShellCmd - err := ps.Run(script, path, productKey) - return err -} diff --git a/builder/hyperv/common/powershell/powershell_test.go b/builder/hyperv/common/powershell/powershell_test.go deleted file mode 100644 index 91c9a83f8..000000000 --- a/builder/hyperv/common/powershell/powershell_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package powershell - -import ( - "bytes" - "testing" -) - -func TestOutput(t *testing.T) { - - var ps PowerShellCmd - - powershellAvailable, _, _ := IsPowershellAvailable() - - if !powershellAvailable { - t.Skipf("powershell not installed") - return - } - - cmdOut, err := ps.Output("") - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if cmdOut != "" { - t.Fatalf("output '%v' is not ''", cmdOut) - } - - trueOutput, err := ps.Output("$True") - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if trueOutput != "True" { - t.Fatalf("output '%v' is not 'True'", trueOutput) - } - - falseOutput, err := ps.Output("$False") - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if falseOutput != "False" { - t.Fatalf("output '%v' is not 'False'", falseOutput) - } -} - -func TestRunFile(t *testing.T) { - var ps PowerShellCmd - - powershellAvailable, _, _ := IsPowershellAvailable() - - if !powershellAvailable { - t.Skipf("powershell not installed") - return - } - - var blockBuffer bytes.Buffer - blockBuffer.WriteString(`param([string]$a, [string]$b, [int]$x, [int]$y) if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $n = $x + $y; Write-Output "$a $b $n";`) - - cmdOut, err := ps.Output(blockBuffer.String(), "a", "b", "5", "10") - - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if cmdOut != "a b 15" { - t.Fatalf("output '%v' is not 'a b 15'", cmdOut) - } -} diff --git a/builder/hyperv/common/powershell/scriptbuilder.go b/builder/hyperv/common/powershell/scriptbuilder.go deleted file mode 100644 index 84f454bc7..000000000 --- a/builder/hyperv/common/powershell/scriptbuilder.go +++ /dev/null @@ -1,29 +0,0 @@ -package powershell - -import ( - "bytes" -) - -type ScriptBuilder struct { - buffer bytes.Buffer -} - -func (b *ScriptBuilder) WriteLine(s string) (n int, err error) { - n, err = b.buffer.WriteString(s) - b.buffer.WriteString("\n") - - return n + 1, err -} - -func (b *ScriptBuilder) WriteString(s string) (n int, err error) { - n, err = b.buffer.WriteString(s) - return n, err -} - -func (b *ScriptBuilder) String() string { - return b.buffer.String() -} - -func (b *ScriptBuilder) Reset() { - b.buffer.Reset() -} diff --git a/builder/hyperv/common/ssh.go b/builder/hyperv/common/ssh.go deleted file mode 100644 index 2844f2802..000000000 --- a/builder/hyperv/common/ssh.go +++ /dev/null @@ -1,33 +0,0 @@ -package common - -import ( - "log" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func CommHost(host string) func(multistep.StateBag) (string, error) { - return func(state multistep.StateBag) (string, error) { - - // Skip IP auto detection if the configuration has an ssh host configured. - if host != "" { - log.Printf("Using host value: %s", host) - return host, nil - } - - vmName := state.Get("vmName").(string) - driver := state.Get("driver").(Driver) - - mac, err := driver.Mac(vmName) - if err != nil { - return "", err - } - - ip, err := driver.IpAddress(mac) - if err != nil { - return "", err - } - - return ip, nil - } -} diff --git a/builder/hyperv/common/ssh_config.go b/builder/hyperv/common/ssh_config.go deleted file mode 100644 index 56f6cf637..000000000 --- a/builder/hyperv/common/ssh_config.go +++ /dev/null @@ -1,14 +0,0 @@ -package common - -import ( - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -type SSHConfig struct { - Comm communicator.Config `mapstructure:",squash"` -} - -func (c *SSHConfig) Prepare(ctx *interpolate.Context) []error { - return c.Comm.Prepare(ctx) -} diff --git a/builder/hyperv/common/step_clone_vm.go b/builder/hyperv/common/step_clone_vm.go deleted file mode 100644 index 8ec609100..000000000 --- a/builder/hyperv/common/step_clone_vm.go +++ /dev/null @@ -1,183 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "path/filepath" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -// This step clones an existing virtual machine. -// -// Produces: -// VMName string - The name of the VM -type StepCloneVM struct { - CloneFromVMCXPath string - CloneFromVMName string - CloneFromSnapshotName string - CloneAllSnapshots bool - VMName string - SwitchName string - CompareCopy bool - RamSize uint - Cpu uint - EnableMacSpoofing bool - EnableDynamicMemory bool - EnableSecureBoot bool - SecureBootTemplate string - EnableVirtualizationExtensions bool - MacAddress string - KeepRegistered bool - AdditionalDiskSize []uint - DiskBlockSize uint -} - -func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - ui.Say("Cloning virtual machine...") - - path := state.Get("build_dir").(string) - - // Determine if we even have an existing virtual harddrive to attach - harddrivePath := "" - if harddrivePathRaw, ok := state.GetOk("iso_path"); ok { - extension := strings.ToLower(filepath.Ext(harddrivePathRaw.(string))) - if extension == ".vhd" || extension == ".vhdx" { - harddrivePath = harddrivePathRaw.(string) - } else { - log.Println("No existing virtual harddrive, not attaching.") - } - } else { - log.Println("No existing virtual harddrive, not attaching.") - } - - // convert the MB to bytes - ramSize := int64(s.RamSize * 1024 * 1024) - - err := driver.CloneVirtualMachine(s.CloneFromVMCXPath, s.CloneFromVMName, - s.CloneFromSnapshotName, s.CloneAllSnapshots, s.VMName, path, - harddrivePath, ramSize, s.SwitchName, s.CompareCopy) - if err != nil { - err := fmt.Errorf("Error cloning virtual machine: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - err = driver.SetVirtualMachineCpuCount(s.VMName, s.Cpu) - if err != nil { - err := fmt.Errorf("Error creating setting virtual machine cpu: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if s.EnableDynamicMemory { - err = driver.SetVirtualMachineDynamicMemory(s.VMName, s.EnableDynamicMemory) - if err != nil { - err := fmt.Errorf("Error creating setting virtual machine dynamic memory: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - if s.EnableMacSpoofing { - err = driver.SetVirtualMachineMacSpoofing(s.VMName, s.EnableMacSpoofing) - if err != nil { - err := fmt.Errorf("Error creating setting virtual machine mac spoofing: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - generation, err := driver.GetVirtualMachineGeneration(s.VMName) - if err != nil { - err := fmt.Errorf("Error detecting vm generation: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if generation == 2 { - - err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot, s.SecureBootTemplate) - if err != nil { - err := fmt.Errorf("Error setting secure boot: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - if s.EnableVirtualizationExtensions { - //This is only supported on Windows 10 and Windows Server 2016 onwards - err = driver.SetVirtualMachineVirtualizationExtensions(s.VMName, s.EnableVirtualizationExtensions) - if err != nil { - err := fmt.Errorf("Error creating setting virtual machine virtualization extensions: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - if len(s.AdditionalDiskSize) > 0 { - for index, size := range s.AdditionalDiskSize { - diskSize := int64(size * 1024 * 1024) - diskFile := fmt.Sprintf("%s-%d.vhdx", s.VMName, index) - diskBlockSize := int64(s.DiskBlockSize) * 1024 * 1024 - err = driver.AddVirtualMachineHardDrive(s.VMName, path, diskFile, diskSize, diskBlockSize, "SCSI") - if err != nil { - err := fmt.Errorf("Error creating and attaching additional disk drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - } - - if s.MacAddress != "" { - err = driver.SetVmNetworkAdapterMacAddress(s.VMName, s.MacAddress) - if err != nil { - err := fmt.Errorf("Error setting MAC address: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - // Set the final name in the state bag so others can use it - state.Put("vmName", s.VMName) - // instance_id is the generic term used so that users can have access to the - // instance id inside of the provisioners, used in step_provision. - state.Put("instance_id", s.VMName) - - return multistep.ActionContinue -} - -func (s *StepCloneVM) Cleanup(state multistep.StateBag) { - if s.VMName == "" { - return - } - - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - if s.KeepRegistered { - ui.Say("keep_registered set. Skipping unregister/deletion of VM.") - return - } - - ui.Say("Unregistering and deleting virtual machine...") - - err := driver.DeleteVirtualMachine(s.VMName) - if err != nil { - ui.Error(fmt.Sprintf("Error deleting virtual machine: %s", err)) - } -} diff --git a/builder/hyperv/common/step_collate_artifacts.go b/builder/hyperv/common/step_collate_artifacts.go deleted file mode 100644 index de95fe3af..000000000 --- a/builder/hyperv/common/step_collate_artifacts.go +++ /dev/null @@ -1,69 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepCollateArtifacts struct { - OutputDir string - SkipExport bool -} - -// Runs the step required to collate all build artifacts under the -// specified output directory -func (s *StepCollateArtifacts) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - ui.Say("Collating build artifacts...") - - if s.SkipExport { - // Get the path to the main build directory from the statebag - var buildDir string - if v, ok := state.GetOk("build_dir"); ok { - buildDir = v.(string) - } - // If the user has chosen to skip a full export of the VM the only - // artifacts that they are interested in will be the VHDs. The - // called function searches for all disks under the given source - // directory and moves them to a 'Virtual Hard Disks' folder under - // the destination directory - err := driver.MoveCreatedVHDsToOutputDir(buildDir, s.OutputDir) - if err != nil { - err = fmt.Errorf("Error moving VHDs from build dir to output dir: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } else { - // Get the full path to the export directory from the statebag - var exportPath string - if v, ok := state.GetOk("export_path"); ok { - exportPath = v.(string) - } - // The export process exports the VM into a folder named 'vm name' - // under the output directory. However, to maintain backwards - // compatibility, we now need to shuffle around the exported folders - // so the 'Snapshots', 'Virtual Hard Disks' and 'Virtual Machines' - // directories appear *directly* under . - // The empty '/' directory is removed - // when complete. - // The 'Snapshots' folder will not be moved into the output - // directory if it is empty. - err := driver.PreserveLegacyExportBehaviour(exportPath, s.OutputDir) - if err != nil { - // No need to halt here; Just warn the user instead - err = fmt.Errorf("WARNING: Error restoring legacy export dir structure: %s", err) - ui.Error(err.Error()) - } - } - - return multistep.ActionContinue -} - -// Cleanup does nothing -func (s *StepCollateArtifacts) Cleanup(state multistep.StateBag) {} diff --git a/builder/hyperv/common/step_collate_artifacts_test.go b/builder/hyperv/common/step_collate_artifacts_test.go deleted file mode 100644 index 9ca5cde1c..000000000 --- a/builder/hyperv/common/step_collate_artifacts_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package common - -import ( - "context" - "path/filepath" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepCollateArtifacts_impl(t *testing.T) { - var _ multistep.Step = new(StepCollateArtifacts) -} - -func TestStepCollateArtifacts_exportedArtifacts(t *testing.T) { - state := testState(t) - step := new(StepCollateArtifacts) - - step.OutputDir = "foopath" - vmName := "foo" - - // Uses export path from the state bag - exportPath := filepath.Join(step.OutputDir, vmName) - state.Put("export_path", exportPath) - - driver := state.Get("driver").(*DriverMock) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatal("Should NOT have error") - } - - // Test the driver - if !driver.PreserveLegacyExportBehaviour_Called { - t.Fatal("Should have called PreserveLegacyExportBehaviour") - } - if driver.PreserveLegacyExportBehaviour_SrcPath != exportPath { - t.Fatalf("Should call with correct srcPath. Got: %s Wanted: %s", - driver.PreserveLegacyExportBehaviour_SrcPath, exportPath) - } - if driver.PreserveLegacyExportBehaviour_DstPath != step.OutputDir { - t.Fatalf("Should call with correct dstPath. Got: %s Wanted: %s", - driver.PreserveLegacyExportBehaviour_DstPath, step.OutputDir) - } - - // Should only be called when skip_export is true - if driver.MoveCreatedVHDsToOutputDir_Called { - t.Fatal("Should NOT have called MoveCreatedVHDsToOutputDir") - } -} - -func TestStepCollateArtifacts_skipExportArtifacts(t *testing.T) { - state := testState(t) - step := new(StepCollateArtifacts) - - // Needs the path to the main output directory and build directory - step.OutputDir = "foopath" - buildDir := "fooBuildPath" - state.Put("build_dir", buildDir) - // Export has been skipped - step.SkipExport = true - - driver := state.Get("driver").(*DriverMock) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatal("Should NOT have error") - } - - // Test the driver - if !driver.MoveCreatedVHDsToOutputDir_Called { - t.Fatal("Should have called MoveCreatedVHDsToOutputDir") - } - if driver.MoveCreatedVHDsToOutputDir_SrcPath != buildDir { - t.Fatalf("Should call with correct srcPath. Got: %s Wanted: %s", - driver.MoveCreatedVHDsToOutputDir_SrcPath, buildDir) - } - if driver.MoveCreatedVHDsToOutputDir_DstPath != step.OutputDir { - t.Fatalf("Should call with correct dstPath. Got: %s Wanted: %s", - driver.MoveCreatedVHDsToOutputDir_DstPath, step.OutputDir) - } - - if driver.PreserveLegacyExportBehaviour_Called { - t.Fatal("Should NOT have called PreserveLegacyExportBehaviour") - } -} diff --git a/builder/hyperv/common/step_compact_disk.go b/builder/hyperv/common/step_compact_disk.go deleted file mode 100644 index 36c3f8f40..000000000 --- a/builder/hyperv/common/step_compact_disk.go +++ /dev/null @@ -1,50 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepCompactDisk struct { - SkipCompaction bool -} - -// Run runs a compaction/optimisation process on attached VHD/VHDX disks -func (s *StepCompactDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - if s.SkipCompaction { - ui.Say("Skipping disk compaction...") - return multistep.ActionContinue - } - - // Get the dir used to store the VMs files during the build process - var buildDir string - if v, ok := state.GetOk("build_dir"); ok { - buildDir = v.(string) - } - - ui.Say("Compacting disks...") - // CompactDisks searches for all VHD/VHDX files under the supplied - // path and runs the compacting process on each of them. If no disks - // are found under the supplied path this is treated as a 'soft' error - // and a warning message is printed. All other errors halt the build. - result, err := driver.CompactDisks(buildDir) - if err != nil { - err := fmt.Errorf("Error compacting disks: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - // Report disk compaction results/warn if no disks were found - ui.Message(result) - - return multistep.ActionContinue -} - -// Cleanup does nothing -func (s *StepCompactDisk) Cleanup(state multistep.StateBag) {} diff --git a/builder/hyperv/common/step_compact_disk_test.go b/builder/hyperv/common/step_compact_disk_test.go deleted file mode 100644 index 0e83e5940..000000000 --- a/builder/hyperv/common/step_compact_disk_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package common - -import ( - "context" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepCompactDisk_impl(t *testing.T) { - var _ multistep.Step = new(StepCompactDisk) -} - -func TestStepCompactDisk(t *testing.T) { - state := testState(t) - step := new(StepCompactDisk) - - // Set up the path to the build directory - buildDir := "foopath" - state.Put("build_dir", buildDir) - - driver := state.Get("driver").(*DriverMock) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatal("Should NOT have error") - } - - // Test the driver - if !driver.CompactDisks_Called { - t.Fatal("Should have called CompactDisks") - } - if driver.CompactDisks_Path != buildDir { - t.Fatalf("Should call with correct path. Got: %s Wanted: %s", driver.CompactDisks_Path, buildDir) - } -} - -func TestStepCompactDisk_skip(t *testing.T) { - state := testState(t) - step := new(StepCompactDisk) - step.SkipCompaction = true - - // Set up the path to the build directory - state.Put("build_dir", "foopath") - - driver := state.Get("driver").(*DriverMock) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatalf("Should NOT have error") - } - - // Test the driver - if driver.CompactDisks_Called { - t.Fatal("Should NOT have called CompactDisks") - } -} diff --git a/builder/hyperv/common/step_configure_ip.go b/builder/hyperv/common/step_configure_ip.go deleted file mode 100644 index 7126e144a..000000000 --- a/builder/hyperv/common/step_configure_ip.go +++ /dev/null @@ -1,77 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "strings" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepConfigureIp struct { -} - -func (s *StepConfigureIp) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - errorMsg := "Error configuring ip address: %s" - vmName := state.Get("vmName").(string) - - ui.Say("Configuring ip address...") - - count := 60 - var duration time.Duration = 1 - sleepTime := time.Minute * duration - var ip string - - for count != 0 { - cmdOut, err := driver.GetVirtualMachineNetworkAdapterAddress(vmName) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ip = strings.TrimSpace(cmdOut) - - if ip != "False" { - break - } - - log.Println(fmt.Sprintf("Waiting for another %v minutes...", uint(duration))) - time.Sleep(sleepTime) - count-- - } - - if count == 0 { - err := fmt.Errorf(errorMsg, "IP address assigned to the adapter is empty") - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("ip address is " + ip) - - hostName, err := driver.GetHostName(ip) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("hostname is " + hostName) - - state.Put("ip", ip) - state.Put("hostname", hostName) - - return multistep.ActionContinue -} - -func (s *StepConfigureIp) Cleanup(state multistep.StateBag) { - // do nothing -} diff --git a/builder/hyperv/common/step_configure_vlan.go b/builder/hyperv/common/step_configure_vlan.go deleted file mode 100644 index 6f72f8883..000000000 --- a/builder/hyperv/common/step_configure_vlan.go +++ /dev/null @@ -1,53 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepConfigureVlan struct { - VlanId string - SwitchVlanId string -} - -func (s *StepConfigureVlan) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - errorMsg := "Error configuring vlan: %s" - vmName := state.Get("vmName").(string) - switchName := state.Get("SwitchName").(string) - vlanId := s.VlanId - switchVlanId := s.SwitchVlanId - - ui.Say("Configuring vlan...") - - if switchVlanId != "" { - err := driver.SetNetworkAdapterVlanId(switchName, vlanId) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - if vlanId != "" { - err := driver.SetVirtualMachineVlanId(vmName, vlanId) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepConfigureVlan) Cleanup(state multistep.StateBag) { - //do nothing -} diff --git a/builder/hyperv/common/step_create_build_dir.go b/builder/hyperv/common/step_create_build_dir.go deleted file mode 100644 index 2f77e5bfd..000000000 --- a/builder/hyperv/common/step_create_build_dir.go +++ /dev/null @@ -1,68 +0,0 @@ -package common - -import ( - "context" - "fmt" - "io/ioutil" - "log" - "os" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/tmp" -) - -type StepCreateBuildDir struct { - // User supplied directory under which we create the main build - // directory. The build directory is used to house the VM files and - // folders during the build. If unspecified the default temp directory - // for the OS is used - TempPath string - // The full path to the build directory. This is the concatenation of - // TempPath plus a directory uniquely named for the build - buildDir string -} - -// Creates the main directory used to house the VMs files and folders -// during the build -func (s *StepCreateBuildDir) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - - ui.Say("Creating build directory...") - - var err error - if s.TempPath == "" { - s.buildDir, err = tmp.Dir("hyperv") - } else { - s.buildDir, err = ioutil.TempDir(s.TempPath, "hyperv") - } - - if err != nil { - err = fmt.Errorf("Error creating build directory: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - log.Printf("Created build directory: %s", s.buildDir) - - // Record the build directory location for later steps - state.Put("build_dir", s.buildDir) - - return multistep.ActionContinue -} - -// Cleanup removes the build directory -func (s *StepCreateBuildDir) Cleanup(state multistep.StateBag) { - if s.buildDir == "" { - return - } - - ui := state.Get("ui").(packersdk.Ui) - ui.Say("Deleting build directory...") - - err := os.RemoveAll(s.buildDir) - if err != nil { - ui.Error(fmt.Sprintf("Error deleting build directory: %s", err)) - } -} diff --git a/builder/hyperv/common/step_create_build_dir_test.go b/builder/hyperv/common/step_create_build_dir_test.go deleted file mode 100644 index f7f87eb32..000000000 --- a/builder/hyperv/common/step_create_build_dir_test.go +++ /dev/null @@ -1,113 +0,0 @@ -package common - -import ( - "context" - "os" - "path/filepath" - "regexp" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepCreateBuildDir_imp(t *testing.T) { - var _ multistep.Step = new(StepCreateBuildDir) -} - -func TestStepCreateBuildDir_Defaults(t *testing.T) { - state := testState(t) - step := new(StepCreateBuildDir) - - // Default is for the user not to supply value for TempPath. When - // nothing is set the step should use the OS temp directory as the root - // for the build directory - step.TempPath = "" - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatal("Should NOT have error") - } - - if v, ok := state.GetOk("build_dir"); !ok { - t.Fatal("Should store path to build directory in statebag as 'build_dir'") - } else { - // On windows convert everything to forward slash separated paths - // This prevents the regexp interpreting backslashes as escape sequences - stateBuildDir := filepath.ToSlash(v.(string)) - expectedBuildDirRe := regexp.MustCompile( - filepath.ToSlash(filepath.Join(os.TempDir(), "hyperv") + `[[:digit:]]{9}$`)) - match := expectedBuildDirRe.MatchString(stateBuildDir) - if !match { - t.Fatalf("Got path that doesn't match expected format in 'build_dir': %s", stateBuildDir) - } - } - - // Test Cleanup - step.Cleanup(state) - if _, err := os.Stat(step.buildDir); err == nil { - t.Fatalf("Build directory should NOT exist after Cleanup: %s", step.buildDir) - } -} - -func TestStepCreateBuildDir_UserDefinedTempPath(t *testing.T) { - state := testState(t) - step := new(StepCreateBuildDir) - - // Create a directory we'll use as the user supplied temp_path - step.TempPath = genTestDirPath("userTempDir") - err := os.Mkdir(step.TempPath, 0755) // The directory must exist - if err != nil { - t.Fatal("Error creating test directory") - } - defer os.RemoveAll(step.TempPath) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatal("Should NOT have error") - } - - if v, ok := state.GetOk("build_dir"); !ok { - t.Fatal("Should store path to build directory in statebag as 'build_dir'") - } else { - // On windows convert everything to forward slash separated paths - // This prevents the regexp interpreting backslashes as escape sequences - stateBuildDir := filepath.ToSlash(v.(string)) - expectedBuildDirRe := regexp.MustCompile( - filepath.ToSlash(filepath.Join(step.TempPath, "hyperv") + `[[:digit:]]{9}$`)) - match := expectedBuildDirRe.MatchString(stateBuildDir) - if !match { - t.Fatalf("Got path that doesn't match expected format in 'build_dir': %s", stateBuildDir) - } - } - - // Test Cleanup - step.Cleanup(state) - if _, err := os.Stat(step.buildDir); err == nil { - t.Fatalf("Build directory should NOT exist after Cleanup: %s", step.buildDir) - } - if _, err := os.Stat(step.TempPath); err != nil { - t.Fatal("User supplied root for build directory should NOT be deleted by Cleanup") - } -} - -func TestStepCreateBuildDir_BadTempPath(t *testing.T) { - state := testState(t) - step := new(StepCreateBuildDir) - - // Bad - step.TempPath = genTestDirPath("iDontExist") - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionHalt { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); !ok { - t.Fatal("Should have error due to bad path") - } -} diff --git a/builder/hyperv/common/step_create_external_switch.go b/builder/hyperv/common/step_create_external_switch.go deleted file mode 100644 index 2976a13bc..000000000 --- a/builder/hyperv/common/step_create_external_switch.go +++ /dev/null @@ -1,107 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/uuid" -) - -// This step creates an external switch for the VM. -// -// Produces: -// SwitchName string - The name of the Switch -type StepCreateExternalSwitch struct { - SwitchName string - oldSwitchName string -} - -// Run runs the step required to create an external switch. Depending on -// the connectivity of the host machine, the external switch will allow the -// build VM to connect to the outside world. -func (s *StepCreateExternalSwitch) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - vmName := state.Get("vmName").(string) - errorMsg := "Error creating external switch: %s" - var err error - - ui.Say("Creating external switch...") - - packerExternalSwitchName := "paes_" + uuid.TimeOrderedUUID() - - // CreateExternalVirtualSwitch checks for an existing external switch, - // creating one if required, and connects the VM to it - err = driver.CreateExternalVirtualSwitch(vmName, packerExternalSwitchName) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - s.SwitchName = "" - return multistep.ActionHalt - } - - switchName, err := driver.GetVirtualMachineSwitchName(vmName) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if len(switchName) == 0 { - err := fmt.Errorf(errorMsg, err) - state.Put("error", "Can't get the VM switch name") - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("External switch name is: '" + switchName + "'") - - if switchName != packerExternalSwitchName { - s.SwitchName = "" - } else { - s.SwitchName = packerExternalSwitchName - s.oldSwitchName = state.Get("SwitchName").(string) - } - - // Set the final name in the state bag so others can use it - state.Put("SwitchName", switchName) - - return multistep.ActionContinue -} - -func (s *StepCreateExternalSwitch) Cleanup(state multistep.StateBag) { - if s.SwitchName == "" { - return - } - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - ui.Say("Unregistering and deleting external switch...") - - errMsg := "Error deleting external switch: %s" - - // connect the vm to the old switch - if s.oldSwitchName == "" { - ui.Error(fmt.Sprintf(errMsg, "the old switch name is empty")) - return - } - - err := driver.ConnectVirtualMachineNetworkAdapterToSwitch(vmName, s.oldSwitchName) - if err != nil { - ui.Error(fmt.Sprintf(errMsg, err)) - return - } - - state.Put("SwitchName", s.oldSwitchName) - - err = driver.DeleteVirtualSwitch(s.SwitchName) - if err != nil { - ui.Error(fmt.Sprintf(errMsg, err)) - } -} diff --git a/builder/hyperv/common/step_create_switch.go b/builder/hyperv/common/step_create_switch.go deleted file mode 100644 index 6f2eb2d00..000000000 --- a/builder/hyperv/common/step_create_switch.go +++ /dev/null @@ -1,80 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -const ( - SwitchTypeInternal = "Internal" - SwitchTypePrivate = "Private" - DefaultSwitchType = SwitchTypeInternal -) - -// This step creates switch for VM. -// -// Produces: -// SwitchName string - The name of the Switch -type StepCreateSwitch struct { - // Specifies the name of the switch to be created. - SwitchName string - // Specifies the type of the switch to be created. Allowed values are Internal and Private. To create an External - // virtual switch, specify either the NetAdapterInterfaceDescription or the NetAdapterName parameter, which - // implicitly set the type of the virtual switch to External. - SwitchType string - // Specifies the name of the network adapter to be bound to the switch to be created. - NetAdapterName string - // Specifies the interface description of the network adapter to be bound to the switch to be created. - NetAdapterInterfaceDescription string - - createdSwitch bool -} - -func (s *StepCreateSwitch) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - if len(s.SwitchType) == 0 { - s.SwitchType = DefaultSwitchType - } - - ui.Say(fmt.Sprintf("Creating switch '%v' if required...", s.SwitchName)) - - createdSwitch, err := driver.CreateVirtualSwitch(s.SwitchName, s.SwitchType) - if err != nil { - err := fmt.Errorf("Error creating switch: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - s.SwitchName = "" - return multistep.ActionHalt - } - - s.createdSwitch = createdSwitch - - if !s.createdSwitch { - ui.Say(fmt.Sprintf(" switch '%v' already exists. Will not delete on cleanup...", s.SwitchName)) - } - - // Set the final name in the state bag so others can use it - state.Put("SwitchName", s.SwitchName) - - return multistep.ActionContinue -} - -func (s *StepCreateSwitch) Cleanup(state multistep.StateBag) { - if len(s.SwitchName) == 0 || !s.createdSwitch { - return - } - - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - ui.Say("Unregistering and deleting switch...") - - err := driver.DeleteVirtualSwitch(s.SwitchName) - if err != nil { - ui.Error(fmt.Sprintf("Error deleting switch: %s", err)) - } -} diff --git a/builder/hyperv/common/step_create_vm.go b/builder/hyperv/common/step_create_vm.go deleted file mode 100644 index f95bbbe47..000000000 --- a/builder/hyperv/common/step_create_vm.go +++ /dev/null @@ -1,197 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "path/filepath" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -// This step creates the actual virtual machine. -// -// Produces: -// VMName string - The name of the VM -type StepCreateVM struct { - VMName string - SwitchName string - HarddrivePath string - RamSize uint - DiskSize uint - DiskBlockSize uint - UseLegacyNetworkAdapter bool - Generation uint - Cpu uint - EnableMacSpoofing bool - EnableDynamicMemory bool - EnableSecureBoot bool - SecureBootTemplate string - EnableVirtualizationExtensions bool - AdditionalDiskSize []uint - DifferencingDisk bool - MacAddress string - FixedVHD bool - Version string - KeepRegistered bool -} - -func (s *StepCreateVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - ui.Say("Creating virtual machine...") - - var path string - if v, ok := state.GetOk("build_dir"); ok { - path = v.(string) - } - - err := driver.CheckVMName(s.VMName) - if err != nil { - s.KeepRegistered = true - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // Determine if we even have an existing virtual harddrive to attach - harddrivePath := "" - if harddrivePathRaw, ok := state.GetOk("iso_path"); ok { - extension := strings.ToLower(filepath.Ext(harddrivePathRaw.(string))) - if extension == ".vhd" || extension == ".vhdx" { - harddrivePath = harddrivePathRaw.(string) - } else { - log.Println("No existing virtual harddrive, not attaching.") - } - } else { - log.Println("No existing virtual harddrive, not attaching.") - } - - // convert the MB to bytes - ramSize := int64(s.RamSize) * 1024 * 1024 - diskSize := int64(s.DiskSize) * 1024 * 1024 - diskBlockSize := int64(s.DiskBlockSize) * 1024 * 1024 - - err = driver.CreateVirtualMachine(s.VMName, path, harddrivePath, ramSize, diskSize, diskBlockSize, - s.SwitchName, s.Generation, s.DifferencingDisk, s.FixedVHD, s.Version) - if err != nil { - err := fmt.Errorf("Error creating virtual machine: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if s.UseLegacyNetworkAdapter { - err := driver.ReplaceVirtualMachineNetworkAdapter(s.VMName, true) - if err != nil { - err := fmt.Errorf("Error creating legacy network adapter: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - err = driver.SetVirtualMachineCpuCount(s.VMName, s.Cpu) - if err != nil { - err := fmt.Errorf("Error setting virtual machine cpu count: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - err = driver.SetVirtualMachineDynamicMemory(s.VMName, s.EnableDynamicMemory) - if err != nil { - err := fmt.Errorf("Error setting virtual machine dynamic memory: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if s.EnableMacSpoofing { - err = driver.SetVirtualMachineMacSpoofing(s.VMName, s.EnableMacSpoofing) - if err != nil { - err := fmt.Errorf("Error setting virtual machine mac spoofing: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - if s.Generation == 2 { - err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot, s.SecureBootTemplate) - if err != nil { - err := fmt.Errorf("Error setting secure boot: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - if s.EnableVirtualizationExtensions { - //This is only supported on Windows 10 and Windows Server 2016 onwards - err = driver.SetVirtualMachineVirtualizationExtensions(s.VMName, s.EnableVirtualizationExtensions) - if err != nil { - err := fmt.Errorf("Error setting virtual machine virtualization extensions: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - if len(s.AdditionalDiskSize) > 0 { - for index, size := range s.AdditionalDiskSize { - diskSize := int64(size * 1024 * 1024) - diskFile := fmt.Sprintf("%s-%d.vhdx", s.VMName, index) - err = driver.AddVirtualMachineHardDrive(s.VMName, path, diskFile, diskSize, diskBlockSize, "SCSI") - if err != nil { - err := fmt.Errorf("Error creating and attaching additional disk drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - } - - if s.MacAddress != "" { - err = driver.SetVmNetworkAdapterMacAddress(s.VMName, s.MacAddress) - if err != nil { - err := fmt.Errorf("Error setting MAC address: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - // Set the final name in the state bag so others can use it - state.Put("vmName", s.VMName) - // instance_id is the generic term used so that users can have access to the - // instance id inside of the provisioners, used in step_provision. - state.Put("instance_id", s.VMName) - - return multistep.ActionContinue -} - -func (s *StepCreateVM) Cleanup(state multistep.StateBag) { - if s.VMName == "" { - return - } - - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - if s.KeepRegistered { - ui.Say("keep_registered set. Skipping unregister/deletion of VM.") - return - } - - ui.Say("Unregistering and deleting virtual machine...") - - err := driver.DeleteVirtualMachine(s.VMName) - if err != nil { - ui.Error(fmt.Sprintf("Error deleting virtual machine: %s", err)) - } - - // TODO: Clean up created VHDX -} diff --git a/builder/hyperv/common/step_create_vm_test.go b/builder/hyperv/common/step_create_vm_test.go deleted file mode 100644 index c36c5fe07..000000000 --- a/builder/hyperv/common/step_create_vm_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package common - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepCreateVM_impl(t *testing.T) { - var _ multistep.Step = new(StepCreateVM) -} - -func TestStepCreateVM(t *testing.T) { - state := testState(t) - step := new(StepCreateVM) - - step.VMName = "test-VM-Name" - driver := state.Get("driver").(*DriverMock) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatal("Should NOT have error") - } - - // Test the driver - if !driver.CheckVMName_Called { - t.Fatal("Should have called CheckVMName") - } -} - -func TestStepCreateVM_CheckVMNameErr(t *testing.T) { - state := testState(t) - step := new(StepCreateVM) - - step.VMName = "test-VM-Name" - driver := state.Get("driver").(*DriverMock) - driver.CheckVMName_Err = fmt.Errorf("A virtual machine with the name is already" + - " defined in Hyper-V. To avoid a name collision, please set your " + - "vm_name to a unique value") - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionHalt { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); !ok { - t.Fatal("Should have error") - } - - // Test the driver - if !driver.CheckVMName_Called { - t.Fatal("Should have called CheckVMName") - } -} diff --git a/builder/hyperv/common/step_disable_vlan.go b/builder/hyperv/common/step_disable_vlan.go deleted file mode 100644 index 4bd499d3c..000000000 --- a/builder/hyperv/common/step_disable_vlan.go +++ /dev/null @@ -1,37 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepDisableVlan struct { -} - -func (s *StepDisableVlan) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - errorMsg := "Error disabling vlan: %s" - vmName := state.Get("vmName").(string) - switchName := state.Get("SwitchName").(string) - - ui.Say("Disabling vlan...") - - err := driver.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *StepDisableVlan) Cleanup(state multistep.StateBag) { - //do nothing -} diff --git a/builder/hyperv/common/step_enable_integration_service.go b/builder/hyperv/common/step_enable_integration_service.go deleted file mode 100644 index b62059502..000000000 --- a/builder/hyperv/common/step_enable_integration_service.go +++ /dev/null @@ -1,37 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepEnableIntegrationService struct { - name string -} - -func (s *StepEnableIntegrationService) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - ui.Say("Enabling Integration Service...") - - vmName := state.Get("vmName").(string) - s.name = "Guest Service Interface" - - err := driver.EnableVirtualMachineIntegrationService(vmName, s.name) - - if err != nil { - err := fmt.Errorf("Error enabling Integration Service: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *StepEnableIntegrationService) Cleanup(state multistep.StateBag) { - // do nothing -} diff --git a/builder/hyperv/common/step_export_vm.go b/builder/hyperv/common/step_export_vm.go deleted file mode 100644 index 099120b12..000000000 --- a/builder/hyperv/common/step_export_vm.go +++ /dev/null @@ -1,54 +0,0 @@ -package common - -import ( - "context" - "fmt" - "path/filepath" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepExportVm struct { - OutputDir string - SkipExport bool -} - -func (s *StepExportVm) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - if s.SkipExport { - ui.Say("Skipping export of virtual machine...") - return multistep.ActionContinue - } - - ui.Say("Exporting virtual machine...") - - // The VM name is needed for the export command - var vmName string - if v, ok := state.GetOk("vmName"); ok { - vmName = v.(string) - } - - // The export process exports the VM to a folder named 'vmName' under - // the output directory. This contains the usual 'Snapshots', 'Virtual - // Hard Disks' and 'Virtual Machines' directories. - err := driver.ExportVirtualMachine(vmName, s.OutputDir) - if err != nil { - err = fmt.Errorf("Error exporting vm: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // Store the path to the export directory for later steps - exportPath := filepath.Join(s.OutputDir, vmName) - state.Put("export_path", exportPath) - - return multistep.ActionContinue -} - -func (s *StepExportVm) Cleanup(state multistep.StateBag) { - // do nothing -} diff --git a/builder/hyperv/common/step_export_vm_test.go b/builder/hyperv/common/step_export_vm_test.go deleted file mode 100644 index 575a6d313..000000000 --- a/builder/hyperv/common/step_export_vm_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package common - -import ( - "context" - "path/filepath" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -func TestStepExportVm_impl(t *testing.T) { - var _ multistep.Step = new(StepExportVm) -} - -func TestStepExportVm(t *testing.T) { - state := testState(t) - step := new(StepExportVm) - - // ExportVirtualMachine needs the VM name and a path to export to - vmName := "foo" - state.Put("vmName", vmName) - outputDir := "foopath" - step.OutputDir = outputDir - - driver := state.Get("driver").(*DriverMock) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatal("Should NOT have error") - } - - // Test the driver - if !driver.ExportVirtualMachine_Called { - t.Fatal("Should have called ExportVirtualMachine") - } - if driver.ExportVirtualMachine_Path != outputDir { - t.Fatalf("Should call with correct path. Got: %s Wanted: %s", - driver.ExportVirtualMachine_Path, outputDir) - } - if driver.ExportVirtualMachine_VmName != vmName { - t.Fatalf("Should call with correct vm name. Got: %s Wanted: %s", - driver.ExportVirtualMachine_VmName, vmName) - } - - // Test we stored the export path in the statebag and it is correct - expectedPath := filepath.Join(outputDir, vmName) - if exportPath, ok := state.GetOk("export_path"); !ok { - t.Fatal("Should set export_path") - } else if exportPath != expectedPath { - t.Fatalf("Bad path stored for export_path. Got: %#v Wanted: %#v", exportPath, expectedPath) - } -} - -func TestStepExportVm_skip(t *testing.T) { - state := testState(t) - step := new(StepExportVm) - step.SkipExport = true - - // ExportVirtualMachine needs the VM name and a path to export to - vmName := "foo" - state.Put("vmName", vmName) - outputDir := "foopath" - step.OutputDir = outputDir - - driver := state.Get("driver").(*DriverMock) - - // Test the run - if action := step.Run(context.Background(), state); action != multistep.ActionContinue { - t.Fatalf("Bad action: %v", action) - } - if _, ok := state.GetOk("error"); ok { - t.Fatalf("Should NOT have error") - } - - // Test the driver - if driver.ExportVirtualMachine_Called { - t.Fatal("Should NOT have called ExportVirtualMachine") - } - - // Should not store the export path in the statebag - if _, ok := state.GetOk("export_path"); ok { - t.Fatal("Should NOT have stored export_path in the statebag") - } -} diff --git a/builder/hyperv/common/step_mount_dvddrive.go b/builder/hyperv/common/step_mount_dvddrive.go deleted file mode 100644 index 6a8a4587f..000000000 --- a/builder/hyperv/common/step_mount_dvddrive.go +++ /dev/null @@ -1,121 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - "path/filepath" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepMountDvdDrive struct { - Generation uint - FirstBootDevice string -} - -func (s *StepMountDvdDrive) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - errorMsg := "Error mounting dvd drive: %s" - vmName := state.Get("vmName").(string) - - // Determine if we even have a dvd disk to attach - var isoPath string - if isoPathRaw, ok := state.GetOk("iso_path"); ok { - isoPath = isoPathRaw.(string) - } else { - log.Println("No dvd disk, not attaching.") - return multistep.ActionContinue - } - - // Determine if its a virtual hdd to mount - if strings.ToLower(filepath.Ext(isoPath)) == ".vhd" || strings.ToLower(filepath.Ext(isoPath)) == ".vhdx" { - log.Println("Its a hard disk, not attaching.") - return multistep.ActionContinue - } - - // should be able to mount up to 60 additional iso images using SCSI - // but Windows would only allow a max of 22 due to available drive letters - // Will Windows assign DVD drives to A: and B: ? - - // For IDE, there are only 2 controllers (0,1) with 2 locations each (0,1) - - var dvdControllerProperties DvdControllerProperties - controllerNumber, controllerLocation, err := driver.CreateDvdDrive(vmName, isoPath, s.Generation) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - dvdControllerProperties.ControllerNumber = controllerNumber - dvdControllerProperties.ControllerLocation = controllerLocation - dvdControllerProperties.Existing = false - - state.Put("os.dvd.properties", dvdControllerProperties) - - // the "first_boot_device" setting has precedence over the legacy boot order - // configuration, but only if its been assigned a value. - - if s.FirstBootDevice == "" { - - if s.Generation > 1 { - // only print this message for Gen2, it's not a true statement for Gen1 VMs - ui.Say(fmt.Sprintf("Setting boot drive to os dvd drive %s ...", isoPath)) - } - - err = driver.SetBootDvdDrive(vmName, controllerNumber, controllerLocation, s.Generation) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - } - - ui.Say(fmt.Sprintf("Mounting os dvd drive %s ...", isoPath)) - err = driver.MountDvdDrive(vmName, isoPath, controllerNumber, controllerLocation) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (s *StepMountDvdDrive) Cleanup(state multistep.StateBag) { - dvdControllerState := state.Get("os.dvd.properties") - - if dvdControllerState == nil { - return - } - - dvdController := dvdControllerState.(DvdControllerProperties) - driver := state.Get("driver").(Driver) - vmName := state.Get("vmName").(string) - ui := state.Get("ui").(packersdk.Ui) - errorMsg := "Error unmounting os dvd drive: %s" - - ui.Say("Clean up os dvd drive...") - - if dvdController.Existing { - err := driver.UnmountDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error unmounting dvd drive: %s", err) - log.Print(fmt.Sprintf(errorMsg, err)) - } - } else { - err := driver.DeleteDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error deleting dvd drive: %s", err) - log.Print(fmt.Sprintf(errorMsg, err)) - } - } -} diff --git a/builder/hyperv/common/step_mount_floppydrive.go b/builder/hyperv/common/step_mount_floppydrive.go deleted file mode 100644 index 2d5379b16..000000000 --- a/builder/hyperv/common/step_mount_floppydrive.go +++ /dev/null @@ -1,120 +0,0 @@ -package common - -import ( - "context" - "fmt" - "io" - "log" - "os" - "path/filepath" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/tmp" -) - -const ( - FloppyFileName = "assets.vfd" -) - -type StepMountFloppydrive struct { - Generation uint - floppyPath string -} - -func (s *StepMountFloppydrive) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - if s.Generation > 1 { - return multistep.ActionContinue - } - - driver := state.Get("driver").(Driver) - - // Determine if we even have a floppy disk to attach - var floppyPath string - if floppyPathRaw, ok := state.GetOk("floppy_path"); ok { - floppyPath = floppyPathRaw.(string) - } else { - log.Println("No floppy disk, not attaching.") - return multistep.ActionContinue - } - - // Hyper-V is really dumb and can't figure out the format of the file - // without an extension, so we need to add the "vfd" extension to the - // floppy. - floppyPath, err := s.copyFloppy(floppyPath) - if err != nil { - state.Put("error", fmt.Errorf("Error preparing floppy: %s", err)) - return multistep.ActionHalt - } - - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - ui.Say("Mounting floppy drive...") - - err = driver.MountFloppyDrive(vmName, floppyPath) - if err != nil { - state.Put("error", fmt.Errorf("Error mounting floppy drive: %s", err)) - return multistep.ActionHalt - } - - // Track the path so that we can unregister it from Hyper-V later - s.floppyPath = floppyPath - - return multistep.ActionContinue -} - -func (s *StepMountFloppydrive) Cleanup(state multistep.StateBag) { - if s.Generation > 1 { - return - } - driver := state.Get("driver").(Driver) - if s.floppyPath == "" { - return - } - - errorMsg := "Error unmounting floppy drive: %s" - - vmName := state.Get("vmName").(string) - ui := state.Get("ui").(packersdk.Ui) - - ui.Say("Cleanup floppy drive...") - - err := driver.UnmountFloppyDrive(vmName) - if err != nil { - log.Print(fmt.Sprintf(errorMsg, err)) - } - - err = os.Remove(s.floppyPath) - - if err != nil { - log.Print(fmt.Sprintf(errorMsg, err)) - } -} - -func (s *StepMountFloppydrive) copyFloppy(path string) (string, error) { - tempdir, err := tmp.Dir("hyperv") - if err != nil { - return "", err - } - - floppyPath := filepath.Join(tempdir, "floppy.vfd") - f, err := os.Create(floppyPath) - if err != nil { - return "", err - } - defer f.Close() - - sourceF, err := os.Open(path) - if err != nil { - return "", err - } - defer sourceF.Close() - - log.Printf("Copying floppy to temp location: %s", floppyPath) - if _, err := io.Copy(f, sourceF); err != nil { - return "", err - } - - return floppyPath, nil -} diff --git a/builder/hyperv/common/step_mount_guest_additions.go b/builder/hyperv/common/step_mount_guest_additions.go deleted file mode 100644 index 2663521ac..000000000 --- a/builder/hyperv/common/step_mount_guest_additions.go +++ /dev/null @@ -1,95 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepMountGuestAdditions struct { - GuestAdditionsMode string - GuestAdditionsPath string - Generation uint -} - -func (s *StepMountGuestAdditions) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - - if s.GuestAdditionsMode != "attach" { - ui.Say("Skipping mounting Integration Services Setup Disk...") - return multistep.ActionContinue - } - - driver := state.Get("driver").(Driver) - ui.Say("Mounting Integration Services Setup Disk...") - - vmName := state.Get("vmName").(string) - - // should be able to mount up to 60 additional iso images using SCSI - // but Windows would only allow a max of 22 due to available drive letters - // Will Windows assign DVD drives to A: and B: ? - - // For IDE, there are only 2 controllers (0,1) with 2 locations each (0,1) - - var dvdControllerProperties DvdControllerProperties - - controllerNumber, controllerLocation, err := driver.CreateDvdDrive(vmName, s.GuestAdditionsPath, s.Generation) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - dvdControllerProperties.ControllerNumber = controllerNumber - dvdControllerProperties.ControllerLocation = controllerLocation - dvdControllerProperties.Existing = false - state.Put("guest.dvd.properties", dvdControllerProperties) - - ui.Say(fmt.Sprintf("Mounting Integration Services dvd drive %s ...", s.GuestAdditionsPath)) - err = driver.MountDvdDrive(vmName, s.GuestAdditionsPath, controllerNumber, controllerLocation) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - log.Println(fmt.Sprintf("ISO %s mounted on DVD controller %v, location %v", s.GuestAdditionsPath, - controllerNumber, controllerLocation)) - - return multistep.ActionContinue -} - -func (s *StepMountGuestAdditions) Cleanup(state multistep.StateBag) { - if s.GuestAdditionsMode != "attach" { - return - } - - dvdControllerState := state.Get("guest.dvd.properties") - - if dvdControllerState == nil { - return - } - - dvdController := dvdControllerState.(DvdControllerProperties) - ui := state.Get("ui").(packersdk.Ui) - driver := state.Get("driver").(Driver) - vmName := state.Get("vmName").(string) - errorMsg := "Error unmounting Integration Services dvd drive: %s" - - ui.Say("Cleanup Integration Services dvd drive...") - - if dvdController.Existing { - err := driver.UnmountDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - log.Print(fmt.Sprintf(errorMsg, err)) - } - } else { - err := driver.DeleteDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - log.Print(fmt.Sprintf(errorMsg, err)) - } - } -} diff --git a/builder/hyperv/common/step_mount_secondary_dvd_images.go b/builder/hyperv/common/step_mount_secondary_dvd_images.go deleted file mode 100644 index 39a0d9e43..000000000 --- a/builder/hyperv/common/step_mount_secondary_dvd_images.go +++ /dev/null @@ -1,107 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepMountSecondaryDvdImages struct { - IsoPaths []string - Generation uint -} - -type DvdControllerProperties struct { - ControllerNumber uint - ControllerLocation uint - Existing bool -} - -func (s *StepMountSecondaryDvdImages) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - ui.Say("Mounting secondary DVD images...") - - vmName := state.Get("vmName").(string) - - // should be able to mount up to 60 additional iso images using SCSI - // but Windows would only allow a max of 22 due to available drive letters - // Will Windows assign DVD drives to A: and B: ? - - // For IDE, there are only 2 controllers (0,1) with 2 locations each (0,1) - var dvdProperties []DvdControllerProperties - - isoPaths := s.IsoPaths - - // Add our custom CD, if it exists - cd_path, ok := state.Get("cd_path").(string) - if ok { - if cd_path != "" { - isoPaths = append(isoPaths, cd_path) - } - } - - for _, isoPath := range isoPaths { - var properties DvdControllerProperties - - controllerNumber, controllerLocation, err := driver.CreateDvdDrive(vmName, isoPath, s.Generation) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - properties.ControllerNumber = controllerNumber - properties.ControllerLocation = controllerLocation - properties.Existing = false - dvdProperties = append(dvdProperties, properties) - state.Put("secondary.dvd.properties", dvdProperties) - - ui.Say(fmt.Sprintf("Mounting secondary dvd drive %s ...", isoPath)) - err = driver.MountDvdDrive(vmName, isoPath, controllerNumber, controllerLocation) - if err != nil { - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - log.Println(fmt.Sprintf("ISO %s mounted on DVD controller %v, location %v", isoPath, controllerNumber, - controllerLocation)) - } - - return multistep.ActionContinue -} - -func (s *StepMountSecondaryDvdImages) Cleanup(state multistep.StateBag) { - dvdControllersState := state.Get("secondary.dvd.properties") - - if dvdControllersState == nil { - return - } - - dvdControllers := dvdControllersState.([]DvdControllerProperties) - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - errorMsg := "Error unmounting secondary dvd drive: %s" - - ui.Say("Clean up secondary dvd drives...") - - for _, dvdController := range dvdControllers { - - if dvdController.Existing { - err := driver.UnmountDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - log.Print(fmt.Sprintf(errorMsg, err)) - } - } else { - err := driver.DeleteDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - log.Print(fmt.Sprintf(errorMsg, err)) - } - } - } -} diff --git a/builder/hyperv/common/step_polling_installation.go b/builder/hyperv/common/step_polling_installation.go deleted file mode 100644 index 7c71c430b..000000000 --- a/builder/hyperv/common/step_polling_installation.go +++ /dev/null @@ -1,80 +0,0 @@ -package common - -import ( - "bytes" - "context" - "fmt" - "log" - "os/exec" - "strings" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -const port string = "13000" - -type StepPollingInstallation struct { -} - -func (s *StepPollingInstallation) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - - errorMsg := "Error polling VM: %s" - vmIp := state.Get("ip").(string) - - ui.Say("Start polling VM to check the installation is complete...") - host := "'" + vmIp + "'," + port - - var blockBuffer bytes.Buffer - blockBuffer.WriteString("Invoke-Command -scriptblock {function foo(){try{$client=New-Object System.Net.Sockets.TcpClient(") - blockBuffer.WriteString(host) - blockBuffer.WriteString(") -ErrorAction SilentlyContinue;if($client -eq $null){return $false}}catch{return $false}return $true} foo}") - - count := 60 - var duration time.Duration = 20 - sleepTime := time.Second * duration - - var res string - - for count > 0 { - log.Println(fmt.Sprintf("Connecting vm (%s)...", host)) - cmd := exec.Command("powershell", blockBuffer.String()) - cmdOut, err := cmd.Output() - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - res = strings.TrimSpace(string(cmdOut)) - - if res != "False" { - ui.Say("Signal was received from the VM") - // Sleep before starting provision - time.Sleep(time.Second * 30) - break - } - - log.Println(fmt.Sprintf("Slipping for more %v seconds...", uint(duration))) - time.Sleep(sleepTime) - count-- - } - - if count == 0 { - err := fmt.Errorf(errorMsg, "a signal from vm was not received in a given time period ") - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("The installation complete") - - return multistep.ActionContinue -} - -func (s *StepPollingInstallation) Cleanup(state multistep.StateBag) { - -} diff --git a/builder/hyperv/common/step_reboot_vm.go b/builder/hyperv/common/step_reboot_vm.go deleted file mode 100644 index e9df6eee1..000000000 --- a/builder/hyperv/common/step_reboot_vm.go +++ /dev/null @@ -1,42 +0,0 @@ -package common - -import ( - "context" - "fmt" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepRebootVm struct { -} - -func (s *StepRebootVm) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - errorMsg := "Error rebooting vm: %s" - vmName := state.Get("vmName").(string) - - ui.Say("Rebooting vm...") - - err := driver.RestartVirtualMachine(vmName) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say("Waiting the VM to complete rebooting (2 minutes)...") - - sleepTime := time.Minute * 2 - time.Sleep(sleepTime) - - return multistep.ActionContinue -} - -func (s *StepRebootVm) Cleanup(state multistep.StateBag) { - // do nothing -} diff --git a/builder/hyperv/common/step_run.go b/builder/hyperv/common/step_run.go deleted file mode 100644 index e17e7ec09..000000000 --- a/builder/hyperv/common/step_run.go +++ /dev/null @@ -1,77 +0,0 @@ -package common - -import ( - "context" - "fmt" - "log" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepRun struct { - GuiCancelFunc context.CancelFunc - Headless bool - SwitchName string - vmName string -} - -func (s *StepRun) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - ui.Say("Determine Host IP for HyperV machine...") - hostIp, err := driver.GetHostAdapterIpAddressForSwitch(s.SwitchName) - if err != nil { - err := fmt.Errorf("Error getting host adapter ip address: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - ui.Say(fmt.Sprintf("Host IP for the HyperV machine: %s", hostIp)) - state.Put("http_ip", hostIp) - - if !s.Headless { - ui.Say("Attempting to connect with vmconnect...") - s.GuiCancelFunc, err = driver.Connect(vmName) - if err != nil { - log.Printf(fmt.Sprintf("Non-fatal error starting vmconnect: %s. continuing...", err)) - } - } - - ui.Say("Starting the virtual machine...") - - err = driver.Start(vmName) - if err != nil { - err := fmt.Errorf("Error starting vm: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - s.vmName = vmName - - return multistep.ActionContinue -} - -func (s *StepRun) Cleanup(state multistep.StateBag) { - if s.vmName == "" { - return - } - - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - if !s.Headless && s.GuiCancelFunc != nil { - ui.Say("Disconnecting from vmconnect...") - s.GuiCancelFunc() - } - - if running, _ := driver.IsRunning(s.vmName); running { - if err := driver.Stop(s.vmName); err != nil { - ui.Error(fmt.Sprintf("Error shutting down VM: %s", err)) - } - } -} diff --git a/builder/hyperv/common/step_set_boot_order.go b/builder/hyperv/common/step_set_boot_order.go deleted file mode 100644 index 6a47c0e02..000000000 --- a/builder/hyperv/common/step_set_boot_order.go +++ /dev/null @@ -1,37 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepSetBootOrder struct { - BootOrder []string -} - -func (s *StepSetBootOrder) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - if s.BootOrder != nil { - ui.Say(fmt.Sprintf("Setting boot order to %q", s.BootOrder)) - err := driver.SetBootOrder(vmName, s.BootOrder) - - if err != nil { - err := fmt.Errorf("Error setting the boot order: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - return multistep.ActionContinue -} - -func (s *StepSetBootOrder) Cleanup(state multistep.StateBag) { - // do nothing -} diff --git a/builder/hyperv/common/step_set_boot_order_test.go b/builder/hyperv/common/step_set_boot_order_test.go deleted file mode 100644 index 5dbbab573..000000000 --- a/builder/hyperv/common/step_set_boot_order_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package common - -import ( - "context" - "reflect" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -type bootOrderTest struct { - bootOrder []string -} - -var bootOrderTests = [...]bootOrderTest{ - {[]string{"SCSI:0:0"}}, -} - -func TestStepSetBootOrder(t *testing.T) { - step := new(StepSetBootOrder) - - for _, d := range bootOrderTests { - state := testState(t) - driver := state.Get("driver").(*DriverMock) - vmName := "test" - - state.Put("vmName", vmName) - step.BootOrder = d.bootOrder - - action := step.Run(context.Background(), state) - - if multistep.ActionContinue != action { - t.Fatalf("Should have returned action %v but got %v", multistep.ActionContinue, action) - } - - if vmName != driver.SetBootOrder_VmName { - t.Fatalf("Should have set VmName to %v but got %v", vmName, driver.SetBootOrder_VmName) - } - - if !driver.SetBootOrder_Called { - t.Fatalf("Should have called SetBootOrder") - } - - if !reflect.DeepEqual(d.bootOrder, driver.SetBootOrder_BootOrder) { - t.Fatalf("Should have set BootOrder to %v but got %v", d.bootOrder, driver.SetBootOrder_BootOrder) - } - } -} diff --git a/builder/hyperv/common/step_set_first_boot_device.go b/builder/hyperv/common/step_set_first_boot_device.go deleted file mode 100644 index cbcd8b177..000000000 --- a/builder/hyperv/common/step_set_first_boot_device.go +++ /dev/null @@ -1,160 +0,0 @@ -package common - -import ( - "context" - "fmt" - "regexp" - "strconv" - "strings" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepSetFirstBootDevice struct { - Generation uint - FirstBootDevice string -} - -func ParseBootDeviceIdentifier(deviceIdentifier string, generation uint) (string, uint, uint, error) { - - // all input strings are forced to upperCase for comparison, I believe this is - // safe as all of our values are 7bit ASCII clean. - - lookupDeviceIdentifier := strings.ToUpper(deviceIdentifier) - - if generation == 1 { - - // Gen1 values are a simple set of if/then/else values, which we coalesce into a map - // here for simplicity - - lookupTable := map[string]string{ - "FLOPPY": "FLOPPY", - "IDE": "IDE", - "NET": "NET", - "CD": "CD", - "DVD": "CD", - } - - controllerType, isDefined := lookupTable[lookupDeviceIdentifier] - if !isDefined { - - return "", 0, 0, fmt.Errorf("The value %q is not a properly formatted device group identifier.", deviceIdentifier) - - } - - // success - return controllerType, 0, 0, nil - } - - // everything else is treated as generation 2... the first set of lookups covers - // the simple options.. - - lookupTable := map[string]string{ - "CD": "CD", - "DVD": "CD", - "NET": "NET", - } - - controllerType, isDefined := lookupTable[lookupDeviceIdentifier] - if isDefined { - - // these types do not require controllerNumber or controllerLocation - return controllerType, 0, 0, nil - - } - - // not a simple option, check for a controllerType:controllerNumber:controllerLocation formatted - // device.. - - r, err := regexp.Compile(`^(IDE|SCSI):(\d+):(\d+)$`) - if err != nil { - return "", 0, 0, err - } - - controllerMatch := r.FindStringSubmatch(lookupDeviceIdentifier) - if controllerMatch != nil { - - var controllerLocation int64 - var controllerNumber int64 - - // NOTE: controllerNumber and controllerLocation cannot be negative, the regex expression - // would not have matched if either number was signed - - controllerNumber, err = strconv.ParseInt(controllerMatch[2], 10, 8) - if err == nil { - - controllerLocation, err = strconv.ParseInt(controllerMatch[3], 10, 8) - if err == nil { - - return controllerMatch[1], uint(controllerNumber), uint(controllerLocation), nil - - } - - } - - return "", 0, 0, err - - } - - return "", 0, 0, fmt.Errorf("The value %q is not a properly formatted device identifier.", deviceIdentifier) -} - -func (s *StepSetFirstBootDevice) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - if s.FirstBootDevice != "" { - - controllerType, controllerNumber, controllerLocation, err := ParseBootDeviceIdentifier(s.FirstBootDevice, s.Generation) - if err == nil { - - switch { - - case controllerType == "CD": - { - // the "DVD" controller is special, we only apply the setting if we actually mounted - // an ISO and only if that was mounted as the "IsoUrl" not a secondary ISO. - - dvdControllerState := state.Get("os.dvd.properties") - if dvdControllerState == nil { - - ui.Say("First Boot Device is DVD, but no primary ISO mounted. Ignoring.") - return multistep.ActionContinue - - } - - ui.Say(fmt.Sprintf("Setting boot device to %q", s.FirstBootDevice)) - dvdController := dvdControllerState.(DvdControllerProperties) - err = driver.SetFirstBootDevice(vmName, controllerType, dvdController.ControllerNumber, dvdController.ControllerLocation, s.Generation) - - } - - default: - { - // anything else, we just pass as is.. - ui.Say(fmt.Sprintf("Setting boot device to %q", s.FirstBootDevice)) - err = driver.SetFirstBootDevice(vmName, controllerType, controllerNumber, controllerLocation, s.Generation) - } - } - - } - - if err != nil { - err := fmt.Errorf("Error setting first boot device: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - - } - - } - - return multistep.ActionContinue -} - -func (s *StepSetFirstBootDevice) Cleanup(state multistep.StateBag) { - // do nothing -} diff --git a/builder/hyperv/common/step_set_first_boot_device_test.go b/builder/hyperv/common/step_set_first_boot_device_test.go deleted file mode 100644 index 20341bb90..000000000 --- a/builder/hyperv/common/step_set_first_boot_device_test.go +++ /dev/null @@ -1,170 +0,0 @@ -package common - -import ( - "context" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" -) - -type parseBootDeviceIdentifierTest struct { - generation uint - deviceIdentifier string - controllerType string - controllerNumber uint - controllerLocation uint - failInParse bool // true if ParseBootDeviceIdentifier should return an error - haltStep bool // true if Step.Run should return Halt action - shouldCallSet bool // true if driver.SetFirstBootDevice should have been called - setDvdProps bool // true to set DvdDeviceProperties state -} - -var parseIdentifierTests = [...]parseBootDeviceIdentifierTest{ - {1, "IDE", "IDE", 0, 0, false, false, true, false}, - {1, "idE", "IDE", 0, 0, false, false, true, false}, - {1, "CD", "CD", 0, 0, false, false, false, false}, - {1, "CD", "CD", 0, 0, false, false, true, true}, - {1, "cD", "CD", 0, 0, false, false, false, false}, - {1, "DVD", "CD", 0, 0, false, false, false, false}, - {1, "DVD", "CD", 0, 0, false, false, true, true}, - {1, "Dvd", "CD", 0, 0, false, false, false, false}, - {1, "FLOPPY", "FLOPPY", 0, 0, false, false, true, false}, - {1, "FloppY", "FLOPPY", 0, 0, false, false, true, false}, - {1, "NET", "NET", 0, 0, false, false, true, false}, - {1, "net", "NET", 0, 0, false, false, true, false}, - {1, "", "", 0, 0, true, false, false, false}, - {1, "bad", "", 0, 0, true, true, false, false}, - {1, "IDE:0:0", "", 0, 0, true, true, true, false}, - {1, "SCSI:0:0", "", 0, 0, true, true, true, false}, - {2, "IDE", "", 0, 0, true, true, true, false}, - {2, "idE", "", 0, 0, true, true, true, false}, - {2, "CD", "CD", 0, 0, false, false, false, false}, - {2, "CD", "CD", 0, 0, false, false, true, true}, - {2, "cD", "CD", 0, 0, false, false, false, false}, - {2, "DVD", "CD", 0, 0, false, false, false, false}, - {2, "DVD", "CD", 0, 0, false, false, true, true}, - {2, "Dvd", "CD", 0, 0, false, false, false, false}, - {2, "FLOPPY", "", 0, 0, true, true, true, false}, - {2, "FloppY", "", 0, 0, true, true, true, false}, - {2, "NET", "NET", 0, 0, false, false, true, false}, - {2, "net", "NET", 0, 0, false, false, true, false}, - {2, "", "", 0, 0, true, false, false, false}, - {2, "bad", "", 0, 0, true, true, false, false}, - {2, "IDE:0:0", "IDE", 0, 0, false, false, true, false}, - {2, "SCSI:0:0", "SCSI", 0, 0, false, false, true, false}, - {2, "Ide:0:0", "IDE", 0, 0, false, false, true, false}, - {2, "sCsI:0:0", "SCSI", 0, 0, false, false, true, false}, - {2, "IDEscsi:0:0", "", 0, 0, true, true, false, false}, - {2, "SCSIide:0:0", "", 0, 0, true, true, false, false}, - {2, "IDE:0", "", 0, 0, true, true, false, false}, - {2, "SCSI:0", "", 0, 0, true, true, false, false}, - {2, "IDE:0:a", "", 0, 0, true, true, false, false}, - {2, "SCSI:0:a", "", 0, 0, true, true, false, false}, - {2, "IDE:0:653", "", 0, 0, true, true, false, false}, - {2, "SCSI:-10:0", "", 0, 0, true, true, false, false}, -} - -func TestStepSetFirstBootDevice_impl(t *testing.T) { - var _ multistep.Step = new(StepSetFirstBootDevice) -} - -func TestStepSetFirstBootDevice_ParseIdentifier(t *testing.T) { - - for _, identifierTest := range parseIdentifierTests { - - controllerType, controllerNumber, controllerLocation, err := ParseBootDeviceIdentifier( - identifierTest.deviceIdentifier, - identifierTest.generation) - - if (err != nil) != identifierTest.failInParse { - - t.Fatalf("Test %q (gen %v): failInParse: %v but err: %v", identifierTest.deviceIdentifier, - identifierTest.generation, identifierTest.failInParse, err) - - } - - switch { - - case controllerType != identifierTest.controllerType: - t.Fatalf("Test %q (gen %v): controllerType: %q != %q", identifierTest.deviceIdentifier, identifierTest.generation, - identifierTest.controllerType, controllerType) - - case controllerNumber != identifierTest.controllerNumber: - t.Fatalf("Test %q (gen %v): controllerNumber: %v != %v", identifierTest.deviceIdentifier, identifierTest.generation, - identifierTest.controllerNumber, controllerNumber) - - case controllerLocation != identifierTest.controllerLocation: - t.Fatalf("Test %q (gen %v): controllerLocation: %v != %v", identifierTest.deviceIdentifier, identifierTest.generation, - identifierTest.controllerLocation, controllerLocation) - - } - } -} - -func TestStepSetFirstBootDevice(t *testing.T) { - - step := new(StepSetFirstBootDevice) - - for _, identifierTest := range parseIdentifierTests { - - state := testState(t) - driver := state.Get("driver").(*DriverMock) - - // requires the vmName state value - vmName := "foo" - state.Put("vmName", vmName) - - // pretend that we mounted a DVD somewhere (CD:0:0) - if identifierTest.setDvdProps { - var dvdControllerProperties DvdControllerProperties - dvdControllerProperties.ControllerNumber = 0 - dvdControllerProperties.ControllerLocation = 0 - dvdControllerProperties.Existing = false - state.Put("os.dvd.properties", dvdControllerProperties) - } - - step.Generation = identifierTest.generation - step.FirstBootDevice = identifierTest.deviceIdentifier - - action := step.Run(context.Background(), state) - if (action != multistep.ActionContinue) != identifierTest.haltStep { - t.Fatalf("Test %q (gen %v): Bad action: %v", identifierTest.deviceIdentifier, identifierTest.generation, action) - } - - if identifierTest.haltStep { - - if _, ok := state.GetOk("error"); !ok { - t.Fatalf("Test %q (gen %v): Should have error", identifierTest.deviceIdentifier, identifierTest.generation) - } - - // don't perform the remaining checks.. - continue - - } else { - - if _, ok := state.GetOk("error"); ok { - t.Fatalf("Test %q (gen %v): Should NOT have error", identifierTest.deviceIdentifier, identifierTest.generation) - } - - } - - if driver.SetFirstBootDevice_Called != identifierTest.shouldCallSet { - if identifierTest.shouldCallSet { - t.Fatalf("Test %q (gen %v): Should have called SetFirstBootDevice", identifierTest.deviceIdentifier, identifierTest.generation) - } - - t.Fatalf("Test %q (gen %v): Should NOT have called SetFirstBootDevice", identifierTest.deviceIdentifier, identifierTest.generation) - } - - if (driver.SetFirstBootDevice_Called) && - ((driver.SetFirstBootDevice_VmName != vmName) || - (driver.SetFirstBootDevice_ControllerType != identifierTest.controllerType) || - (driver.SetFirstBootDevice_ControllerNumber != identifierTest.controllerNumber) || - (driver.SetFirstBootDevice_ControllerLocation != identifierTest.controllerLocation) || - (driver.SetFirstBootDevice_Generation != identifierTest.generation)) { - - t.Fatalf("Test %q (gen %v): Called SetFirstBootDevice with unexpected arguments.", identifierTest.deviceIdentifier, identifierTest.generation) - - } - } -} diff --git a/builder/hyperv/common/step_shutdown.go b/builder/hyperv/common/step_shutdown.go deleted file mode 100644 index fd210ea44..000000000 --- a/builder/hyperv/common/step_shutdown.go +++ /dev/null @@ -1,90 +0,0 @@ -package common - -import ( - "bytes" - "context" - "errors" - "fmt" - "log" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -// This step shuts down the machine. It first attempts to do so gracefully, -// but ultimately forcefully shuts it down if that fails. -// -// Uses: -// communicator packersdk.Communicator -// driver Driver -// ui packersdk.Ui -// vmName string -// -// Produces: -// -type StepShutdown struct { - Command string - Timeout time.Duration -} - -func (s *StepShutdown) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - - comm := state.Get("communicator").(packersdk.Communicator) - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - if s.Command != "" { - ui.Say("Gracefully halting virtual machine...") - log.Printf("Executing shutdown command: %s", s.Command) - - var stdout, stderr bytes.Buffer - cmd := &packersdk.RemoteCmd{ - Command: s.Command, - Stdout: &stdout, - Stderr: &stderr, - } - if err := comm.Start(ctx, cmd); err != nil { - err := fmt.Errorf("Failed to send shutdown command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - // Wait for the machine to actually shut down - log.Printf("Waiting max %s for shutdown to complete", s.Timeout) - shutdownTimer := time.After(s.Timeout) - for { - running, _ := driver.IsRunning(vmName) - if !running { - break - } - - select { - case <-shutdownTimer: - log.Printf("Shutdown stdout: %s", stdout.String()) - log.Printf("Shutdown stderr: %s", stderr.String()) - err := errors.New("Timeout while waiting for machine to shut down.") - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - default: - time.Sleep(500 * time.Millisecond) - } - } - } else { - ui.Say("Forcibly halting virtual machine...") - if err := driver.Stop(vmName); err != nil { - err := fmt.Errorf("Error stopping VM: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - log.Println("VM shut down.") - return multistep.ActionContinue -} - -func (s *StepShutdown) Cleanup(state multistep.StateBag) {} diff --git a/builder/hyperv/common/step_sleep.go b/builder/hyperv/common/step_sleep.go deleted file mode 100644 index 411d27eda..000000000 --- a/builder/hyperv/common/step_sleep.go +++ /dev/null @@ -1,31 +0,0 @@ -package common - -import ( - "context" - "fmt" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepSleep struct { - Minutes time.Duration - ActionName string -} - -func (s *StepSleep) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - ui := state.Get("ui").(packersdk.Ui) - - if len(s.ActionName) > 0 { - ui.Say(s.ActionName + "! Waiting for " + fmt.Sprintf("%v", uint(s.Minutes)) + - " minutes to let the action to complete...") - } - time.Sleep(time.Minute * s.Minutes) - - return multistep.ActionContinue -} - -func (s *StepSleep) Cleanup(state multistep.StateBag) { - -} diff --git a/builder/hyperv/common/step_test.go b/builder/hyperv/common/step_test.go deleted file mode 100644 index 13a83bcbb..000000000 --- a/builder/hyperv/common/step_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package common - -import ( - "bytes" - "os" - "path/filepath" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/uuid" -) - -func testState(t *testing.T) multistep.StateBag { - state := new(multistep.BasicStateBag) - state.Put("driver", new(DriverMock)) - state.Put("ui", &packersdk.BasicUi{ - Reader: new(bytes.Buffer), - Writer: new(bytes.Buffer), - }) - return state -} - -// Generates an absolute path to a directory under OS temp with a name -// beginning with prefix and a UUID appended to the end -func genTestDirPath(prefix string) string { - return filepath.Join(os.TempDir(), prefix+"-"+uuid.TimeOrderedUUID()) -} diff --git a/builder/hyperv/common/step_type_boot_command.go b/builder/hyperv/common/step_type_boot_command.go deleted file mode 100644 index 4f5f86794..000000000 --- a/builder/hyperv/common/step_type_boot_command.go +++ /dev/null @@ -1,88 +0,0 @@ -package common - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/hashicorp/packer-plugin-sdk/bootcommand" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" -) - -type bootCommandTemplateData struct { - HTTPIP string - HTTPPort int - Name string -} - -// This step "types" the boot command into the VM via the Hyper-V virtual keyboard -type StepTypeBootCommand struct { - BootCommand string - BootWait time.Duration - SwitchName string - Ctx interpolate.Context - GroupInterval time.Duration -} - -func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - httpPort := state.Get("http_port").(int) - ui := state.Get("ui").(packersdk.Ui) - driver := state.Get("driver").(Driver) - vmName := state.Get("vmName").(string) - hostIp := state.Get("http_ip").(string) - - // Wait the for the vm to boot. - if int64(s.BootWait) > 0 { - ui.Say(fmt.Sprintf("Waiting %s for boot...", s.BootWait.String())) - select { - case <-time.After(s.BootWait): - break - case <-ctx.Done(): - return multistep.ActionHalt - } - } - - s.Ctx.Data = &bootCommandTemplateData{ - hostIp, - httpPort, - vmName, - } - - sendCodes := func(codes []string) error { - scanCodesToSendString := strings.Join(codes, " ") - return driver.TypeScanCodes(vmName, scanCodesToSendString) - } - d := bootcommand.NewPCXTDriver(sendCodes, 32, s.GroupInterval) - - ui.Say("Typing the boot command...") - command, err := interpolate.Render(s.BootCommand, &s.Ctx) - - if err != nil { - err := fmt.Errorf("Error preparing boot command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - seq, err := bootcommand.GenerateExpressionSequence(command) - if err != nil { - err := fmt.Errorf("Error generating boot command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if err := seq.Do(ctx, d); err != nil { - err := fmt.Errorf("Error running boot command: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - return multistep.ActionContinue -} - -func (*StepTypeBootCommand) Cleanup(multistep.StateBag) {} diff --git a/builder/hyperv/common/step_unmount_dvddrive.go b/builder/hyperv/common/step_unmount_dvddrive.go deleted file mode 100644 index 29a2beaf3..000000000 --- a/builder/hyperv/common/step_unmount_dvddrive.go +++ /dev/null @@ -1,57 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepUnmountDvdDrive struct { -} - -func (s *StepUnmountDvdDrive) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - vmName := state.Get("vmName").(string) - ui := state.Get("ui").(packersdk.Ui) - - ui.Say("Unmount/delete os dvd drive...") - - dvdControllerState := state.Get("os.dvd.properties") - - if dvdControllerState == nil { - return multistep.ActionContinue - } - - dvdController := dvdControllerState.(DvdControllerProperties) - - if dvdController.Existing { - ui.Say(fmt.Sprintf("Unmounting os dvd drives controller %d location %d ...", - dvdController.ControllerNumber, dvdController.ControllerLocation)) - err := driver.UnmountDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error unmounting os dvd drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } else { - ui.Say(fmt.Sprintf("Delete os dvd drives controller %d location %d ...", - dvdController.ControllerNumber, dvdController.ControllerLocation)) - err := driver.DeleteDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error deleting os dvd drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - state.Put("os.dvd.properties", nil) - - return multistep.ActionContinue -} - -func (s *StepUnmountDvdDrive) Cleanup(state multistep.StateBag) { -} diff --git a/builder/hyperv/common/step_unmount_floppydrive.go b/builder/hyperv/common/step_unmount_floppydrive.go deleted file mode 100644 index 862bfbf8a..000000000 --- a/builder/hyperv/common/step_unmount_floppydrive.go +++ /dev/null @@ -1,40 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepUnmountFloppyDrive struct { - Generation uint -} - -func (s *StepUnmountFloppyDrive) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - - if s.Generation > 1 { - return multistep.ActionContinue - } - - vmName := state.Get("vmName").(string) - ui.Say("Unmount/delete floppy drive (Run)...") - - errorMsg := "Error Unmounting floppy drive: %s" - - err := driver.UnmountFloppyDrive(vmName) - if err != nil { - err := fmt.Errorf(errorMsg, err) - state.Put("error", err) - ui.Error(err.Error()) - } - - return multistep.ActionContinue -} - -func (s *StepUnmountFloppyDrive) Cleanup(state multistep.StateBag) { - // do nothing -} diff --git a/builder/hyperv/common/step_unmount_guest_additions.go b/builder/hyperv/common/step_unmount_guest_additions.go deleted file mode 100644 index 602f1cb5e..000000000 --- a/builder/hyperv/common/step_unmount_guest_additions.go +++ /dev/null @@ -1,57 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepUnmountGuestAdditions struct { -} - -func (s *StepUnmountGuestAdditions) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - vmName := state.Get("vmName").(string) - ui := state.Get("ui").(packersdk.Ui) - - ui.Say("Unmount/delete Integration Services dvd drive...") - - dvdControllerState := state.Get("guest.dvd.properties") - - if dvdControllerState == nil { - return multistep.ActionContinue - } - - dvdController := dvdControllerState.(DvdControllerProperties) - - if dvdController.Existing { - ui.Say(fmt.Sprintf("Unmounting Integration Services dvd drives controller %d location %d ...", - dvdController.ControllerNumber, dvdController.ControllerLocation)) - err := driver.UnmountDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error unmounting Integration Services dvd drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } else { - ui.Say(fmt.Sprintf("Delete Integration Services dvd drives controller %d location %d ...", - dvdController.ControllerNumber, dvdController.ControllerLocation)) - err := driver.DeleteDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error deleting Integration Services dvd drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - - state.Put("guest.dvd.properties", nil) - - return multistep.ActionContinue -} - -func (s *StepUnmountGuestAdditions) Cleanup(state multistep.StateBag) { -} diff --git a/builder/hyperv/common/step_unmount_secondary_dvd_images.go b/builder/hyperv/common/step_unmount_secondary_dvd_images.go deleted file mode 100644 index 46cd93e38..000000000 --- a/builder/hyperv/common/step_unmount_secondary_dvd_images.go +++ /dev/null @@ -1,59 +0,0 @@ -package common - -import ( - "context" - "fmt" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -type StepUnmountSecondaryDvdImages struct { -} - -func (s *StepUnmountSecondaryDvdImages) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - ui.Say("Unmount/delete secondary dvd drives...") - - dvdControllersState := state.Get("secondary.dvd.properties") - - if dvdControllersState == nil { - return multistep.ActionContinue - } - - dvdControllers := dvdControllersState.([]DvdControllerProperties) - - for _, dvdController := range dvdControllers { - if dvdController.Existing { - ui.Say(fmt.Sprintf("Unmounting secondary dvd drives controller %d location %d ...", - dvdController.ControllerNumber, dvdController.ControllerLocation)) - err := driver.UnmountDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error unmounting secondary dvd drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } else { - ui.Say(fmt.Sprintf("Delete secondary dvd drives controller %d location %d ...", - dvdController.ControllerNumber, dvdController.ControllerLocation)) - err := driver.DeleteDvdDrive(vmName, dvdController.ControllerNumber, dvdController.ControllerLocation) - if err != nil { - err := fmt.Errorf("Error deleting secondary dvd drive: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - } - } - - state.Put("secondary.dvd.properties", nil) - - return multistep.ActionContinue -} - -func (s *StepUnmountSecondaryDvdImages) Cleanup(state multistep.StateBag) { -} diff --git a/builder/hyperv/common/step_wait_for_install_to_complete.go b/builder/hyperv/common/step_wait_for_install_to_complete.go deleted file mode 100644 index 91da113af..000000000 --- a/builder/hyperv/common/step_wait_for_install_to_complete.go +++ /dev/null @@ -1,92 +0,0 @@ -package common - -import ( - "context" - "fmt" - "time" - - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" -) - -const ( - SleepSeconds = 10 -) - -type StepWaitForPowerOff struct { -} - -func (s *StepWaitForPowerOff) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - ui.Say("Waiting for vm to be powered down...") - - for { - isOff, err := driver.IsOff(vmName) - - if err != nil { - err := fmt.Errorf("Error checking if vm is off: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if isOff { - break - } else { - time.Sleep(time.Second * SleepSeconds) - } - } - - return multistep.ActionContinue -} - -func (s *StepWaitForPowerOff) Cleanup(state multistep.StateBag) { -} - -type StepWaitForInstallToComplete struct { - ExpectedRebootCount uint - ActionName string -} - -func (s *StepWaitForInstallToComplete) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { - driver := state.Get("driver").(Driver) - ui := state.Get("ui").(packersdk.Ui) - vmName := state.Get("vmName").(string) - - if len(s.ActionName) > 0 { - ui.Say(fmt.Sprintf("%v ! Waiting for VM to reboot %v times...", s.ActionName, s.ExpectedRebootCount)) - } - - var rebootCount uint - var lastUptime uint64 - - for rebootCount < s.ExpectedRebootCount { - uptime, err := driver.Uptime(vmName) - - if err != nil { - err := fmt.Errorf("Error checking uptime: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt - } - - if uptime < lastUptime { - rebootCount++ - ui.Say(fmt.Sprintf("%v -> Detected reboot %v after %v seconds...", s.ActionName, rebootCount, lastUptime)) - } - - lastUptime = uptime - - if rebootCount < s.ExpectedRebootCount { - time.Sleep(time.Second * SleepSeconds) - } - } - - return multistep.ActionContinue -} - -func (s *StepWaitForInstallToComplete) Cleanup(state multistep.StateBag) { - -} diff --git a/builder/hyperv/iso/builder.go b/builder/hyperv/iso/builder.go deleted file mode 100644 index ebe37bfa2..000000000 --- a/builder/hyperv/iso/builder.go +++ /dev/null @@ -1,377 +0,0 @@ -//go:generate packer-sdc struct-markdown -//go:generate packer-sdc mapstructure-to-hcl2 -type Config - -package iso - -import ( - "context" - "errors" - "fmt" - "log" - "path/filepath" - "strings" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/bootcommand" - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/shutdowncommand" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" - hypervcommon "github.com/hashicorp/packer/builder/hyperv/common" -) - -const ( - DefaultDiskSize = 40 * 1024 // ~40GB - MinDiskSize = 256 // 256MB - MaxDiskSize = 64 * 1024 * 1024 // 64TB - MaxVHDSize = 2040 * 1024 // 2040GB - - DefaultDiskBlockSize = 32 // 32MB - MinDiskBlockSize = 1 // 1MB - MaxDiskBlockSize = 256 // 256MB - - DefaultRamSize = 1 * 1024 // 1GB - MinRamSize = 32 // 32MB - MaxRamSize = 32 * 1024 // 32GB - MinNestedVirtualizationRamSize = 4 * 1024 // 4GB - - LowRam = 256 // 256MB - - DefaultUsername = "" - DefaultPassword = "" -) - -// Builder implements packersdk.Builder and builds the actual Hyperv -// images. -type Builder struct { - config Config - runner multistep.Runner -} - -type Config struct { - common.PackerConfig `mapstructure:",squash"` - commonsteps.HTTPConfig `mapstructure:",squash"` - commonsteps.ISOConfig `mapstructure:",squash"` - bootcommand.BootConfig `mapstructure:",squash"` - hypervcommon.OutputConfig `mapstructure:",squash"` - hypervcommon.SSHConfig `mapstructure:",squash"` - hypervcommon.CommonConfig `mapstructure:",squash"` - shutdowncommand.ShutdownConfig `mapstructure:",squash"` - // The size, in megabytes, of the hard disk to create - // for the VM. By default, this is 40 GB. - DiskSize uint `mapstructure:"disk_size" required:"false"` - // If true use a legacy network adapter as the NIC. - // This defaults to false. A legacy network adapter is fully emulated NIC, and is thus - // supported by various exotic operating systems, but this emulation requires - // additional overhead and should only be used if absolutely necessary. - UseLegacyNetworkAdapter bool `mapstructure:"use_legacy_network_adapter" required:"false"` - // If true enables differencing disks. Only - // the changes will be written to the new disk. This is especially useful if - // your source is a VHD/VHDX. This defaults to false. - DifferencingDisk bool `mapstructure:"differencing_disk" required:"false"` - // If true, creates the boot disk on the - // virtual machine as a fixed VHD format disk. The default is false, which - // creates a dynamic VHDX format disk. This option requires setting - // generation to 1, skip_compaction to true, and - // differencing_disk to false. Additionally, any value entered for - // disk_block_size will be ignored. The most likely use case for this - // option is outputing a disk that is in the format required for upload to - // Azure. - FixedVHD bool `mapstructure:"use_fixed_vhd_format" required:"false"` - - ctx interpolate.Context -} - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - err := config.Decode(&b.config, &config.DecodeOpts{ - PluginType: hypervcommon.BuilderId, - Interpolate: true, - InterpolateContext: &b.config.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{ - "boot_command", - }, - }, - }, raws...) - if err != nil { - return nil, nil, err - } - - // Accumulate any errors and warnings - var errs *packersdk.MultiError - warnings := make([]string, 0) - - isoWarnings, isoErrs := b.config.ISOConfig.Prepare(&b.config.ctx) - warnings = append(warnings, isoWarnings...) - errs = packersdk.MultiErrorAppend(errs, isoErrs...) - - errs = packersdk.MultiErrorAppend(errs, b.config.BootConfig.Prepare(&b.config.ctx)...) - errs = packersdk.MultiErrorAppend(errs, b.config.HTTPConfig.Prepare(&b.config.ctx)...) - errs = packersdk.MultiErrorAppend(errs, b.config.OutputConfig.Prepare(&b.config.ctx, &b.config.PackerConfig)...) - errs = packersdk.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...) - errs = packersdk.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...) - - commonErrs, commonWarns := b.config.CommonConfig.Prepare(&b.config.ctx, &b.config.PackerConfig) - errs = packersdk.MultiErrorAppend(errs, commonErrs...) - warnings = append(warnings, commonWarns...) - - if len(b.config.ISOConfig.ISOUrls) < 1 || - (strings.ToLower(filepath.Ext(b.config.ISOConfig.ISOUrls[0])) != ".vhd" && - strings.ToLower(filepath.Ext(b.config.ISOConfig.ISOUrls[0])) != ".vhdx") { - //We only create a new hard drive if an existing one to copy from does not exist - err = b.checkDiskSize() - if err != nil { - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - if b.config.Cpu < 1 { - b.config.Cpu = 1 - } - - if b.config.Generation == 2 { - if b.config.UseLegacyNetworkAdapter { - err = errors.New("Generation 2 vms don't support legacy network adapters.") - errs = packersdk.MultiErrorAppend(errs, err) - } - } - - // Errors - - if b.config.Generation > 1 && b.config.FixedVHD { - err = errors.New("Fixed VHD disks are only supported on Generation 1 virtual machines.") - errs = packersdk.MultiErrorAppend(errs, err) - } - - if !b.config.SkipCompaction && b.config.FixedVHD { - err = errors.New("Fixed VHD disks do not support compaction.") - errs = packersdk.MultiErrorAppend(errs, err) - } - - if b.config.DifferencingDisk && b.config.FixedVHD { - err = errors.New("Fixed VHD disks are not supported with differencing disks.") - errs = packersdk.MultiErrorAppend(errs, err) - } - - // Warnings - - if b.config.ShutdownCommand == "" { - warnings = append(warnings, - "A shutdown_command was not specified. Without a shutdown command, Packer\n"+ - "will forcibly halt the virtual machine, which may result in data loss.") - } - - if errs != nil && len(errs.Errors) > 0 { - return nil, warnings, errs - } - - return nil, warnings, nil -} - -// Run executes a Packer build and returns a packersdk.Artifact representing -// a Hyperv appliance. -func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) { - // Create the driver that we'll use to communicate with Hyperv - driver, err := hypervcommon.NewHypervPS4Driver() - if err != nil { - return nil, fmt.Errorf("Failed creating Hyper-V driver: %s", err) - } - - // Set up the state. - state := new(multistep.BasicStateBag) - state.Put("debug", b.config.PackerDebug) - state.Put("driver", driver) - state.Put("hook", hook) - state.Put("ui", ui) - - steps := []multistep.Step{ - &hypervcommon.StepCreateBuildDir{ - TempPath: b.config.TempPath, - }, - &commonsteps.StepOutputDir{ - Force: b.config.PackerForce, - Path: b.config.OutputDir, - }, - &commonsteps.StepDownload{ - Checksum: b.config.ISOChecksum, - Description: "ISO", - ResultKey: "iso_path", - Url: b.config.ISOUrls, - Extension: b.config.TargetExtension, - TargetPath: b.config.TargetPath, - }, - &commonsteps.StepCreateFloppy{ - Files: b.config.FloppyConfig.FloppyFiles, - Directories: b.config.FloppyConfig.FloppyDirectories, - Label: b.config.FloppyConfig.FloppyLabel, - }, - commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), - &hypervcommon.StepCreateSwitch{ - SwitchName: b.config.SwitchName, - }, - &hypervcommon.StepCreateVM{ - VMName: b.config.VMName, - SwitchName: b.config.SwitchName, - RamSize: b.config.RamSize, - DiskSize: b.config.DiskSize, - DiskBlockSize: b.config.DiskBlockSize, - Generation: b.config.Generation, - Cpu: b.config.Cpu, - EnableMacSpoofing: b.config.EnableMacSpoofing, - EnableDynamicMemory: b.config.EnableDynamicMemory, - EnableSecureBoot: b.config.EnableSecureBoot, - SecureBootTemplate: b.config.SecureBootTemplate, - EnableVirtualizationExtensions: b.config.EnableVirtualizationExtensions, - UseLegacyNetworkAdapter: b.config.UseLegacyNetworkAdapter, - AdditionalDiskSize: b.config.AdditionalDiskSize, - DifferencingDisk: b.config.DifferencingDisk, - MacAddress: b.config.MacAddress, - FixedVHD: b.config.FixedVHD, - Version: b.config.Version, - KeepRegistered: b.config.KeepRegistered, - }, - &hypervcommon.StepEnableIntegrationService{}, - - &hypervcommon.StepMountDvdDrive{ - Generation: b.config.Generation, - FirstBootDevice: b.config.FirstBootDevice, - }, - &hypervcommon.StepMountFloppydrive{ - Generation: b.config.Generation, - }, - - &hypervcommon.StepMountGuestAdditions{ - GuestAdditionsMode: b.config.GuestAdditionsMode, - GuestAdditionsPath: b.config.GuestAdditionsPath, - Generation: b.config.Generation, - }, - &commonsteps.StepCreateCD{ - Files: b.config.CDConfig.CDFiles, - Label: b.config.CDConfig.CDLabel, - }, - &hypervcommon.StepMountSecondaryDvdImages{ - IsoPaths: b.config.SecondaryDvdImages, - Generation: b.config.Generation, - }, - - &hypervcommon.StepConfigureVlan{ - VlanId: b.config.VlanId, - SwitchVlanId: b.config.SwitchVlanId, - }, - - &hypervcommon.StepSetBootOrder{ - BootOrder: b.config.BootOrder, - }, - &hypervcommon.StepSetFirstBootDevice{ - Generation: b.config.Generation, - FirstBootDevice: b.config.FirstBootDevice, - }, - - &hypervcommon.StepRun{ - Headless: b.config.Headless, - SwitchName: b.config.SwitchName, - }, - - &hypervcommon.StepTypeBootCommand{ - BootCommand: b.config.FlatBootCommand(), - BootWait: b.config.BootWait, - SwitchName: b.config.SwitchName, - Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, - }, - - // configure the communicator ssh, winrm - &communicator.StepConnect{ - Config: &b.config.SSHConfig.Comm, - Host: hypervcommon.CommHost(b.config.SSHConfig.Comm.Host()), - SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(), - }, - - // provision requires communicator to be setup - &commonsteps.StepProvision{}, - - // Remove ephemeral key from authorized_hosts if using SSH communicator - &commonsteps.StepCleanupTempKeys{ - Comm: &b.config.SSHConfig.Comm, - }, - - &hypervcommon.StepShutdown{ - Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, - }, - - // wait for the vm to be powered off - &hypervcommon.StepWaitForPowerOff{}, - - // remove the secondary dvd images - // after we power down - &hypervcommon.StepUnmountSecondaryDvdImages{}, - &hypervcommon.StepUnmountGuestAdditions{}, - &hypervcommon.StepUnmountDvdDrive{}, - &hypervcommon.StepUnmountFloppyDrive{ - Generation: b.config.Generation, - }, - &hypervcommon.StepCompactDisk{ - SkipCompaction: b.config.SkipCompaction, - }, - &hypervcommon.StepExportVm{ - OutputDir: b.config.OutputDir, - SkipExport: b.config.SkipExport, - }, - &hypervcommon.StepCollateArtifacts{ - OutputDir: b.config.OutputDir, - SkipExport: b.config.SkipExport, - }, - - // the clean up actions for each step will be executed reverse order - } - - // Run the steps. - b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui) - b.runner.Run(ctx, state) - - // Report any errors. - if rawErr, ok := state.GetOk("error"); ok { - return nil, rawErr.(error) - } - - // If we were interrupted or cancelled, then just exit. - if _, ok := state.GetOk(multistep.StateCancelled); ok { - return nil, errors.New("Build was cancelled.") - } - - if _, ok := state.GetOk(multistep.StateHalted); ok { - return nil, errors.New("Build was halted.") - } - generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} - return hypervcommon.NewArtifact(b.config.OutputDir, generatedData) -} - -// Cancel. - -func (b *Builder) checkDiskSize() error { - if b.config.DiskSize == 0 { - b.config.DiskSize = DefaultDiskSize - } - - log.Println(fmt.Sprintf("%s: %v", "DiskSize", b.config.DiskSize)) - - if b.config.DiskSize < MinDiskSize { - return fmt.Errorf("disk_size: Virtual machine requires disk space >= %v GB, but defined: %v", - MinDiskSize, b.config.DiskSize/1024) - } else if b.config.DiskSize > MaxDiskSize && !b.config.FixedVHD { - return fmt.Errorf("disk_size: Virtual machine requires disk space <= %v GB, but defined: %v", - MaxDiskSize, b.config.DiskSize/1024) - } else if b.config.DiskSize > MaxVHDSize && b.config.FixedVHD { - return fmt.Errorf("disk_size: Virtual machine requires disk space <= %v GB, but defined: %v", - MaxVHDSize/1024, b.config.DiskSize/1024) - } - - return nil -} diff --git a/builder/hyperv/iso/builder.hcl2spec.go b/builder/hyperv/iso/builder.hcl2spec.go deleted file mode 100644 index 83801b7d9..000000000 --- a/builder/hyperv/iso/builder.hcl2spec.go +++ /dev/null @@ -1,247 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package iso - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"` - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` - BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"` - BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"` - BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"` - OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` - SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"` - FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"` - FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"` - CDFiles []string `mapstructure:"cd_files" cty:"cd_files" hcl:"cd_files"` - CDLabel *string `mapstructure:"cd_label" cty:"cd_label" hcl:"cd_label"` - DiskBlockSize *uint `mapstructure:"disk_block_size" required:"false" cty:"disk_block_size" hcl:"disk_block_size"` - RamSize *uint `mapstructure:"memory" required:"false" cty:"memory" hcl:"memory"` - SecondaryDvdImages []string `mapstructure:"secondary_iso_images" required:"false" cty:"secondary_iso_images" hcl:"secondary_iso_images"` - AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size" hcl:"disk_additional_size"` - GuestAdditionsMode *string `mapstructure:"guest_additions_mode" required:"false" cty:"guest_additions_mode" hcl:"guest_additions_mode"` - GuestAdditionsPath *string `mapstructure:"guest_additions_path" required:"false" cty:"guest_additions_path" hcl:"guest_additions_path"` - VMName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"` - SwitchName *string `mapstructure:"switch_name" required:"false" cty:"switch_name" hcl:"switch_name"` - SwitchVlanId *string `mapstructure:"switch_vlan_id" required:"false" cty:"switch_vlan_id" hcl:"switch_vlan_id"` - MacAddress *string `mapstructure:"mac_address" required:"false" cty:"mac_address" hcl:"mac_address"` - VlanId *string `mapstructure:"vlan_id" required:"false" cty:"vlan_id" hcl:"vlan_id"` - Cpu *uint `mapstructure:"cpus" required:"false" cty:"cpus" hcl:"cpus"` - Generation *uint `mapstructure:"generation" required:"false" cty:"generation" hcl:"generation"` - EnableMacSpoofing *bool `mapstructure:"enable_mac_spoofing" required:"false" cty:"enable_mac_spoofing" hcl:"enable_mac_spoofing"` - EnableDynamicMemory *bool `mapstructure:"enable_dynamic_memory" required:"false" cty:"enable_dynamic_memory" hcl:"enable_dynamic_memory"` - EnableSecureBoot *bool `mapstructure:"enable_secure_boot" required:"false" cty:"enable_secure_boot" hcl:"enable_secure_boot"` - SecureBootTemplate *string `mapstructure:"secure_boot_template" required:"false" cty:"secure_boot_template" hcl:"secure_boot_template"` - EnableVirtualizationExtensions *bool `mapstructure:"enable_virtualization_extensions" required:"false" cty:"enable_virtualization_extensions" hcl:"enable_virtualization_extensions"` - TempPath *string `mapstructure:"temp_path" required:"false" cty:"temp_path" hcl:"temp_path"` - Version *string `mapstructure:"configuration_version" required:"false" cty:"configuration_version" hcl:"configuration_version"` - KeepRegistered *bool `mapstructure:"keep_registered" required:"false" cty:"keep_registered" hcl:"keep_registered"` - SkipCompaction *bool `mapstructure:"skip_compaction" required:"false" cty:"skip_compaction" hcl:"skip_compaction"` - SkipExport *bool `mapstructure:"skip_export" required:"false" cty:"skip_export" hcl:"skip_export"` - Headless *bool `mapstructure:"headless" required:"false" cty:"headless" hcl:"headless"` - FirstBootDevice *string `mapstructure:"first_boot_device" required:"false" cty:"first_boot_device" hcl:"first_boot_device"` - BootOrder []string `mapstructure:"boot_order" required:"false" cty:"boot_order" hcl:"boot_order"` - ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command" hcl:"shutdown_command"` - ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout" hcl:"shutdown_timeout"` - DiskSize *uint `mapstructure:"disk_size" required:"false" cty:"disk_size" hcl:"disk_size"` - UseLegacyNetworkAdapter *bool `mapstructure:"use_legacy_network_adapter" required:"false" cty:"use_legacy_network_adapter" hcl:"use_legacy_network_adapter"` - DifferencingDisk *bool `mapstructure:"differencing_disk" required:"false" cty:"differencing_disk" hcl:"differencing_disk"` - FixedVHD *bool `mapstructure:"use_fixed_vhd_format" required:"false" cty:"use_fixed_vhd_format" hcl:"use_fixed_vhd_format"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, - "http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false}, - "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, - "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, - "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, - "http_interface": &hcldec.AttrSpec{Name: "http_interface", Type: cty.String, Required: false}, - "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, - "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, - "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, - "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, - "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, - "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, - "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, - "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, - "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, - "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, - "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, - "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, - "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, - "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, - "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, - "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, - "temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false}, - "temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false}, - "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, - "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, - "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, - "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, - "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, - "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, - "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, - "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, - "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, - "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, - "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, - "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, - "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, - "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, - "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, - "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, - "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, - "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, - "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, - "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, - "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, - "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, - "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, - "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, - "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, - "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, - "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, - "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, - "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, - "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, - "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, - "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, - "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, - "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, - "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, - "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, - "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, - "floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false}, - "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, - "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, - "cd_files": &hcldec.AttrSpec{Name: "cd_files", Type: cty.List(cty.String), Required: false}, - "cd_label": &hcldec.AttrSpec{Name: "cd_label", Type: cty.String, Required: false}, - "disk_block_size": &hcldec.AttrSpec{Name: "disk_block_size", Type: cty.Number, Required: false}, - "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, - "secondary_iso_images": &hcldec.AttrSpec{Name: "secondary_iso_images", Type: cty.List(cty.String), Required: false}, - "disk_additional_size": &hcldec.AttrSpec{Name: "disk_additional_size", Type: cty.List(cty.Number), Required: false}, - "guest_additions_mode": &hcldec.AttrSpec{Name: "guest_additions_mode", Type: cty.String, Required: false}, - "guest_additions_path": &hcldec.AttrSpec{Name: "guest_additions_path", Type: cty.String, Required: false}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "switch_name": &hcldec.AttrSpec{Name: "switch_name", Type: cty.String, Required: false}, - "switch_vlan_id": &hcldec.AttrSpec{Name: "switch_vlan_id", Type: cty.String, Required: false}, - "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, - "vlan_id": &hcldec.AttrSpec{Name: "vlan_id", Type: cty.String, Required: false}, - "cpus": &hcldec.AttrSpec{Name: "cpus", Type: cty.Number, Required: false}, - "generation": &hcldec.AttrSpec{Name: "generation", Type: cty.Number, Required: false}, - "enable_mac_spoofing": &hcldec.AttrSpec{Name: "enable_mac_spoofing", Type: cty.Bool, Required: false}, - "enable_dynamic_memory": &hcldec.AttrSpec{Name: "enable_dynamic_memory", Type: cty.Bool, Required: false}, - "enable_secure_boot": &hcldec.AttrSpec{Name: "enable_secure_boot", Type: cty.Bool, Required: false}, - "secure_boot_template": &hcldec.AttrSpec{Name: "secure_boot_template", Type: cty.String, Required: false}, - "enable_virtualization_extensions": &hcldec.AttrSpec{Name: "enable_virtualization_extensions", Type: cty.Bool, Required: false}, - "temp_path": &hcldec.AttrSpec{Name: "temp_path", Type: cty.String, Required: false}, - "configuration_version": &hcldec.AttrSpec{Name: "configuration_version", Type: cty.String, Required: false}, - "keep_registered": &hcldec.AttrSpec{Name: "keep_registered", Type: cty.Bool, Required: false}, - "skip_compaction": &hcldec.AttrSpec{Name: "skip_compaction", Type: cty.Bool, Required: false}, - "skip_export": &hcldec.AttrSpec{Name: "skip_export", Type: cty.Bool, Required: false}, - "headless": &hcldec.AttrSpec{Name: "headless", Type: cty.Bool, Required: false}, - "first_boot_device": &hcldec.AttrSpec{Name: "first_boot_device", Type: cty.String, Required: false}, - "boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.List(cty.String), Required: false}, - "shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false}, - "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false}, - "disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false}, - "use_legacy_network_adapter": &hcldec.AttrSpec{Name: "use_legacy_network_adapter", Type: cty.Bool, Required: false}, - "differencing_disk": &hcldec.AttrSpec{Name: "differencing_disk", Type: cty.Bool, Required: false}, - "use_fixed_vhd_format": &hcldec.AttrSpec{Name: "use_fixed_vhd_format", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/hyperv/iso/builder_test.go b/builder/hyperv/iso/builder_test.go deleted file mode 100644 index 85484a97c..000000000 --- a/builder/hyperv/iso/builder_test.go +++ /dev/null @@ -1,658 +0,0 @@ -// +build !windows - -package iso - -import ( - "context" - "fmt" - "reflect" - "strconv" - "testing" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - hypervcommon "github.com/hashicorp/packer/builder/hyperv/common" -) - -func testConfig() map[string]interface{} { - return map[string]interface{}{ - "iso_checksum": "md5:0B0F137F17AC10944716020B018F8126", - "iso_url": "http://www.packer.io", - "shutdown_command": "yes", - "ssh_username": "foo", - "memory": 64, - "disk_size": 256, - "disk_block_size": 1, - "guest_additions_mode": "none", - "disk_additional_size": "50000,40000,30000", - common.BuildNameConfigKey: "foo", - } -} - -func TestBuilder_ImplementsBuilder(t *testing.T) { - var raw interface{} - raw = &Builder{} - if _, ok := raw.(packersdk.Builder); !ok { - t.Error("Builder must implement builder.") - } -} - -func TestBuilderPrepare_Defaults(t *testing.T) { - var b Builder - config := testConfig() - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if b.config.VMName != "packer-foo" { - t.Errorf("bad vm name: %s", b.config.VMName) - } -} - -func TestBuilderPrepare_DiskSize(t *testing.T) { - var b Builder - config := testConfig() - - delete(config, "disk_size") - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("bad err: %s", err) - } - - if b.config.DiskSize != 40*1024 { - t.Fatalf("bad size: %d", b.config.DiskSize) - } - - config["disk_size"] = 256 - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if b.config.DiskSize != 256 { - t.Fatalf("bad size: %d", b.config.DiskSize) - } -} - -func TestBuilderPrepare_DiskBlockSize(t *testing.T) { - var b Builder - config := testConfig() - expected_default_block_size := uint(32) - expected_min_block_size := uint(0) - expected_max_block_size := uint(256) - - // Test default with empty disk_block_size - delete(config, "disk_block_size") - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("bad err: %s", err) - } - if b.config.DiskBlockSize != expected_default_block_size { - t.Fatalf("bad default block size with empty config: %d. Expected %d", b.config.DiskBlockSize, - expected_default_block_size) - } - - test_sizes := []uint{0, 1, 32, 256, 512, 1 * 1024, 32 * 1024} - for _, test_size := range test_sizes { - config["disk_block_size"] = test_size - b = Builder{} - _, warns, err = b.Prepare(config) - if test_size > expected_max_block_size || test_size < expected_min_block_size { - if len(warns) > 0 { - t.Fatalf("bad, should have no warns: %#v", warns) - } - if err == nil { - t.Fatalf("bad, should have error. disk_block_size=%d outside expected valid range [%d,%d]", - test_size, expected_min_block_size, expected_max_block_size) - } - } else { - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("bad, should not have error: %s", err) - } - if test_size == 0 { - if b.config.DiskBlockSize != expected_default_block_size { - t.Fatalf("bad default block size with 0 value config: %d. Expected: %d", - b.config.DiskBlockSize, expected_default_block_size) - } - } else { - if b.config.DiskBlockSize != test_size { - t.Fatalf("bad block size with 0 value config: %d. Expected: %d", b.config.DiskBlockSize, - expected_default_block_size) - } - } - } - } -} - -func TestBuilderPrepare_FixedVHDFormat(t *testing.T) { - var b Builder - config := testConfig() - config["use_fixed_vhd_format"] = true - config["generation"] = 1 - config["skip_compaction"] = true - config["differencing_disk"] = false - - // use_fixed_vhd_format should work with generation = 1, skip_compaction - // = true, and differencing_disk = false - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("bad err: %s", err) - } - - //use_fixed_vhd_format should not work with differencing_disk = true - config["differencing_disk"] = true - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - config["differencing_disk"] = false - - //use_fixed_vhd_format should not work with skip_compaction = false - config["skip_compaction"] = false - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - config["skip_compaction"] = true - - //use_fixed_vhd_format should not work with generation = 2 - config["generation"] = 2 - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } -} - -func TestBuilderPrepare_FloppyFiles(t *testing.T) { - var b Builder - config := testConfig() - - delete(config, "floppy_files") - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("bad err: %s", err) - } - - if len(b.config.FloppyFiles) != 0 { - t.Fatalf("bad: %#v", b.config.FloppyFiles) - } - - floppiesPath := "../../test-fixtures/floppies" - config["floppy_files"] = []string{fmt.Sprintf("%s/bar.bat", floppiesPath), fmt.Sprintf("%s/foo.ps1", floppiesPath)} - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - expected := []string{fmt.Sprintf("%s/bar.bat", floppiesPath), fmt.Sprintf("%s/foo.ps1", floppiesPath)} - if !reflect.DeepEqual(b.config.FloppyFiles, expected) { - t.Fatalf("bad: %#v", b.config.FloppyFiles) - } -} - -func TestBuilderPrepare_InvalidFloppies(t *testing.T) { - var b Builder - config := testConfig() - config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"} - b = Builder{} - _, _, errs := b.Prepare(config) - if errs == nil { - t.Fatalf("Nonexistent floppies should trigger multierror") - } - - if len(errs.(*packersdk.MultiError).Errors) != 2 { - t.Fatalf("Multierror should work and report 2 errors") - } -} - -func TestBuilderPrepare_InvalidKey(t *testing.T) { - var b Builder - config := testConfig() - - // Add a random key - config["i_should_not_be_valid"] = true - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } -} - -func TestBuilderPrepare_ISOChecksum(t *testing.T) { - var b Builder - config := testConfig() - - // Test bad - config["iso_checksum"] = "" - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - - // Test invalid checksum - config["iso_checksum"] = "FOo" - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - - // Test good - config["iso_checksum"] = "md5:0B0F137F17AC10944716020B018F8126" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - -} - -func TestBuilderPrepare_ISOChecksumType(t *testing.T) { - var b Builder - config := testConfig() - - config["iso_checksum"] = "0B0F137F17AC10944716020B018F8126" - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - // Test good - config["iso_checksum"] = "mD5:0B0F137F17AC10944716020B018F8126" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - // Test unknown - config["iso_checksum"] = "fake:foo" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Log("should error in prepare but go-getter doesn't let us validate yet. This will fail before dl.") - } - - // Test none - config["iso_checksum"] = "none" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) == 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } -} - -func TestBuilderPrepare_ISOUrl(t *testing.T) { - var b Builder - config := testConfig() - delete(config, "iso_url") - delete(config, "iso_urls") - - // Test both empty - config["iso_url"] = "" - b = Builder{} - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - - // Test iso_url set - config["iso_url"] = "http://www.packer.io" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Errorf("should not have error: %s", err) - } - - expected := []string{"http://www.packer.io"} - if !reflect.DeepEqual(b.config.ISOUrls, expected) { - t.Fatalf("bad: %#v", b.config.ISOUrls) - } - - // Test both set - config["iso_url"] = "http://www.packer.io" - config["iso_urls"] = []string{"http://www.packer.io"} - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - - // Test just iso_urls set - delete(config, "iso_url") - config["iso_urls"] = []string{ - "http://www.packer.io", - "http://www.hashicorp.com", - } - - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Errorf("should not have error: %s", err) - } - - expected = []string{ - "http://www.packer.io", - "http://www.hashicorp.com", - } - if !reflect.DeepEqual(b.config.ISOUrls, expected) { - t.Fatalf("bad: %#v", b.config.ISOUrls) - } -} - -func TestBuilderPrepare_SizeNotRequiredWhenUsingExistingHarddrive(t *testing.T) { - var b Builder - config := testConfig() - delete(config, "iso_url") - delete(config, "iso_urls") - delete(config, "disk_size") - - config["disk_size"] = 1 - - // Test just iso_urls set but with vhdx - delete(config, "iso_url") - config["iso_urls"] = []string{ - "http://www.packer.io/hdd.vhdx", - "http://www.hashicorp.com/dvd.iso", - } - - b = Builder{} - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Errorf("should not have error: %s", err) - } - - expected := []string{ - "http://www.packer.io/hdd.vhdx", - "http://www.hashicorp.com/dvd.iso", - } - if !reflect.DeepEqual(b.config.ISOUrls, expected) { - t.Fatalf("bad: %#v", b.config.ISOUrls) - } - - // Test just iso_urls set but with vhd - delete(config, "iso_url") - config["iso_urls"] = []string{ - "http://www.packer.io/hdd.vhd", - "http://www.hashicorp.com/dvd.iso", - } - - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Errorf("should not have error: %s", err) - } - - expected = []string{ - "http://www.packer.io/hdd.vhd", - "http://www.hashicorp.com/dvd.iso", - } - if !reflect.DeepEqual(b.config.ISOUrls, expected) { - t.Fatalf("bad: %#v", b.config.ISOUrls) - } -} - -func TestBuilderPrepare_SizeIsRequiredWhenNotUsingExistingHarddrive(t *testing.T) { - var b Builder - config := testConfig() - delete(config, "iso_url") - delete(config, "iso_urls") - delete(config, "disk_size") - - config["disk_size"] = 1 - - // Test just iso_urls set but with vhdx - delete(config, "iso_url") - config["iso_urls"] = []string{ - "http://www.packer.io/os.iso", - "http://www.hashicorp.com/dvd.iso", - } - - b = Builder{} - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Errorf("should have error") - } - - expected := []string{ - "http://www.packer.io/os.iso", - "http://www.hashicorp.com/dvd.iso", - } - if !reflect.DeepEqual(b.config.ISOUrls, expected) { - t.Fatalf("bad: %#v", b.config.ISOUrls) - } -} - -func TestBuilderPrepare_MaximumOfSixtyFourAdditionalDisks(t *testing.T) { - var b Builder - config := testConfig() - - disks := make([]string, 65) - for i := range disks { - disks[i] = strconv.Itoa(i) - } - config["disk_additional_size"] = disks - - b = Builder{} - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Errorf("should have error") - } - -} - -func TestBuilderPrepare_CommConfig(t *testing.T) { - // Test Winrm - { - config := testConfig() - config["communicator"] = "winrm" - config["winrm_username"] = "username" - config["winrm_password"] = "password" - config["winrm_host"] = "1.2.3.4" - - var b Builder - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if b.config.Comm.WinRMUser != "username" { - t.Errorf("bad winrm_username: %s", b.config.Comm.WinRMUser) - } - if b.config.Comm.WinRMPassword != "password" { - t.Errorf("bad winrm_password: %s", b.config.Comm.WinRMPassword) - } - if host := b.config.Comm.Host(); host != "1.2.3.4" { - t.Errorf("bad host: %s", host) - } - } - - // Test SSH - { - config := testConfig() - config["communicator"] = "ssh" - config["ssh_username"] = "username" - config["ssh_password"] = "password" - config["ssh_host"] = "1.2.3.4" - - var b Builder - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if b.config.Comm.SSHUsername != "username" { - t.Errorf("bad ssh_username: %s", b.config.Comm.SSHUsername) - } - if b.config.Comm.SSHPassword != "password" { - t.Errorf("bad ssh_password: %s", b.config.Comm.SSHPassword) - } - if host := b.config.Comm.Host(); host != "1.2.3.4" { - t.Errorf("bad host: %s", host) - } - } - -} - -func TestUserVariablesInBootCommand(t *testing.T) { - var b Builder - config := testConfig() - - config[common.UserVariablesConfigKey] = map[string]string{"test-variable": "test"} - config["boot_command"] = []string{"blah {{user `test-variable`}} blah"} - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - ui := packersdk.TestUi(t) - hook := &packersdk.MockHook{} - driver := &hypervcommon.DriverMock{} - - // Set up the state. - state := new(multistep.BasicStateBag) - state.Put("config", &b.config) - state.Put("driver", driver) - state.Put("hook", hook) - state.Put("http_port", 0) - state.Put("http_ip", "0.0.0.0") - state.Put("ui", ui) - state.Put("vmName", "packer-foo") - - step := &hypervcommon.StepTypeBootCommand{ - BootCommand: b.config.FlatBootCommand(), - SwitchName: b.config.SwitchName, - Ctx: b.config.ctx, - } - - ret := step.Run(context.Background(), state) - if ret != multistep.ActionContinue { - t.Fatalf("should not have error: %#v", ret) - } -} - -func TestBuilderPrepare_UseLegacyNetworkAdapter(t *testing.T) { - var b Builder - config := testConfig() - - // should be allowed for default config - config["use_legacy_network_adapter"] = true - - b = Builder{} - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Errorf("should not have error: %s", err) - } - - // should not be allowed for gen 2 - config["generation"] = 2 - - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } -} diff --git a/builder/hyperv/version/version.go b/builder/hyperv/version/version.go deleted file mode 100644 index 86482937a..000000000 --- a/builder/hyperv/version/version.go +++ /dev/null @@ -1,13 +0,0 @@ -package version - -import ( - "github.com/hashicorp/packer-plugin-sdk/version" - packerVersion "github.com/hashicorp/packer/version" -) - -var HypervPluginVersion *version.PluginVersion - -func init() { - HypervPluginVersion = version.InitializePluginVersion( - packerVersion.Version, packerVersion.VersionPrerelease) -} diff --git a/builder/hyperv/vmcx/builder.go b/builder/hyperv/vmcx/builder.go deleted file mode 100644 index 5cc4c28fb..000000000 --- a/builder/hyperv/vmcx/builder.go +++ /dev/null @@ -1,397 +0,0 @@ -//go:generate packer-sdc struct-markdown -//go:generate packer-sdc mapstructure-to-hcl2 -type Config - -package vmcx - -import ( - "context" - "errors" - "fmt" - "os" - "strings" - - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/hashicorp/packer-plugin-sdk/bootcommand" - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/communicator" - "github.com/hashicorp/packer-plugin-sdk/multistep" - "github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - "github.com/hashicorp/packer-plugin-sdk/shutdowncommand" - "github.com/hashicorp/packer-plugin-sdk/template/config" - "github.com/hashicorp/packer-plugin-sdk/template/interpolate" - hypervcommon "github.com/hashicorp/packer/builder/hyperv/common" - powershell "github.com/hashicorp/packer/builder/hyperv/common/powershell" -) - -const ( - DefaultRamSize = 1 * 1024 // 1GB - MinRamSize = 32 // 32MB - MaxRamSize = 1024 * 1024 // 1TB - MinNestedVirtualizationRamSize = 4 * 1024 // 4GB - - LowRam = 256 // 256MB - - DefaultUsername = "" - DefaultPassword = "" -) - -// Builder implements packersdk.Builder and builds the actual Hyperv -// images. -type Builder struct { - config Config - runner multistep.Runner -} - -type Config struct { - common.PackerConfig `mapstructure:",squash"` - commonsteps.HTTPConfig `mapstructure:",squash"` - commonsteps.ISOConfig `mapstructure:",squash"` - bootcommand.BootConfig `mapstructure:",squash"` - hypervcommon.OutputConfig `mapstructure:",squash"` - hypervcommon.SSHConfig `mapstructure:",squash"` - hypervcommon.CommonConfig `mapstructure:",squash"` - shutdowncommand.ShutdownConfig `mapstructure:",squash"` - - // This is the path to a directory containing an exported virtual machine. - CloneFromVMCXPath string `mapstructure:"clone_from_vmcx_path"` - // This is the name of the virtual machine to clone from. - CloneFromVMName string `mapstructure:"clone_from_vm_name"` - // The name of a snapshot in the - // source machine to use as a starting point for the clone. If the value - // given is an empty string, the last snapshot present in the source will - // be chosen as the starting point for the new VM. - CloneFromSnapshotName string `mapstructure:"clone_from_snapshot_name" required:"false"` - // If set to true all snapshots - // present in the source machine will be copied when the machine is - // cloned. The final result of the build will be an exported virtual - // machine that contains all the snapshots of the parent. - CloneAllSnapshots bool `mapstructure:"clone_all_snapshots" required:"false"` - // If true enables differencing disks. Only - // the changes will be written to the new disk. This is especially useful if - // your source is a VHD/VHDX. This defaults to false. - DifferencingDisk bool `mapstructure:"differencing_disk" required:"false"` - // When cloning a vm to build from, we run a powershell - // Compare-VM command, which, depending on your version of Windows, may need - // the "Copy" flag to be set to true or false. Defaults to "false". Command: - CompareCopy bool `mapstructure:"copy_in_compare" required:"false"` - - ctx interpolate.Context -} - -func (b *Builder) ConfigSpec() hcldec.ObjectSpec { return b.config.FlatMapstructure().HCL2Spec() } - -func (b *Builder) Prepare(raws ...interface{}) ([]string, []string, error) { - err := config.Decode(&b.config, &config.DecodeOpts{ - PluginType: hypervcommon.BuilderId, - Interpolate: true, - InterpolateContext: &b.config.ctx, - InterpolateFilter: &interpolate.RenderFilter{ - Exclude: []string{ - "boot_command", - }, - }, - }, raws...) - if err != nil { - return nil, nil, err - } - - // Accumulate any errors and warnings - var errs *packersdk.MultiError - warnings := make([]string, 0) - - if b.config.RawSingleISOUrl != "" || len(b.config.ISOUrls) > 0 { - isoWarnings, isoErrs := b.config.ISOConfig.Prepare(&b.config.ctx) - warnings = append(warnings, isoWarnings...) - errs = packersdk.MultiErrorAppend(errs, isoErrs...) - } - - errs = packersdk.MultiErrorAppend(errs, b.config.BootConfig.Prepare(&b.config.ctx)...) - errs = packersdk.MultiErrorAppend(errs, b.config.HTTPConfig.Prepare(&b.config.ctx)...) - errs = packersdk.MultiErrorAppend(errs, b.config.OutputConfig.Prepare(&b.config.ctx, &b.config.PackerConfig)...) - errs = packersdk.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...) - errs = packersdk.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...) - - commonErrs, commonWarns := b.config.CommonConfig.Prepare(&b.config.ctx, &b.config.PackerConfig) - errs = packersdk.MultiErrorAppend(errs, commonErrs...) - warnings = append(warnings, commonWarns...) - - if b.config.Cpu < 1 { - b.config.Cpu = 1 - } - - if b.config.CloneFromVMName == "" { - if b.config.CloneFromVMCXPath == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The clone_from_vm_name must be specified if "+ - "clone_from_vmcx_path is not specified.")) - } - } else { - virtualMachineExists, err := powershell.DoesVirtualMachineExist(b.config.CloneFromVMName) - if err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Failed detecting if virtual machine to clone "+ - "from exists: %s", err)) - } else { - if !virtualMachineExists { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Virtual machine '%s' to clone from does not "+ - "exist.", b.config.CloneFromVMName)) - } else { - b.config.Generation, err = powershell.GetVirtualMachineGeneration(b.config.CloneFromVMName) - if err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Failed detecting virtual machine to clone "+ - "from generation: %s", err)) - } - - if b.config.CloneFromSnapshotName != "" { - virtualMachineSnapshotExists, err := powershell.DoesVirtualMachineSnapshotExist( - b.config.CloneFromVMName, b.config.CloneFromSnapshotName) - if err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Failed detecting if virtual machine "+ - "snapshot to clone from exists: %s", err)) - } else { - if !virtualMachineSnapshotExists { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Virtual machine snapshot '%s' on "+ - "virtual machine '%s' to clone from does not exist.", - b.config.CloneFromSnapshotName, b.config.CloneFromVMName)) - } - } - } - - virtualMachineOn, err := powershell.IsVirtualMachineOn(b.config.CloneFromVMName) - if err != nil { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Failed detecting if virtual machine to "+ - "clone is running: %s", err)) - } else { - if virtualMachineOn { - warning := fmt.Sprintf("Cloning from a virtual machine that is running.") - warnings = hypervcommon.Appendwarns(warnings, warning) - } - } - } - } - } - - if b.config.CloneFromVMCXPath == "" { - if b.config.CloneFromVMName == "" { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("The clone_from_vmcx_path be specified if "+ - "clone_from_vm_name must is not specified.")) - } - } else { - if _, err := os.Stat(b.config.CloneFromVMCXPath); os.IsNotExist(err) { - if err != nil { - errs = packersdk.MultiErrorAppend( - errs, fmt.Errorf("CloneFromVMCXPath does not exist: %s", err)) - } - } - if strings.HasSuffix(strings.ToLower(b.config.CloneFromVMCXPath), ".vmcx") { - // User has provided the vmcx file itself rather than the containing - // folder. - if strings.Contains(b.config.CloneFromVMCXPath, "Virtual Machines") { - keep := strings.Split(b.config.CloneFromVMCXPath, "Virtual Machines") - b.config.CloneFromVMCXPath = keep[0] - } else { - errs = packersdk.MultiErrorAppend(errs, fmt.Errorf("Unable to "+ - "parse the clone_from_vmcx_path to find the vm directory. "+ - "Please provide the path to the folder containing the "+ - "vmcx file, not the file itself. Example: instead of "+ - "C:\\path\\to\\output-hyperv-iso\\Virtual Machines\\filename.vmcx"+ - ", provide C:\\path\\to\\output-hyperv-iso\\.")) - } - } - } - - // Warnings - - if b.config.ShutdownCommand == "" { - warnings = hypervcommon.Appendwarns(warnings, - "A shutdown_command was not specified. Without a shutdown command, Packer\n"+ - "will forcibly halt the virtual machine, which may result in data loss.") - } - - if errs != nil && len(errs.Errors) > 0 { - return nil, warnings, errs - } - - return nil, warnings, nil -} - -// Run executes a Packer build and returns a packersdk.Artifact representing -// a Hyperv appliance. -func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook) (packersdk.Artifact, error) { - // Create the driver that we'll use to communicate with Hyperv - driver, err := hypervcommon.NewHypervPS4Driver() - if err != nil { - return nil, fmt.Errorf("Failed creating Hyper-V driver: %s", err) - } - - // Set up the state. - state := new(multistep.BasicStateBag) - state.Put("debug", b.config.PackerDebug) - state.Put("driver", driver) - state.Put("hook", hook) - state.Put("ui", ui) - - steps := []multistep.Step{ - &hypervcommon.StepCreateBuildDir{ - TempPath: b.config.TempPath, - }, - &commonsteps.StepOutputDir{ - Force: b.config.PackerForce, - Path: b.config.OutputDir, - }, - &commonsteps.StepDownload{ - Checksum: b.config.ISOChecksum, - Description: "ISO", - ResultKey: "iso_path", - Url: b.config.ISOUrls, - Extension: b.config.TargetExtension, - TargetPath: b.config.TargetPath, - }, - &commonsteps.StepCreateFloppy{ - Files: b.config.FloppyFiles, - Directories: b.config.FloppyConfig.FloppyDirectories, - Label: b.config.FloppyConfig.FloppyLabel, - }, - commonsteps.HTTPServerFromHTTPConfig(&b.config.HTTPConfig), - &hypervcommon.StepCreateSwitch{ - SwitchName: b.config.SwitchName, - }, - &hypervcommon.StepCloneVM{ - CloneFromVMCXPath: b.config.CloneFromVMCXPath, - CloneFromVMName: b.config.CloneFromVMName, - CloneFromSnapshotName: b.config.CloneFromSnapshotName, - CloneAllSnapshots: b.config.CloneAllSnapshots, - VMName: b.config.VMName, - SwitchName: b.config.SwitchName, - CompareCopy: b.config.CompareCopy, - RamSize: b.config.RamSize, - Cpu: b.config.Cpu, - EnableMacSpoofing: b.config.EnableMacSpoofing, - EnableDynamicMemory: b.config.EnableDynamicMemory, - EnableSecureBoot: b.config.EnableSecureBoot, - SecureBootTemplate: b.config.SecureBootTemplate, - EnableVirtualizationExtensions: b.config.EnableVirtualizationExtensions, - MacAddress: b.config.MacAddress, - KeepRegistered: b.config.KeepRegistered, - AdditionalDiskSize: b.config.AdditionalDiskSize, - DiskBlockSize: b.config.DiskBlockSize, - }, - - &hypervcommon.StepEnableIntegrationService{}, - - &hypervcommon.StepMountDvdDrive{ - Generation: b.config.Generation, - FirstBootDevice: b.config.FirstBootDevice, - }, - &hypervcommon.StepMountFloppydrive{ - Generation: b.config.Generation, - }, - - &hypervcommon.StepMountGuestAdditions{ - GuestAdditionsMode: b.config.GuestAdditionsMode, - GuestAdditionsPath: b.config.GuestAdditionsPath, - Generation: b.config.Generation, - }, - &commonsteps.StepCreateCD{ - Files: b.config.CDConfig.CDFiles, - Label: b.config.CDConfig.CDLabel, - }, - &hypervcommon.StepMountSecondaryDvdImages{ - IsoPaths: b.config.SecondaryDvdImages, - Generation: b.config.Generation, - }, - - &hypervcommon.StepConfigureVlan{ - VlanId: b.config.VlanId, - SwitchVlanId: b.config.SwitchVlanId, - }, - - &hypervcommon.StepSetBootOrder{ - BootOrder: b.config.BootOrder, - }, - &hypervcommon.StepSetFirstBootDevice{ - Generation: b.config.Generation, - FirstBootDevice: b.config.FirstBootDevice, - }, - - &hypervcommon.StepRun{ - Headless: b.config.Headless, - SwitchName: b.config.SwitchName, - }, - - &hypervcommon.StepTypeBootCommand{ - BootCommand: b.config.FlatBootCommand(), - BootWait: b.config.BootWait, - SwitchName: b.config.SwitchName, - Ctx: b.config.ctx, - GroupInterval: b.config.BootConfig.BootGroupInterval, - }, - - // configure the communicator ssh, winrm - &communicator.StepConnect{ - Config: &b.config.SSHConfig.Comm, - Host: hypervcommon.CommHost(b.config.SSHConfig.Comm.Host()), - SSHConfig: b.config.SSHConfig.Comm.SSHConfigFunc(), - }, - - // provision requires communicator to be setup - &commonsteps.StepProvision{}, - - // Remove ephemeral SSH keys, if using - &commonsteps.StepCleanupTempKeys{ - Comm: &b.config.SSHConfig.Comm, - }, - - &hypervcommon.StepShutdown{ - Command: b.config.ShutdownCommand, - Timeout: b.config.ShutdownTimeout, - }, - - // wait for the vm to be powered off - &hypervcommon.StepWaitForPowerOff{}, - - // remove the secondary dvd images - // after we power down - &hypervcommon.StepUnmountSecondaryDvdImages{}, - &hypervcommon.StepUnmountGuestAdditions{}, - &hypervcommon.StepUnmountDvdDrive{}, - &hypervcommon.StepUnmountFloppyDrive{ - Generation: b.config.Generation, - }, - &hypervcommon.StepCompactDisk{ - SkipCompaction: b.config.SkipCompaction, - }, - &hypervcommon.StepExportVm{ - OutputDir: b.config.OutputDir, - SkipExport: b.config.SkipExport, - }, - &hypervcommon.StepCollateArtifacts{ - OutputDir: b.config.OutputDir, - SkipExport: b.config.SkipExport, - }, - } - - // the clean up actions for each step will be executed reverse order - - // Run the steps. - b.runner = commonsteps.NewRunner(steps, b.config.PackerConfig, ui) - b.runner.Run(ctx, state) - - // Report any errors. - if rawErr, ok := state.GetOk("error"); ok { - return nil, rawErr.(error) - } - - // If we were interrupted or cancelled, then just exit. - if _, ok := state.GetOk(multistep.StateCancelled); ok { - return nil, errors.New("Build was cancelled.") - } - - if _, ok := state.GetOk(multistep.StateHalted); ok { - return nil, errors.New("Build was halted.") - } - - generatedData := map[string]interface{}{"generated_data": state.Get("generated_data")} - return hypervcommon.NewArtifact(b.config.OutputDir, generatedData) -} - -// Cancel. diff --git a/builder/hyperv/vmcx/builder.hcl2spec.go b/builder/hyperv/vmcx/builder.hcl2spec.go deleted file mode 100644 index e2a64d05d..000000000 --- a/builder/hyperv/vmcx/builder.hcl2spec.go +++ /dev/null @@ -1,251 +0,0 @@ -// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT. - -package vmcx - -import ( - "github.com/hashicorp/hcl/v2/hcldec" - "github.com/zclconf/go-cty/cty" -) - -// FlatConfig is an auto-generated flat version of Config. -// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up. -type FlatConfig struct { - PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"` - PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"` - PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"` - PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"` - PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"` - PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"` - PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"` - PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"` - HTTPDir *string `mapstructure:"http_directory" cty:"http_directory" hcl:"http_directory"` - HTTPContent map[string]string `mapstructure:"http_content" cty:"http_content" hcl:"http_content"` - HTTPPortMin *int `mapstructure:"http_port_min" cty:"http_port_min" hcl:"http_port_min"` - HTTPPortMax *int `mapstructure:"http_port_max" cty:"http_port_max" hcl:"http_port_max"` - HTTPAddress *string `mapstructure:"http_bind_address" cty:"http_bind_address" hcl:"http_bind_address"` - HTTPInterface *string `mapstructure:"http_interface" undocumented:"true" cty:"http_interface" hcl:"http_interface"` - ISOChecksum *string `mapstructure:"iso_checksum" required:"true" cty:"iso_checksum" hcl:"iso_checksum"` - RawSingleISOUrl *string `mapstructure:"iso_url" required:"true" cty:"iso_url" hcl:"iso_url"` - ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"` - TargetPath *string `mapstructure:"iso_target_path" cty:"iso_target_path" hcl:"iso_target_path"` - TargetExtension *string `mapstructure:"iso_target_extension" cty:"iso_target_extension" hcl:"iso_target_extension"` - BootGroupInterval *string `mapstructure:"boot_keygroup_interval" cty:"boot_keygroup_interval" hcl:"boot_keygroup_interval"` - BootWait *string `mapstructure:"boot_wait" cty:"boot_wait" hcl:"boot_wait"` - BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"` - OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"` - Type *string `mapstructure:"communicator" cty:"communicator" hcl:"communicator"` - PauseBeforeConnect *string `mapstructure:"pause_before_connecting" cty:"pause_before_connecting" hcl:"pause_before_connecting"` - SSHHost *string `mapstructure:"ssh_host" cty:"ssh_host" hcl:"ssh_host"` - SSHPort *int `mapstructure:"ssh_port" cty:"ssh_port" hcl:"ssh_port"` - SSHUsername *string `mapstructure:"ssh_username" cty:"ssh_username" hcl:"ssh_username"` - SSHPassword *string `mapstructure:"ssh_password" cty:"ssh_password" hcl:"ssh_password"` - SSHKeyPairName *string `mapstructure:"ssh_keypair_name" undocumented:"true" cty:"ssh_keypair_name" hcl:"ssh_keypair_name"` - SSHTemporaryKeyPairName *string `mapstructure:"temporary_key_pair_name" undocumented:"true" cty:"temporary_key_pair_name" hcl:"temporary_key_pair_name"` - SSHTemporaryKeyPairType *string `mapstructure:"temporary_key_pair_type" cty:"temporary_key_pair_type" hcl:"temporary_key_pair_type"` - SSHTemporaryKeyPairBits *int `mapstructure:"temporary_key_pair_bits" cty:"temporary_key_pair_bits" hcl:"temporary_key_pair_bits"` - SSHCiphers []string `mapstructure:"ssh_ciphers" cty:"ssh_ciphers" hcl:"ssh_ciphers"` - SSHClearAuthorizedKeys *bool `mapstructure:"ssh_clear_authorized_keys" cty:"ssh_clear_authorized_keys" hcl:"ssh_clear_authorized_keys"` - SSHKEXAlgos []string `mapstructure:"ssh_key_exchange_algorithms" cty:"ssh_key_exchange_algorithms" hcl:"ssh_key_exchange_algorithms"` - SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" undocumented:"true" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"` - SSHCertificateFile *string `mapstructure:"ssh_certificate_file" cty:"ssh_certificate_file" hcl:"ssh_certificate_file"` - SSHPty *bool `mapstructure:"ssh_pty" cty:"ssh_pty" hcl:"ssh_pty"` - SSHTimeout *string `mapstructure:"ssh_timeout" cty:"ssh_timeout" hcl:"ssh_timeout"` - SSHWaitTimeout *string `mapstructure:"ssh_wait_timeout" undocumented:"true" cty:"ssh_wait_timeout" hcl:"ssh_wait_timeout"` - SSHAgentAuth *bool `mapstructure:"ssh_agent_auth" undocumented:"true" cty:"ssh_agent_auth" hcl:"ssh_agent_auth"` - SSHDisableAgentForwarding *bool `mapstructure:"ssh_disable_agent_forwarding" cty:"ssh_disable_agent_forwarding" hcl:"ssh_disable_agent_forwarding"` - SSHHandshakeAttempts *int `mapstructure:"ssh_handshake_attempts" cty:"ssh_handshake_attempts" hcl:"ssh_handshake_attempts"` - SSHBastionHost *string `mapstructure:"ssh_bastion_host" cty:"ssh_bastion_host" hcl:"ssh_bastion_host"` - SSHBastionPort *int `mapstructure:"ssh_bastion_port" cty:"ssh_bastion_port" hcl:"ssh_bastion_port"` - SSHBastionAgentAuth *bool `mapstructure:"ssh_bastion_agent_auth" cty:"ssh_bastion_agent_auth" hcl:"ssh_bastion_agent_auth"` - SSHBastionUsername *string `mapstructure:"ssh_bastion_username" cty:"ssh_bastion_username" hcl:"ssh_bastion_username"` - SSHBastionPassword *string `mapstructure:"ssh_bastion_password" cty:"ssh_bastion_password" hcl:"ssh_bastion_password"` - SSHBastionInteractive *bool `mapstructure:"ssh_bastion_interactive" cty:"ssh_bastion_interactive" hcl:"ssh_bastion_interactive"` - SSHBastionPrivateKeyFile *string `mapstructure:"ssh_bastion_private_key_file" cty:"ssh_bastion_private_key_file" hcl:"ssh_bastion_private_key_file"` - SSHBastionCertificateFile *string `mapstructure:"ssh_bastion_certificate_file" cty:"ssh_bastion_certificate_file" hcl:"ssh_bastion_certificate_file"` - SSHFileTransferMethod *string `mapstructure:"ssh_file_transfer_method" cty:"ssh_file_transfer_method" hcl:"ssh_file_transfer_method"` - SSHProxyHost *string `mapstructure:"ssh_proxy_host" cty:"ssh_proxy_host" hcl:"ssh_proxy_host"` - SSHProxyPort *int `mapstructure:"ssh_proxy_port" cty:"ssh_proxy_port" hcl:"ssh_proxy_port"` - SSHProxyUsername *string `mapstructure:"ssh_proxy_username" cty:"ssh_proxy_username" hcl:"ssh_proxy_username"` - SSHProxyPassword *string `mapstructure:"ssh_proxy_password" cty:"ssh_proxy_password" hcl:"ssh_proxy_password"` - SSHKeepAliveInterval *string `mapstructure:"ssh_keep_alive_interval" cty:"ssh_keep_alive_interval" hcl:"ssh_keep_alive_interval"` - SSHReadWriteTimeout *string `mapstructure:"ssh_read_write_timeout" cty:"ssh_read_write_timeout" hcl:"ssh_read_write_timeout"` - SSHRemoteTunnels []string `mapstructure:"ssh_remote_tunnels" cty:"ssh_remote_tunnels" hcl:"ssh_remote_tunnels"` - SSHLocalTunnels []string `mapstructure:"ssh_local_tunnels" cty:"ssh_local_tunnels" hcl:"ssh_local_tunnels"` - SSHPublicKey []byte `mapstructure:"ssh_public_key" undocumented:"true" cty:"ssh_public_key" hcl:"ssh_public_key"` - SSHPrivateKey []byte `mapstructure:"ssh_private_key" undocumented:"true" cty:"ssh_private_key" hcl:"ssh_private_key"` - WinRMUser *string `mapstructure:"winrm_username" cty:"winrm_username" hcl:"winrm_username"` - WinRMPassword *string `mapstructure:"winrm_password" cty:"winrm_password" hcl:"winrm_password"` - WinRMHost *string `mapstructure:"winrm_host" cty:"winrm_host" hcl:"winrm_host"` - WinRMNoProxy *bool `mapstructure:"winrm_no_proxy" cty:"winrm_no_proxy" hcl:"winrm_no_proxy"` - WinRMPort *int `mapstructure:"winrm_port" cty:"winrm_port" hcl:"winrm_port"` - WinRMTimeout *string `mapstructure:"winrm_timeout" cty:"winrm_timeout" hcl:"winrm_timeout"` - WinRMUseSSL *bool `mapstructure:"winrm_use_ssl" cty:"winrm_use_ssl" hcl:"winrm_use_ssl"` - WinRMInsecure *bool `mapstructure:"winrm_insecure" cty:"winrm_insecure" hcl:"winrm_insecure"` - WinRMUseNTLM *bool `mapstructure:"winrm_use_ntlm" cty:"winrm_use_ntlm" hcl:"winrm_use_ntlm"` - FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"` - FloppyDirectories []string `mapstructure:"floppy_dirs" cty:"floppy_dirs" hcl:"floppy_dirs"` - FloppyLabel *string `mapstructure:"floppy_label" cty:"floppy_label" hcl:"floppy_label"` - CDFiles []string `mapstructure:"cd_files" cty:"cd_files" hcl:"cd_files"` - CDLabel *string `mapstructure:"cd_label" cty:"cd_label" hcl:"cd_label"` - DiskBlockSize *uint `mapstructure:"disk_block_size" required:"false" cty:"disk_block_size" hcl:"disk_block_size"` - RamSize *uint `mapstructure:"memory" required:"false" cty:"memory" hcl:"memory"` - SecondaryDvdImages []string `mapstructure:"secondary_iso_images" required:"false" cty:"secondary_iso_images" hcl:"secondary_iso_images"` - AdditionalDiskSize []uint `mapstructure:"disk_additional_size" required:"false" cty:"disk_additional_size" hcl:"disk_additional_size"` - GuestAdditionsMode *string `mapstructure:"guest_additions_mode" required:"false" cty:"guest_additions_mode" hcl:"guest_additions_mode"` - GuestAdditionsPath *string `mapstructure:"guest_additions_path" required:"false" cty:"guest_additions_path" hcl:"guest_additions_path"` - VMName *string `mapstructure:"vm_name" required:"false" cty:"vm_name" hcl:"vm_name"` - SwitchName *string `mapstructure:"switch_name" required:"false" cty:"switch_name" hcl:"switch_name"` - SwitchVlanId *string `mapstructure:"switch_vlan_id" required:"false" cty:"switch_vlan_id" hcl:"switch_vlan_id"` - MacAddress *string `mapstructure:"mac_address" required:"false" cty:"mac_address" hcl:"mac_address"` - VlanId *string `mapstructure:"vlan_id" required:"false" cty:"vlan_id" hcl:"vlan_id"` - Cpu *uint `mapstructure:"cpus" required:"false" cty:"cpus" hcl:"cpus"` - Generation *uint `mapstructure:"generation" required:"false" cty:"generation" hcl:"generation"` - EnableMacSpoofing *bool `mapstructure:"enable_mac_spoofing" required:"false" cty:"enable_mac_spoofing" hcl:"enable_mac_spoofing"` - EnableDynamicMemory *bool `mapstructure:"enable_dynamic_memory" required:"false" cty:"enable_dynamic_memory" hcl:"enable_dynamic_memory"` - EnableSecureBoot *bool `mapstructure:"enable_secure_boot" required:"false" cty:"enable_secure_boot" hcl:"enable_secure_boot"` - SecureBootTemplate *string `mapstructure:"secure_boot_template" required:"false" cty:"secure_boot_template" hcl:"secure_boot_template"` - EnableVirtualizationExtensions *bool `mapstructure:"enable_virtualization_extensions" required:"false" cty:"enable_virtualization_extensions" hcl:"enable_virtualization_extensions"` - TempPath *string `mapstructure:"temp_path" required:"false" cty:"temp_path" hcl:"temp_path"` - Version *string `mapstructure:"configuration_version" required:"false" cty:"configuration_version" hcl:"configuration_version"` - KeepRegistered *bool `mapstructure:"keep_registered" required:"false" cty:"keep_registered" hcl:"keep_registered"` - SkipCompaction *bool `mapstructure:"skip_compaction" required:"false" cty:"skip_compaction" hcl:"skip_compaction"` - SkipExport *bool `mapstructure:"skip_export" required:"false" cty:"skip_export" hcl:"skip_export"` - Headless *bool `mapstructure:"headless" required:"false" cty:"headless" hcl:"headless"` - FirstBootDevice *string `mapstructure:"first_boot_device" required:"false" cty:"first_boot_device" hcl:"first_boot_device"` - BootOrder []string `mapstructure:"boot_order" required:"false" cty:"boot_order" hcl:"boot_order"` - ShutdownCommand *string `mapstructure:"shutdown_command" required:"false" cty:"shutdown_command" hcl:"shutdown_command"` - ShutdownTimeout *string `mapstructure:"shutdown_timeout" required:"false" cty:"shutdown_timeout" hcl:"shutdown_timeout"` - CloneFromVMCXPath *string `mapstructure:"clone_from_vmcx_path" cty:"clone_from_vmcx_path" hcl:"clone_from_vmcx_path"` - CloneFromVMName *string `mapstructure:"clone_from_vm_name" cty:"clone_from_vm_name" hcl:"clone_from_vm_name"` - CloneFromSnapshotName *string `mapstructure:"clone_from_snapshot_name" required:"false" cty:"clone_from_snapshot_name" hcl:"clone_from_snapshot_name"` - CloneAllSnapshots *bool `mapstructure:"clone_all_snapshots" required:"false" cty:"clone_all_snapshots" hcl:"clone_all_snapshots"` - DifferencingDisk *bool `mapstructure:"differencing_disk" required:"false" cty:"differencing_disk" hcl:"differencing_disk"` - CompareCopy *bool `mapstructure:"copy_in_compare" required:"false" cty:"copy_in_compare" hcl:"copy_in_compare"` -} - -// FlatMapstructure returns a new FlatConfig. -// FlatConfig is an auto-generated flat version of Config. -// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up. -func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } { - return new(FlatConfig) -} - -// HCL2Spec returns the hcl spec of a Config. -// This spec is used by HCL to read the fields of Config. -// The decoded values from this spec will then be applied to a FlatConfig. -func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec { - s := map[string]hcldec.Spec{ - "packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false}, - "packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false}, - "packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false}, - "packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false}, - "packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false}, - "packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false}, - "packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false}, - "packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false}, - "http_directory": &hcldec.AttrSpec{Name: "http_directory", Type: cty.String, Required: false}, - "http_content": &hcldec.AttrSpec{Name: "http_content", Type: cty.Map(cty.String), Required: false}, - "http_port_min": &hcldec.AttrSpec{Name: "http_port_min", Type: cty.Number, Required: false}, - "http_port_max": &hcldec.AttrSpec{Name: "http_port_max", Type: cty.Number, Required: false}, - "http_bind_address": &hcldec.AttrSpec{Name: "http_bind_address", Type: cty.String, Required: false}, - "http_interface": &hcldec.AttrSpec{Name: "http_interface", Type: cty.String, Required: false}, - "iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false}, - "iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false}, - "iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false}, - "iso_target_path": &hcldec.AttrSpec{Name: "iso_target_path", Type: cty.String, Required: false}, - "iso_target_extension": &hcldec.AttrSpec{Name: "iso_target_extension", Type: cty.String, Required: false}, - "boot_keygroup_interval": &hcldec.AttrSpec{Name: "boot_keygroup_interval", Type: cty.String, Required: false}, - "boot_wait": &hcldec.AttrSpec{Name: "boot_wait", Type: cty.String, Required: false}, - "boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false}, - "output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false}, - "communicator": &hcldec.AttrSpec{Name: "communicator", Type: cty.String, Required: false}, - "pause_before_connecting": &hcldec.AttrSpec{Name: "pause_before_connecting", Type: cty.String, Required: false}, - "ssh_host": &hcldec.AttrSpec{Name: "ssh_host", Type: cty.String, Required: false}, - "ssh_port": &hcldec.AttrSpec{Name: "ssh_port", Type: cty.Number, Required: false}, - "ssh_username": &hcldec.AttrSpec{Name: "ssh_username", Type: cty.String, Required: false}, - "ssh_password": &hcldec.AttrSpec{Name: "ssh_password", Type: cty.String, Required: false}, - "ssh_keypair_name": &hcldec.AttrSpec{Name: "ssh_keypair_name", Type: cty.String, Required: false}, - "temporary_key_pair_name": &hcldec.AttrSpec{Name: "temporary_key_pair_name", Type: cty.String, Required: false}, - "temporary_key_pair_type": &hcldec.AttrSpec{Name: "temporary_key_pair_type", Type: cty.String, Required: false}, - "temporary_key_pair_bits": &hcldec.AttrSpec{Name: "temporary_key_pair_bits", Type: cty.Number, Required: false}, - "ssh_ciphers": &hcldec.AttrSpec{Name: "ssh_ciphers", Type: cty.List(cty.String), Required: false}, - "ssh_clear_authorized_keys": &hcldec.AttrSpec{Name: "ssh_clear_authorized_keys", Type: cty.Bool, Required: false}, - "ssh_key_exchange_algorithms": &hcldec.AttrSpec{Name: "ssh_key_exchange_algorithms", Type: cty.List(cty.String), Required: false}, - "ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false}, - "ssh_certificate_file": &hcldec.AttrSpec{Name: "ssh_certificate_file", Type: cty.String, Required: false}, - "ssh_pty": &hcldec.AttrSpec{Name: "ssh_pty", Type: cty.Bool, Required: false}, - "ssh_timeout": &hcldec.AttrSpec{Name: "ssh_timeout", Type: cty.String, Required: false}, - "ssh_wait_timeout": &hcldec.AttrSpec{Name: "ssh_wait_timeout", Type: cty.String, Required: false}, - "ssh_agent_auth": &hcldec.AttrSpec{Name: "ssh_agent_auth", Type: cty.Bool, Required: false}, - "ssh_disable_agent_forwarding": &hcldec.AttrSpec{Name: "ssh_disable_agent_forwarding", Type: cty.Bool, Required: false}, - "ssh_handshake_attempts": &hcldec.AttrSpec{Name: "ssh_handshake_attempts", Type: cty.Number, Required: false}, - "ssh_bastion_host": &hcldec.AttrSpec{Name: "ssh_bastion_host", Type: cty.String, Required: false}, - "ssh_bastion_port": &hcldec.AttrSpec{Name: "ssh_bastion_port", Type: cty.Number, Required: false}, - "ssh_bastion_agent_auth": &hcldec.AttrSpec{Name: "ssh_bastion_agent_auth", Type: cty.Bool, Required: false}, - "ssh_bastion_username": &hcldec.AttrSpec{Name: "ssh_bastion_username", Type: cty.String, Required: false}, - "ssh_bastion_password": &hcldec.AttrSpec{Name: "ssh_bastion_password", Type: cty.String, Required: false}, - "ssh_bastion_interactive": &hcldec.AttrSpec{Name: "ssh_bastion_interactive", Type: cty.Bool, Required: false}, - "ssh_bastion_private_key_file": &hcldec.AttrSpec{Name: "ssh_bastion_private_key_file", Type: cty.String, Required: false}, - "ssh_bastion_certificate_file": &hcldec.AttrSpec{Name: "ssh_bastion_certificate_file", Type: cty.String, Required: false}, - "ssh_file_transfer_method": &hcldec.AttrSpec{Name: "ssh_file_transfer_method", Type: cty.String, Required: false}, - "ssh_proxy_host": &hcldec.AttrSpec{Name: "ssh_proxy_host", Type: cty.String, Required: false}, - "ssh_proxy_port": &hcldec.AttrSpec{Name: "ssh_proxy_port", Type: cty.Number, Required: false}, - "ssh_proxy_username": &hcldec.AttrSpec{Name: "ssh_proxy_username", Type: cty.String, Required: false}, - "ssh_proxy_password": &hcldec.AttrSpec{Name: "ssh_proxy_password", Type: cty.String, Required: false}, - "ssh_keep_alive_interval": &hcldec.AttrSpec{Name: "ssh_keep_alive_interval", Type: cty.String, Required: false}, - "ssh_read_write_timeout": &hcldec.AttrSpec{Name: "ssh_read_write_timeout", Type: cty.String, Required: false}, - "ssh_remote_tunnels": &hcldec.AttrSpec{Name: "ssh_remote_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_local_tunnels": &hcldec.AttrSpec{Name: "ssh_local_tunnels", Type: cty.List(cty.String), Required: false}, - "ssh_public_key": &hcldec.AttrSpec{Name: "ssh_public_key", Type: cty.List(cty.Number), Required: false}, - "ssh_private_key": &hcldec.AttrSpec{Name: "ssh_private_key", Type: cty.List(cty.Number), Required: false}, - "winrm_username": &hcldec.AttrSpec{Name: "winrm_username", Type: cty.String, Required: false}, - "winrm_password": &hcldec.AttrSpec{Name: "winrm_password", Type: cty.String, Required: false}, - "winrm_host": &hcldec.AttrSpec{Name: "winrm_host", Type: cty.String, Required: false}, - "winrm_no_proxy": &hcldec.AttrSpec{Name: "winrm_no_proxy", Type: cty.Bool, Required: false}, - "winrm_port": &hcldec.AttrSpec{Name: "winrm_port", Type: cty.Number, Required: false}, - "winrm_timeout": &hcldec.AttrSpec{Name: "winrm_timeout", Type: cty.String, Required: false}, - "winrm_use_ssl": &hcldec.AttrSpec{Name: "winrm_use_ssl", Type: cty.Bool, Required: false}, - "winrm_insecure": &hcldec.AttrSpec{Name: "winrm_insecure", Type: cty.Bool, Required: false}, - "winrm_use_ntlm": &hcldec.AttrSpec{Name: "winrm_use_ntlm", Type: cty.Bool, Required: false}, - "floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false}, - "floppy_dirs": &hcldec.AttrSpec{Name: "floppy_dirs", Type: cty.List(cty.String), Required: false}, - "floppy_label": &hcldec.AttrSpec{Name: "floppy_label", Type: cty.String, Required: false}, - "cd_files": &hcldec.AttrSpec{Name: "cd_files", Type: cty.List(cty.String), Required: false}, - "cd_label": &hcldec.AttrSpec{Name: "cd_label", Type: cty.String, Required: false}, - "disk_block_size": &hcldec.AttrSpec{Name: "disk_block_size", Type: cty.Number, Required: false}, - "memory": &hcldec.AttrSpec{Name: "memory", Type: cty.Number, Required: false}, - "secondary_iso_images": &hcldec.AttrSpec{Name: "secondary_iso_images", Type: cty.List(cty.String), Required: false}, - "disk_additional_size": &hcldec.AttrSpec{Name: "disk_additional_size", Type: cty.List(cty.Number), Required: false}, - "guest_additions_mode": &hcldec.AttrSpec{Name: "guest_additions_mode", Type: cty.String, Required: false}, - "guest_additions_path": &hcldec.AttrSpec{Name: "guest_additions_path", Type: cty.String, Required: false}, - "vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false}, - "switch_name": &hcldec.AttrSpec{Name: "switch_name", Type: cty.String, Required: false}, - "switch_vlan_id": &hcldec.AttrSpec{Name: "switch_vlan_id", Type: cty.String, Required: false}, - "mac_address": &hcldec.AttrSpec{Name: "mac_address", Type: cty.String, Required: false}, - "vlan_id": &hcldec.AttrSpec{Name: "vlan_id", Type: cty.String, Required: false}, - "cpus": &hcldec.AttrSpec{Name: "cpus", Type: cty.Number, Required: false}, - "generation": &hcldec.AttrSpec{Name: "generation", Type: cty.Number, Required: false}, - "enable_mac_spoofing": &hcldec.AttrSpec{Name: "enable_mac_spoofing", Type: cty.Bool, Required: false}, - "enable_dynamic_memory": &hcldec.AttrSpec{Name: "enable_dynamic_memory", Type: cty.Bool, Required: false}, - "enable_secure_boot": &hcldec.AttrSpec{Name: "enable_secure_boot", Type: cty.Bool, Required: false}, - "secure_boot_template": &hcldec.AttrSpec{Name: "secure_boot_template", Type: cty.String, Required: false}, - "enable_virtualization_extensions": &hcldec.AttrSpec{Name: "enable_virtualization_extensions", Type: cty.Bool, Required: false}, - "temp_path": &hcldec.AttrSpec{Name: "temp_path", Type: cty.String, Required: false}, - "configuration_version": &hcldec.AttrSpec{Name: "configuration_version", Type: cty.String, Required: false}, - "keep_registered": &hcldec.AttrSpec{Name: "keep_registered", Type: cty.Bool, Required: false}, - "skip_compaction": &hcldec.AttrSpec{Name: "skip_compaction", Type: cty.Bool, Required: false}, - "skip_export": &hcldec.AttrSpec{Name: "skip_export", Type: cty.Bool, Required: false}, - "headless": &hcldec.AttrSpec{Name: "headless", Type: cty.Bool, Required: false}, - "first_boot_device": &hcldec.AttrSpec{Name: "first_boot_device", Type: cty.String, Required: false}, - "boot_order": &hcldec.AttrSpec{Name: "boot_order", Type: cty.List(cty.String), Required: false}, - "shutdown_command": &hcldec.AttrSpec{Name: "shutdown_command", Type: cty.String, Required: false}, - "shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false}, - "clone_from_vmcx_path": &hcldec.AttrSpec{Name: "clone_from_vmcx_path", Type: cty.String, Required: false}, - "clone_from_vm_name": &hcldec.AttrSpec{Name: "clone_from_vm_name", Type: cty.String, Required: false}, - "clone_from_snapshot_name": &hcldec.AttrSpec{Name: "clone_from_snapshot_name", Type: cty.String, Required: false}, - "clone_all_snapshots": &hcldec.AttrSpec{Name: "clone_all_snapshots", Type: cty.Bool, Required: false}, - "differencing_disk": &hcldec.AttrSpec{Name: "differencing_disk", Type: cty.Bool, Required: false}, - "copy_in_compare": &hcldec.AttrSpec{Name: "copy_in_compare", Type: cty.Bool, Required: false}, - } - return s -} diff --git a/builder/hyperv/vmcx/builder_test.go b/builder/hyperv/vmcx/builder_test.go deleted file mode 100644 index f663012d1..000000000 --- a/builder/hyperv/vmcx/builder_test.go +++ /dev/null @@ -1,521 +0,0 @@ -package vmcx - -import ( - "context" - "fmt" - "reflect" - "testing" - - "io/ioutil" - "os" - - "github.com/hashicorp/packer-plugin-sdk/common" - "github.com/hashicorp/packer-plugin-sdk/multistep" - packersdk "github.com/hashicorp/packer-plugin-sdk/packer" - hypervcommon "github.com/hashicorp/packer/builder/hyperv/common" -) - -func testConfig() map[string]interface{} { - return map[string]interface{}{ - "iso_checksum": "md5:0B0F137F17AC10944716020B018F8126", - "iso_url": "http://www.packer.io", - "shutdown_command": "yes", - "ssh_username": "foo", - "switch_name": "switch", // to avoid using builder.detectSwitchName which can lock down in travis-ci - "memory": 64, - "guest_additions_mode": "none", - "clone_from_vmcx_path": "generated", - common.BuildNameConfigKey: "foo", - } -} - -func TestBuilder_ImplementsBuilder(t *testing.T) { - var raw interface{} - raw = &Builder{} - if _, ok := raw.(packersdk.Builder); !ok { - t.Error("Builder must implement builder.") - } -} - -func TestBuilderPrepare_Defaults(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if b.config.VMName != "packer-foo" { - t.Errorf("bad vm name: %s", b.config.VMName) - } -} - -func TestBuilderPrepare_InvalidKey(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - // Add a random key - config["i_should_not_be_valid"] = true - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } -} - -func TestBuilderPrepare_CloneFromExistingMachineOrImportFromExportedMachineSettingsRequired(t *testing.T) { - var b Builder - config := testConfig() - delete(config, "clone_from_vmcx_path") - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } -} - -func TestBuilderPrepare_ExportedMachinePathDoesNotExist(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - - //Delete the folder immediately - os.RemoveAll(td) - - config["clone_from_vmcx_path"] = td - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } -} - -func TestBuilderPrepare_ExportedMachinePathExists(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - - //Only delete afterwards - defer os.RemoveAll(td) - - config["clone_from_vmcx_path"] = td - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } -} - -func disabled_TestBuilderPrepare_CloneFromVmSettingUsedSoNoCloneFromVmcxPathRequired(t *testing.T) { - var b Builder - config := testConfig() - delete(config, "clone_from_vmcx_path") - - config["clone_from_vm_name"] = "test_machine_name_that_does_not_exist" - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - - if err == nil { - t.Fatal("should have error") - } else { - errorMessage := err.Error() - if errorMessage != "1 error(s) occurred:\n\n* Virtual machine 'test_machine_name_that_does_not_exist' "+ - "to clone from does not exist." { - t.Fatalf("should not have error: %s", err) - } - } -} - -func TestBuilderPrepare_ISOChecksum(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - // Test bad - config["iso_checksum"] = "" - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - - // Test good - config["iso_checksum"] = "0B0F137F17AC10944716020B018F8126" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - -} - -func TestBuilderPrepare_ISOChecksumType(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - config["iso_checksum"] = "0B0F137F17AC10944716020B018F8126" - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - // Test good - config["iso_checksum"] = "mD5:0B0F137F17AC10944716020B018F8126" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - // Test none - config["iso_checksum"] = "none" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) == 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - -} - -func TestBuilderPrepare_ISOUrl(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - delete(config, "iso_url") - delete(config, "iso_urls") - - // Test both empty (should be allowed, as we cloning a vm so we probably don't need an ISO file) - config["iso_url"] = "" - b = Builder{} - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatal("should not have an error") - } - - // Test iso_url set - config["iso_url"] = "http://www.packer.io" - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Errorf("should not have error: %s", err) - } - - expected := []string{"http://www.packer.io"} - if !reflect.DeepEqual(b.config.ISOUrls, expected) { - t.Fatalf("bad: %#v", b.config.ISOUrls) - } - - // Test both set - config["iso_url"] = "http://www.packer.io" - config["iso_urls"] = []string{"http://www.packer.io"} - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err == nil { - t.Fatal("should have error") - } - - // Test just iso_urls set - delete(config, "iso_url") - config["iso_urls"] = []string{ - "http://www.packer.io", - "http://www.hashicorp.com", - } - - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Errorf("should not have error: %s", err) - } - - expected = []string{ - "http://www.packer.io", - "http://www.hashicorp.com", - } - if !reflect.DeepEqual(b.config.ISOUrls, expected) { - t.Fatalf("bad: %#v", b.config.ISOUrls) - } -} - -func TestBuilderPrepare_FloppyFiles(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - delete(config, "floppy_files") - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("bad err: %s", err) - } - - if len(b.config.FloppyFiles) != 0 { - t.Fatalf("bad: %#v", b.config.FloppyFiles) - } - - floppies_path := "../../test-fixtures/floppies" - config["floppy_files"] = []string{fmt.Sprintf("%s/bar.bat", floppies_path), fmt.Sprintf("%s/foo.ps1", floppies_path)} - b = Builder{} - _, warns, err = b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - expected := []string{fmt.Sprintf("%s/bar.bat", floppies_path), fmt.Sprintf("%s/foo.ps1", floppies_path)} - if !reflect.DeepEqual(b.config.FloppyFiles, expected) { - t.Fatalf("bad: %#v", b.config.FloppyFiles) - } -} - -func TestBuilderPrepare_InvalidFloppies(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - config["floppy_files"] = []string{"nonexistent.bat", "nonexistent.ps1"} - b = Builder{} - _, _, errs := b.Prepare(config) - if errs == nil { - t.Fatalf("Nonexistent floppies should trigger multierror") - } - - if len(errs.(*packersdk.MultiError).Errors) != 2 { - t.Fatalf("Multierror should work and report 2 errors") - } -} - -func TestBuilderPrepare_CommConfig(t *testing.T) { - // Test Winrm - { - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - config["communicator"] = "winrm" - config["winrm_username"] = "username" - config["winrm_password"] = "password" - config["winrm_host"] = "1.2.3.4" - - var b Builder - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if b.config.Comm.WinRMUser != "username" { - t.Errorf("bad winrm_username: %s", b.config.Comm.WinRMUser) - } - if b.config.Comm.WinRMPassword != "password" { - t.Errorf("bad winrm_password: %s", b.config.Comm.WinRMPassword) - } - if host := b.config.Comm.Host(); host != "1.2.3.4" { - t.Errorf("bad host: %s", host) - } - } - - // Test SSH - { - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - config["communicator"] = "ssh" - config["ssh_username"] = "username" - config["ssh_password"] = "password" - config["ssh_host"] = "1.2.3.4" - - var b Builder - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - if b.config.Comm.SSHUsername != "username" { - t.Errorf("bad ssh_username: %s", b.config.Comm.SSHUsername) - } - if b.config.Comm.SSHPassword != "password" { - t.Errorf("bad ssh_password: %s", b.config.Comm.SSHPassword) - } - if host := b.config.Comm.Host(); host != "1.2.3.4" { - t.Errorf("bad host: %s", host) - } - } -} - -func TestUserVariablesInBootCommand(t *testing.T) { - var b Builder - config := testConfig() - - //Create vmcx folder - td, err := ioutil.TempDir("", "packer") - if err != nil { - t.Fatalf("err: %s", err) - } - defer os.RemoveAll(td) - config["clone_from_vmcx_path"] = td - - config[common.UserVariablesConfigKey] = map[string]string{"test-variable": "test"} - config["boot_command"] = []string{"blah {{user `test-variable`}} blah"} - - _, warns, err := b.Prepare(config) - if len(warns) > 0 { - t.Fatalf("bad: %#v", warns) - } - if err != nil { - t.Fatalf("should not have error: %s", err) - } - - ui := packersdk.TestUi(t) - hook := &packersdk.MockHook{} - driver := &hypervcommon.DriverMock{} - - // Set up the state. - state := new(multistep.BasicStateBag) - state.Put("config", &b.config) - state.Put("driver", driver) - state.Put("hook", hook) - state.Put("http_port", 0) - state.Put("http_ip", "0.0.0.0") - state.Put("ui", ui) - state.Put("vmName", "packer-foo") - - step := &hypervcommon.StepTypeBootCommand{ - BootCommand: b.config.FlatBootCommand(), - SwitchName: b.config.SwitchName, - Ctx: b.config.ctx, - } - - ret := step.Run(context.Background(), state) - if ret != multistep.ActionContinue { - t.Fatalf("should not have error: %#v", ret) - } -} diff --git a/command/plugin.go b/command/plugin.go index fe83100f8..ba502682e 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -19,8 +19,6 @@ import ( digitaloceanbuilder "github.com/hashicorp/packer/builder/digitalocean" filebuilder "github.com/hashicorp/packer/builder/file" hcloudbuilder "github.com/hashicorp/packer/builder/hcloud" - hypervisobuilder "github.com/hashicorp/packer/builder/hyperv/iso" - hypervvmcxbuilder "github.com/hashicorp/packer/builder/hyperv/vmcx" jdcloudbuilder "github.com/hashicorp/packer/builder/jdcloud" linodebuilder "github.com/hashicorp/packer/builder/linode" lxcbuilder "github.com/hashicorp/packer/builder/lxc" @@ -71,8 +69,6 @@ var Builders = map[string]packersdk.Builder{ "digitalocean": new(digitaloceanbuilder.Builder), "file": new(filebuilder.Builder), "hcloud": new(hcloudbuilder.Builder), - "hyperv-iso": new(hypervisobuilder.Builder), - "hyperv-vmcx": new(hypervvmcxbuilder.Builder), "jdcloud": new(jdcloudbuilder.Builder), "linode": new(linodebuilder.Builder), "lxc": new(lxcbuilder.Builder), diff --git a/command/vendored_plugins.go b/command/vendored_plugins.go index 715388798..2a873e45b 100644 --- a/command/vendored_plugins.go +++ b/command/vendored_plugins.go @@ -31,6 +31,8 @@ import ( googlecomputeexportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-export" googlecomputeimportpostprocessor "github.com/hashicorp/packer-plugin-googlecompute/post-processor/googlecompute-import" hyperonebuilder "github.com/hashicorp/packer-plugin-hyperone/builder/hyperone" + hypervisobuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/iso" + hypervvmcxbuilder "github.com/hashicorp/packer-plugin-hyperv/builder/hyperv/vmcx" ncloudbuilder "github.com/hashicorp/packer-plugin-ncloud/builder/ncloud" openstackbuilder "github.com/hashicorp/packer-plugin-openstack/builder/openstack" oscbsubuilder "github.com/hashicorp/packer-plugin-outscale/builder/osc/bsu" @@ -75,6 +77,9 @@ var VendoredBuilders = map[string]packersdk.Builder{ "cloudstack": new(cloudstackbuilder.Builder), "docker": new(dockerbuilder.Builder), "googlecompute": new(googlecomputebuilder.Builder), + "hyperv-iso": new(hypervisobuilder.Builder), + "hyperv-vmcx": new(hypervvmcxbuilder.Builder), + "hyperone": new(hyperonebuilder.Builder), "ncloud": new(ncloudbuilder.Builder), "openstack": new(openstackbuilder.Builder), "proxmox": new(proxmoxiso.Builder), @@ -95,7 +100,6 @@ var VendoredBuilders = map[string]packersdk.Builder{ "osc-bsusurrogate": new(oscbsusurrogatebuilder.Builder), "osc-bsuvolume": new(oscbsuvolumebuilder.Builder), "osc-chroot": new(oscchrootbuilder.Builder), - "hyperone": new(hyperonebuilder.Builder), } // VendoredProvisioners are provisioner components that were once bundled with the diff --git a/go.mod b/go.mod index 44cea012e..dbb9cad07 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/gobwas/glob v0.2.3 github.com/google/go-cmp v0.5.5 github.com/google/go-github/v33 v33.0.1-0.20210113204525-9318e629ec69 - github.com/google/uuid v1.1.2 + github.com/google/uuid v1.2.0 github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026 github.com/hashicorp/errwrap v1.0.0 @@ -36,7 +36,7 @@ require ( github.com/hashicorp/go-oracle-terraform v0.0.0-20181016190316-007121241b79 github.com/hashicorp/go-uuid v1.0.2 github.com/hashicorp/go-version v1.3.0 - github.com/hashicorp/hcl/v2 v2.9.1 + github.com/hashicorp/hcl/v2 v2.10.0 github.com/hashicorp/packer-plugin-alicloud v0.0.2 github.com/hashicorp/packer-plugin-amazon v0.0.1 github.com/hashicorp/packer-plugin-ansible v0.0.2 @@ -45,8 +45,9 @@ require ( github.com/hashicorp/packer-plugin-docker v0.0.7 github.com/hashicorp/packer-plugin-googlecompute v0.0.1 github.com/hashicorp/packer-plugin-hyperone v0.0.1 + github.com/hashicorp/packer-plugin-hyperv v0.0.1 github.com/hashicorp/packer-plugin-ncloud v0.0.2 - github.com/hashicorp/packer-plugin-openstack v0.0.1 + github.com/hashicorp/packer-plugin-openstack v0.0.2 github.com/hashicorp/packer-plugin-outscale v0.0.1 github.com/hashicorp/packer-plugin-parallels v0.0.1 github.com/hashicorp/packer-plugin-proxmox v0.0.2 @@ -83,7 +84,7 @@ require ( github.com/ulikunitz/xz v0.5.6 github.com/yandex-cloud/go-genproto v0.0.0-20200915125933-33de72a328bd github.com/yandex-cloud/go-sdk v0.0.0-20200921111412-ef15ded2014c - github.com/zclconf/go-cty v1.8.1 + github.com/zclconf/go-cty v1.8.2 github.com/zclconf/go-cty-yaml v1.0.1 golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc golang.org/x/mod v0.4.1 diff --git a/go.sum b/go.sum index 8b0b243f8..7e4c6f1dd 100644 --- a/go.sum +++ b/go.sum @@ -353,8 +353,9 @@ github.com/google/shlex v0.0.0-20150127133951-6f45313302b9 h1:JM174NTeGNJ2m/oLH3 github.com/google/shlex v0.0.0-20150127133951-6f45313302b9/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE= github.com/google/uuid v0.0.0-20170306145142-6a5e28554805/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -443,8 +444,9 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl/v2 v2.6.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= github.com/hashicorp/hcl/v2 v2.8.0/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY= -github.com/hashicorp/hcl/v2 v2.9.1 h1:eOy4gREY0/ZQHNItlfuEZqtcQbXIxzojlP301hDpnac= github.com/hashicorp/hcl/v2 v2.9.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= +github.com/hashicorp/hcl/v2 v2.10.0 h1:1S1UnuhDGlv3gRFV4+0EdwB+znNP5HmcGbIqwnSCByg= +github.com/hashicorp/hcl/v2 v2.10.0/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= @@ -478,10 +480,12 @@ github.com/hashicorp/packer-plugin-googlecompute v0.0.1 h1:Shjio88MraB+ocj0VI5+M github.com/hashicorp/packer-plugin-googlecompute v0.0.1/go.mod h1:MfV898IrEMpKH6wVnvOI5Tkhxm2snf3QxwVqV4k3bNI= github.com/hashicorp/packer-plugin-hyperone v0.0.1 h1:Owp1B5cI0VgFgR3pCyeeQdyKPTWls36mVedv+WxZMOM= github.com/hashicorp/packer-plugin-hyperone v0.0.1/go.mod h1:9DglrxEBIig85Hr8r11YE+uMn3G0u+pt0AZHVP+wnAY= +github.com/hashicorp/packer-plugin-hyperv v0.0.1 h1:ZdsJw4X+4zSgRYPzVQbJrx8Az73AkneSWLnmfpojl0k= +github.com/hashicorp/packer-plugin-hyperv v0.0.1/go.mod h1:sB9mEZCfaXVjTD6pS+Tt0xMtUD1Ocnl5mZ3i/PG6eB0= github.com/hashicorp/packer-plugin-ncloud v0.0.2 h1:MGvGkOVfzeosqOSs5dteghLwv9VRcRxTuLoLX1ssUag= github.com/hashicorp/packer-plugin-ncloud v0.0.2/go.mod h1:Hud2R1pkky96TQy3TPTTrr9Kej4b/4dqC/v+uEE0VDY= -github.com/hashicorp/packer-plugin-openstack v0.0.1 h1:FUaNjKguAipPZZXQ4UiJK6c5+2nS89CRxJHjAsfVyIQ= -github.com/hashicorp/packer-plugin-openstack v0.0.1/go.mod h1:L1OTbN24H+izce3v5IyQLdjDdrUigxPWgAQOK920h9A= +github.com/hashicorp/packer-plugin-openstack v0.0.2 h1:wGNE8es3Bn9auuIoX+gqT9chXzYY9GlM55eSpM4uwtU= +github.com/hashicorp/packer-plugin-openstack v0.0.2/go.mod h1:rHAdd4+JmI+1z98Zx+lVOehgzLZT1Rjo2YgtS0NNvwM= github.com/hashicorp/packer-plugin-outscale v0.0.1 h1:BrL8hKypNYrvP3NR+d+xX03SZKB08yTgXPRnH9piUI8= github.com/hashicorp/packer-plugin-outscale v0.0.1/go.mod h1:6jEWfJO7TgAbaL3e+St1bN5PoIC/MmDIsYqNUzAHF1w= github.com/hashicorp/packer-plugin-parallels v0.0.1 h1:fcaaiGWdU1+X4IGadXdUhJ2si1ZA3apXS9tMNJXln2A= @@ -788,8 +792,9 @@ github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q github.com/zclconf/go-cty v1.4.0/go.mod h1:nHzOclRkoj++EU9ZjSrZvRG0BXIWt8c7loYc0qXAFGQ= github.com/zclconf/go-cty v1.7.0/go.mod h1:VDR4+I79ubFBGm1uJac1226K5yANQFHeauxPBoP54+o= github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= -github.com/zclconf/go-cty v1.8.1 h1:SI0LqNeNxAgv2WWqWJMlG2/Ad/6aYJ7IVYYMigmfkuI= github.com/zclconf/go-cty v1.8.1/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= +github.com/zclconf/go-cty v1.8.2 h1:u+xZfBKgpycDnTNjPhGiTEYZS5qS/Sb5MqSfm7vzcjg= +github.com/zclconf/go-cty v1.8.2/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= github.com/zclconf/go-cty-yaml v1.0.1 h1:up11wlgAaDvlAGENcFDnZgkn0qUJurso7k6EpURKNF8= github.com/zclconf/go-cty-yaml v1.0.1/go.mod h1:IP3Ylp0wQpYm50IHK8OZWKMu6sPJIUgKa8XhiVHura0= diff --git a/website/content/docs/builders/hyperv/index.mdx b/website/content/docs/builders/hyperv/index.mdx deleted file mode 100644 index 9d5169d46..000000000 --- a/website/content/docs/builders/hyperv/index.mdx +++ /dev/null @@ -1,22 +0,0 @@ ---- -description: | - The Hyper-V Packer builder is able to create Hyper-V virtual machines and - export them. -page_title: Hyper-V - Builders ---- - -# HyperV Builder - -The HyperV Packer builder is able to create -[Hyper-V](https://www.microsoft.com/en-us/server-cloud/solutions/virtualization.aspx) -virtual machines and export them. - -- [hyperv-iso](/docs/builders/hyperv-iso) - Starts from an ISO file, - creates a brand new Hyper-V VM, installs an OS, provisions software within - the OS, then exports that machine to create an image. This is best for - people who want to start from scratch. - -- [hyperv-vmcx](/docs/builders/hyperv-vmcx) - Clones an an existing - virtual machine, provisions software within the OS, then exports that - machine to create an image. This is best for people who have existing base - images and want to customize them. diff --git a/website/content/docs/builders/hyperv/iso.mdx b/website/content/docs/builders/hyperv/iso.mdx deleted file mode 100644 index e9466e926..000000000 --- a/website/content/docs/builders/hyperv/iso.mdx +++ /dev/null @@ -1,860 +0,0 @@ ---- -modeline: | - vim: set ft=pandoc: -description: | - The Hyper-V Packer builder is able to create Hyper-V virtual machines and - export them. -page_title: Hyper-V ISO - Builders ---- - -# Hyper-V Builder (from an ISO) - -Type: `hyperv-iso` -Artifact BuilderId: `MSOpenTech.hyperv` - -The Hyper-V Packer builder is able to create -[Hyper-V](https://www.microsoft.com/en-us/server-cloud/solutions/virtualization.aspx) -virtual machines and export them, starting from an ISO image. - -The builder builds a virtual machine by creating a new virtual machine from -scratch. Typically, the VM is booted, an OS is installed, and software is -provisioned within the OS. Finally the VM is shut down. The result of the -Hyper-V builder is a directory containing all the files necessary to run -the virtual machine portably. - -## Basic Example - -Here is a basic example. This example is not functional. It will start the OS -installer but then fail because we don't provide the preseed file for Ubuntu -to self-install. Still, the example serves to show the basic configuration: - -```json -{ - "type": "hyperv-iso", - "iso_url": "http://releases.ubuntu.com/12.04/ubuntu-12.04.5-server-amd64.iso", - "iso_checksum": "md5:769474248a3897f4865817446f9a4a53", - "ssh_username": "packer", - "ssh_password": "packer", - "shutdown_command": "echo 'packer' | sudo -S shutdown -P now" -} -``` - -By default Packer will perform a hard power off of a virtual machine. -However, when a machine is powered off this way, it is possible that -changes made to the VMs file system may not be fully synced, possibly -leading to corruption of files or lost changes. As such, it is important to -add a `shutdown_command`. This tells Packer how to safely shutdown and -power off the VM. - -## ISO Configuration Reference - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig.mdx' - -### Required: - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-required.mdx' - -### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-not-required.mdx' - -## Configuration Reference - -There are many configuration options available for the Hyper-V builder. They -are organized below into two categories: required and optional. Within each -category, the available options are alphabetized and described. - -In addition to the options listed here, a -[communicator](/docs/templates/legacy_json_templates/communicator) can be configured for this -builder. - -### Optional: - -- `output_directory` (string) - This setting specifies the directory that - artifacts from the build, such as the virtual machine files and disks, - will be output to. The path to the directory may be relative or - absolute. If relative, the path is relative to the working directory - `packer` is executed from. This directory must not exist or, if - created, must be empty prior to running the builder. By default this is - "output-BUILDNAME" where "BUILDNAME" is the name of the build. - -@include 'builder/hyperv/iso/Config-not-required.mdx' - -@include 'builder/hyperv/common/CommonConfig-not-required.mdx' - -## Http directory configuration reference - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig.mdx' - -### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig-not-required.mdx' - -## Shutdown configuration reference - -### Optional: - -@include 'packer-plugin-sdk/shutdowncommand/ShutdownConfig-not-required.mdx' - -## Floppy configuration reference - -@include 'packer-plugin-sdk/multistep/commonsteps/FloppyConfig.mdx' - -### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/FloppyConfig-not-required.mdx' - -### CD configuration reference - -@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig-not-required.mdx' - -## Communicator configuration reference - -### Optional common fields: - -@include 'packer-plugin-sdk/communicator/Config-not-required.mdx' - -### Optional SSH fields: - -@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx' - -### Optional WinRM fields: - -@include 'packer-plugin-sdk/communicator/WinRM-not-required.mdx' - -## Boot Configuration Reference - -@include 'packer-plugin-sdk/bootcommand/BootConfig.mdx' - -### Optional: - -@include 'packer-plugin-sdk/bootcommand/BootConfig-not-required.mdx' - -## Integration Services - -Packer will automatically attach the integration services ISO as a DVD drive -for the version of Hyper-V that is running. - -## Generation 1 vs Generation 2 - -Floppy drives are no longer supported by generation 2 machines. This requires -you to take another approach when dealing with preseed or answer files. Two -possible options are using your own virtual DVD drives, the cd_files option, -or using Packer's built in web server. - -When dealing with Windows you need to enable UEFI drives for generation 2 -virtual machines. - -## Creating an ISO From a Directory - -Programs like mkisofs can be used to create an ISO from a directory. There is -a [windows version of -mkisofs](http://opensourcepack.blogspot.co.uk/p/cdrtools.html) available. - -Below is a working PowerShell script that can be used to create a Windows -answer ISO: - -```powershell -$isoFolder = "answer-iso" -if (test-path $isoFolder){ - remove-item $isoFolder -Force -Recurse -} - -if (test-path windows\windows-2012R2-serverdatacenter-amd64\answer.iso){ - remove-item windows\windows-2012R2-serverdatacenter-amd64\answer.iso -Force -} - -mkdir $isoFolder - -copy windows\windows-2012R2-serverdatacenter-amd64\Autounattend.xml $isoFolder\ -copy windows\windows-2012R2-serverdatacenter-amd64\sysprep-unattend.xml $isoFolder\ -copy windows\common\set-power-config.ps1 $isoFolder\ -copy windows\common\microsoft-updates.ps1 $isoFolder\ -copy windows\common\win-updates.ps1 $isoFolder\ -copy windows\common\run-sysprep.ps1 $isoFolder\ -copy windows\common\run-sysprep.cmd $isoFolder\ - -$textFile = "$isoFolder\Autounattend.xml" - -$c = Get-Content -Encoding UTF8 $textFile - -# Enable UEFI and disable Non EUFI -$c | % { $_ -replace '','','Finish Non UEFI -->' } | % { $_ -replace '' } | % { $_ -replace 'Finish UEFI compatible -->','' } | sc -Path $textFile - -& .\mkisofs.exe -r -iso-level 4 -UDF -o windows\windows-2012R2-serverdatacenter-amd64\answer.iso $isoFolder - -if (test-path $isoFolder){ - remove-item $isoFolder -Force -Recurse -} -``` - -## Example For Windows Server 2012 R2 Generation 2 - -Packer config: - -```json -{ - "builders": [ - { - "vm_name": "windows2012r2", - "type": "hyperv-iso", - "disk_size": 61440, - "floppy_files": [], - "secondary_iso_images": [ - "./windows/windows-2012R2-serverdatacenter-amd64/answer.iso" - ], - "http_directory": "./windows/common/http/", - "boot_wait": "0s", - "boot_command": ["aaa"], - "iso_url": "http://download.microsoft.com/download/6/2/A/62A76ABB-9990-4EFC-A4FE-C7D698DAEB96/9600.16384.WINBLUE_RTM.130821-1623_X64FRE_SERVER_EVAL_EN-US-IRM_SSS_X64FREE_EN-US_DV5.ISO", - "iso_checksum": "md5:458ff91f8abc21b75cb544744bf92e6a", - "communicator": "winrm", - "winrm_username": "vagrant", - "winrm_password": "vagrant", - "winrm_timeout": "4h", - "shutdown_command": "f:\\run-sysprep.cmd", - "memory": 4096, - "cpus": 4, - "generation": 2, - "switch_name": "LAN", - "enable_secure_boot": true - } - ], - "provisioners": [ - { - "type": "powershell", - "elevated_user": "vagrant", - "elevated_password": "vagrant", - "scripts": [ - "./windows/common/install-7zip.ps1", - "./windows/common/install-chef.ps1", - "./windows/common/compile-dotnet-assemblies.ps1", - "./windows/common/cleanup.ps1", - "./windows/common/ultradefrag.ps1", - "./windows/common/sdelete.ps1" - ] - } - ], - "post-processors": [ - { - "type": "vagrant", - "keep_input_artifact": false, - "output": "{{.Provider}}_windows-2012r2_chef.box" - } - ] -} -``` - -autounattend.xml: - -```xml - - - - - - en-US - - en-US - en-US - en-US - en-US - en-US - - - - - - - - Primary - 1 - 350 - - - 2 - Primary - true - - - - - true - NTFS - - 1 - 1 - - - NTFS - - C - 2 - 2 - - - 0 - true - - - - - - - /IMAGE/NAME - Windows Server 2012 R2 SERVERSTANDARD - - - - 0 - 2 - - - - - - - - - - - - OnError - - true - Vagrant - Vagrant - - - - - - - false - - vagrant-2012r2 - Coordinated Universal Time - - - - true - - - false - false - - - true - - - true - - - - - - - - vagrant - true</PlainText> - </Password> - <Enabled>true</Enabled> - <Username>vagrant</Username> - </AutoLogon> - <FirstLogonCommands> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine> - <Description>Set Execution Policy 64 Bit</Description> - <Order>1</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>C:\Windows\SysWOW64\cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine> - <Description>Set Execution Policy 32 Bit</Description> - <Order>2</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm quickconfig -q</CommandLine> - <Description>winrm quickconfig -q</Description> - <Order>3</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm quickconfig -transport:http</CommandLine> - <Description>winrm quickconfig -transport:http</Description> - <Order>4</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config @{MaxTimeoutms="1800000"}</CommandLine> - <Description>Win RM MaxTimeoutms</Description> - <Order>5</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/winrs @{MaxMemoryPerShellMB="300"}</CommandLine> - <Description>Win RM MaxMemoryPerShellMB</Description> - <Order>6</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/service @{AllowUnencrypted="true"}</CommandLine> - <Description>Win RM AllowUnencrypted</Description> - <Order>7</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/service/auth @{Basic="true"}</CommandLine> - <Description>Win RM auth Basic</Description> - <Order>8</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/client/auth @{Basic="true"}</CommandLine> - <Description>Win RM client auth Basic</Description> - <Order>9</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/listener?Address=*+Transport=HTTP @{Port="5985"} </CommandLine> - <Description>Win RM listener Address/Port</Description> - <Order>10</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes </CommandLine> - <Description>Win RM adv firewall enable</Description> - <Order>11</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow</CommandLine> - <Description>Win RM port open</Description> - <Order>12</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow</CommandLine> - <Description>Win RM port open</Description> - <Order>13</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c net stop winrm </CommandLine> - <Description>Stop Win RM Service </Description> - <Order>14</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c sc config winrm start= disabled</CommandLine> - <Description>Win RM Autostart</Description> - <Order>15</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v HideFileExt /t REG_DWORD /d 0 /f</CommandLine> - <Order>16</Order> - <Description>Show file extensions in Explorer</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\Console /v QuickEdit /t REG_DWORD /d 1 /f</CommandLine> - <Order>17</Order> - <Description>Enable QuickEdit mode</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v Start_ShowRun /t REG_DWORD /d 1 /f</CommandLine> - <Order>18</Order> - <Description>Show Run command in Start Menu</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v StartMenuAdminTools /t REG_DWORD /d 1 /f</CommandLine> - <Order>19</Order> - <Description>Show Administrative Tools in Start Menu</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateFileSizePercent /t REG_DWORD /d 0 /f</CommandLine> - <Order>20</Order> - <Description>Zero Hibernation File</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateEnabled /t REG_DWORD /d 0 /f</CommandLine> - <Order>21</Order> - <Description>Disable Hibernation Mode</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c wmic useraccount where "name='vagrant'" set PasswordExpires=FALSE</CommandLine> - <Order>22</Order> - <Description>Disable password expiration for vagrant user</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/winrs @{MaxShellsPerUser="30"}</CommandLine> - <Description>Win RM MaxShellsPerUser</Description> - <Order>23</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/winrs @{MaxProcessesPerShell="25"}</CommandLine> - <Description>Win RM MaxProcessesPerShell</Description> - <Order>24</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD "HKLM\System\CurrentControlSet\Services\Netlogon\Parameters" /v DisablePasswordChange /t REG_DWORD /d 1 /f</CommandLine> - <Description>Turn off computer password</Description> - <Order>25</Order> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow</CommandLine> - <Description>ICMP open for ping</Description> - <Order>26</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <!-- WITH WINDOWS UPDATES --> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c IF EXIST a:\set-power-config.ps1 (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\set-power-config.ps1) ELSE (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File f:\set-power-config.ps1)</CommandLine> - <Order>97</Order> - <Description>Turn off all power saving and timeouts</Description> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c IF EXIST a:\microsoft-updates.ps1 (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\microsoft-updates.ps1) ELSE (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File f:\microsoft-updates.ps1)</CommandLine> - <Order>98</Order> - <Description>Enable Microsoft Updates</Description> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c IF EXIST a:\win-updates.ps1 (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\win-updates.ps1) ELSE (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File f:\win-updates.ps1)</CommandLine> - <Description>Install Windows Updates</Description> - <Order>100</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <!-- END WITH WINDOWS UPDATES --> - </FirstLogonCommands> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Work</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - <LocalAccounts> - <LocalAccount wcm:action="add"> - <Password> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </Password> - <Group>administrators</Group> - <DisplayName>Vagrant</DisplayName> - <Name>vagrant</Name> - <Description>Vagrant User</Description> - </LocalAccount> - </LocalAccounts> - </UserAccounts> - <RegisteredOwner /> - <TimeZone>Coordinated Universal Time</TimeZone> - </component> - </settings> - <settings pass="offlineServicing"> - <component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <EnableLUA>false</EnableLUA> - </component> - </settings> - <cpi:offlineImage cpi:source="wim:c:/projects/baseboxes/9600.16384.winblue_rtm.130821-1623_x64fre_server_eval_en-us-irm_sss_x64free_en-us_dv5_slipstream/sources/install.wim#Windows Server 2012 R2 SERVERDATACENTER" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> -</unattend> -``` - -sysprep-unattend.xml: - -```xml -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend"> - <settings pass="generalize"> - <component language="neutral" name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <SkipRearm>1</SkipRearm> - </component> - </settings> - <settings pass="oobeSystem"> -<!-- Setup proxy after sysprep - <component name="Microsoft-Windows-IE-ClientNetworkProtocolImplementation" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <POLICYProxySettingsPerUser>1</POLICYProxySettingsPerUser> - <HKLMProxyEnable>false</HKLMProxyEnable> - <HKLMProxyServer>cache-proxy:3142</HKLMProxyServer> - </component> -Finish proxy after sysprep --> - <component language="neutral" name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <InputLocale>0809:00000809</InputLocale> - <SystemLocale>en-GB</SystemLocale> - <UILanguage>en-US</UILanguage> - <UILanguageFallback>en-US</UILanguageFallback> - <UserLocale>en-GB</UserLocale> - </component> - <component language="neutral" name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Work</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - <SkipUserOOBE>true</SkipUserOOBE> - <SkipMachineOOBE>true</SkipMachineOOBE> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - <LocalAccounts> - <LocalAccount wcm:action="add"> - <Password> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </Password> - <Group>administrators</Group> - <DisplayName>Vagrant</DisplayName> - <Name>vagrant</Name> - <Description>Vagrant User</Description> - </LocalAccount> - </LocalAccounts> - </UserAccounts> - <DisableAutoDaylightTimeSet>true</DisableAutoDaylightTimeSet> - <TimeZone>Coordinated Universal Time</TimeZone> - <VisualEffects> - <SystemDefaultBackgroundColor>2</SystemDefaultBackgroundColor> - </VisualEffects> - </component> - </settings> -</unattend> -``` - --> **Warning:** Please note that if you're setting up WinRM for provisioning, you'll probably want to turn it off or restrict its permissions as part of a shutdown script at the end of Packer's provisioning process. For more details on the why/how, check out this useful blog post and the associated code: -https://cloudywindows.io/post/winrm-for-provisioning-close-the-door-on-the-way-out-eh/ - -## Example For Ubuntu Vivid Generation 2 - -If you are running Windows under virtualization, you may need to create a -virtual switch with an `External` connection type. - -### Packer config: - -```json -{ - "variables": { - "vm_name": "ubuntu-xenial", - "cpus": "2", - "memory": "1024", - "disk_size": "21440", - "iso_url": "http://releases.ubuntu.com/16.04/ubuntu-16.04.6-server-amd64.iso", - "iso_checksum": "sha1:056b7c15efc15bbbf40bf1a9ff1a3531fcbf70a2" - }, - "builders": [ - { - "vm_name": "{{user `vm_name`}}", - "type": "hyperv-iso", - "disk_size": "{{user `disk_size`}}", - "guest_additions_mode": "disable", - "iso_url": "{{user `iso_url`}}", - "iso_checksum": "{{user `iso_checksum`}}", - "communicator": "ssh", - "ssh_username": "packer", - "ssh_password": "packer", - "ssh_timeout": "4h", - "http_directory": "./", - "boot_wait": "5s", - "boot_command": [ - "<esc><wait10><esc><esc><enter><wait>", - "set gfxpayload=1024x768<enter>", - "linux /install/vmlinuz ", - "preseed/url=http://{{.HTTPIP}}:{{.HTTPPort}}/hyperv-taliesins.cfg ", - "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ", - "hostname={{.Name}} ", - "fb=false debconf/frontend=noninteractive ", - "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ", - "keyboard-configuration/variant=USA console-setup/ask_detect=false <enter>", - "initrd /install/initrd.gz<enter>", - "boot<enter>" - ], - "shutdown_command": "echo 'packer' | sudo -S -E shutdown -P now", - "memory": "{{user `memory`}}", - "cpus": "{{user `cpus`}}", - "generation": 2, - "enable_secure_boot": false - } - ] -} -``` - -### preseed.cfg: - -```text -## Options to set on the command line -d-i debian-installer/locale string en_US.utf8 -d-i console-setup/ask_detect boolean false -d-i console-setup/layout string us - -d-i netcfg/get_hostname string nl-ams-basebox3 -d-i netcfg/get_domain string unassigned-domain - -d-i time/zone string UTC -d-i clock-setup/utc-auto boolean true -d-i clock-setup/utc boolean true - -d-i kbd-chooser/method select American English - -d-i netcfg/wireless_wep string - -d-i base-installer/kernel/override-image string linux-server - -d-i debconf debconf/frontend select Noninteractive - -d-i pkgsel/install-language-support boolean false -tasksel tasksel/first multiselect standard, ubuntu-server - -## Partitioning -d-i partman-auto/method string lvm - -d-i partman-lvm/confirm boolean true -d-i partman-lvm/device_remove_lvm boolean true -d-i partman-lvm/confirm boolean true - -d-i partman-auto-lvm/guided_size string max -d-i partman-auto/choose_recipe select atomic - -d-i partman/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 - -# Write the changes to disks and configure LVM? -d-i partman-lvm/confirm boolean true -d-i partman-lvm/confirm_nooverwrite boolean true - -d-i partman-partitioning/no_bootable_gpt_biosgrub boolean false -d-i partman-partitioning/no_bootable_gpt_efi boolean false -d-i partman-efi/non_efi_system boolean true - -# Default user -d-i passwd/user-fullname string packer -d-i passwd/username string packer -d-i passwd/user-password password packer -d-i passwd/user-password-again password packer -d-i user-setup/encrypt-home boolean false -d-i user-setup/allow-password-weak boolean true - -# Minimum packages -d-i pkgsel/include string openssh-server ntp linux-tools-$(uname -r) linux-cloud-tools-$(uname -r) linux-cloud-tools-common - -# Upgrade packages after debootstrap? (none, safe-upgrade, full-upgrade) -# (note: set to none for speed) -d-i pkgsel/upgrade select none - -d-i grub-installer/only_debian boolean true -d-i grub-installer/with_other_os boolean true -d-i finish-install/reboot_in_progress note - -d-i pkgsel/update-policy select none - -choose-mirror-bin mirror/http/proxy string -``` - --> **Note for \*nix guests:** Please note that Packer requires the VM to be -running a hyper-v KVP daemon in order to detect the IP address of the guest VM. -On RHEL based machines this may require installing the package `hyperv-daemons` -and ensuring the `hypervkvpd` service is started at boot. On Debian based -machines, you may need `linux-cloud-tools-common` for `hv_kvp_daemon`. Failure -to do this may cause packer to wait at `Waiting for SSH to become available...` -before eventually timing out. - -Also note that while the operating system is still being installed by a preseed -file, it is normal to see `Waiting for SSH/WinRM to be available` and -`Error getting SSH/WinRM host: No ip address` error messages until the system -is actually installed and ready to be connected to. - -For more information about the hyper-v daemons and supported distributions, see -the Microsoft docs at -https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/supported-linux-and-freebsd-virtual-machines-for-hyper-v-on-windows diff --git a/website/content/docs/builders/hyperv/vmcx.mdx b/website/content/docs/builders/hyperv/vmcx.mdx deleted file mode 100644 index 617201cc2..000000000 --- a/website/content/docs/builders/hyperv/vmcx.mdx +++ /dev/null @@ -1,881 +0,0 @@ ---- -modeline: | - vim: set ft=pandoc: -description: >- - The Hyper-V Packer builder is able to clone an existing Hyper-V virtual - machine and export them. -page_title: Hyper-V Builder (from a vmcx) ---- - -# Hyper-V Builder (from a vmcx) - -Type: `hyperv-vmcx` -Artifact BuilderId: `MSOpenTech.hyperv` - -The Hyper-V Packer builder is able to use exported virtual machines or clone -existing -[Hyper-V](https://www.microsoft.com/en-us/server-cloud/solutions/virtualization.aspx) -virtual machines. - -Typically, the builder imports or clones an existing virtual machine, -boots it, provisions software within the OS, and then shuts it down. The -result of the Hyper-V builder is a directory containing all the files -necessary to run the virtual machine portably. - -## Basic Examples - -Here are some basic examples. Neither example would really do anything more -than producing a copy of the source virtual machine. However, the examples -could be used as a starting point for more advanced templates. - -Import from folder: - -```json -{ - "type": "hyperv-vmcx", - "clone_from_vmcx_path": "c:/path/to/ubuntu-12.04.5-server-amd64", - "ssh_username": "packer", - "ssh_password": "packer", - "shutdown_command": "echo 'packer' | sudo -S shutdown -P now" -} -``` - -Clone from existing virtual machine: - -```json -{ - "clone_from_vm_name": "ubuntu-12.04.5-server-amd64", - "shutdown_command": "echo 'packer' | sudo -S shutdown -P now", - "ssh_password": "packer", - "ssh_username": "packer", - "type": "hyperv-vmcx" -} -``` - -By default Packer will perform a hard power off of a virtual machine. -However, when a machine is powered off this way, it is possible that -changes made to the VMs file system may not be fully synced, possibly -leading to corruption of files or lost changes. As such, it is important to -add a `shutdown_command`. This tells Packer how to safely shutdown and -power off the VM. - -## Configuration Reference - -There are many configuration options available for the Hyper-V builder. They -are organized below into two categories: required and optional. Within each -category, the available options are alphabetized and described. - -In addition to the options listed here, a -[communicator](/docs/templates/legacy_json_templates/communicator) can be configured for this -builder. - -## ISO Configuration Reference - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig.mdx' - -### Required: - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-required.mdx' - -### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/ISOConfig-not-required.mdx' - -### Required for virtual machine import: - -- `clone_from_vmcx_path` (string) - The path to a directory containing a - previously exported virtual machine. The exported machine will be used - as the source for new VM. - - note: You should provide the named directory that contains the - "Virtual Machines", "Snapshots", and/or "Virtual Hard Disks" subdirectories, - not the .vmcx file itself. - -### Required for virtual machine clone: - -- `clone_from_vm_name` (string) - The name of the VM to clone from. Ideally - the machine to clone from should be shutdown. - -### Optional: - -@include 'builder/hyperv/vmcx/Config-not-required.mdx' - -@include 'builder/hyperv/common/CommonConfig-not-required.mdx' - -## Communicator configuration reference - -### Optional common fields: - -@include 'packer-plugin-sdk/communicator/Config-not-required.mdx' - -### Optional SSH fields: - -@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx' - -@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx' - -### Optional WinRM fields: - -@include 'packer-plugin-sdk/communicator/WinRM-not-required.mdx' - -### CD configuration - -@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig.mdx' - -#### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/CDConfig-not-required.mdx' - -## Boot Command - -The `boot_command` configuration is very important: it specifies the keys to -type when the virtual machine is first booted in order to start the OS -installer. This command is typed after `boot_wait`, which gives the virtual -machine some time to actually load the ISO. - -As documented above, the `boot_command` is an array of strings. The strings -are all typed in sequence. It is an array only to improve readability within -the template. - -The boot command is "typed" character for character over the virtual keyboard -to the machine, simulating a human actually typing the keyboard. - -@include 'builders/boot-command.mdx' - -The example shown below is a working boot command used to start an Ubuntu -12.04 installer: - -```json -[ - "<esc><esc><enter><wait>", - "/install/vmlinuz noapic ", - "preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg ", - "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ", - "hostname={{ .Name }} ", - "fb=false debconf/frontend=noninteractive ", - "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ", - "keyboard-configuration/variant=USA console-setup/ask_detect=false ", - "initrd=/install/initrd.gz -- <enter>" -] -``` - -For more examples of various boot commands, see the sample projects from our -[community templates page](/community-tools#templates). - -## Http directory configuration - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig.mdx' - -### Optional: - -@include 'packer-plugin-sdk/multistep/commonsteps/HTTPConfig-not-required.mdx' - -## Integration Services - -Packer will automatically attach the integration services ISO as a DVD drive -for the version of Hyper-V that is running. - -## Generation 1 vs Generation 2 - -Floppy drives are no longer supported by generation 2 machines. This requires -you to take another approach when dealing with preseed or answer files. Two -possible options are using the `cd_files` option or using Packer's built in web -server. - -When dealing with Windows you need to enable UEFI drives for generation 2 -virtual machines. - -## Creating an ISO From a Directory - -Programs like mkisofs can be used to create an ISO from a directory. There is -a [windows version of -mkisofs](http://opensourcepack.blogspot.co.uk/p/cdrtools.html) available. - -Below is a working PowerShell script that can be used to create a Windows -answer ISO: - -```powershell -$isoFolder = "answer-iso" -if (test-path $isoFolder){ - remove-item $isoFolder -Force -Recurse -} - -if (test-path windows\windows-2012R2-serverdatacenter-amd64\answer.iso){ - remove-item windows\windows-2012R2-serverdatacenter-amd64\answer.iso -Force -} - -mkdir $isoFolder - -copy windows\windows-2012R2-serverdatacenter-amd64\Autounattend.xml $isoFolder\ -copy windows\windows-2012R2-serverdatacenter-amd64\sysprep-unattend.xml $isoFolder\ -copy windows\common\set-power-config.ps1 $isoFolder\ -copy windows\common\microsoft-updates.ps1 $isoFolder\ -copy windows\common\win-updates.ps1 $isoFolder\ -copy windows\common\run-sysprep.ps1 $isoFolder\ -copy windows\common\run-sysprep.cmd $isoFolder\ - -$textFile = "$isoFolder\Autounattend.xml" - -$c = Get-Content -Encoding UTF8 $textFile - -# Enable UEFI and disable Non EUFI -$c | % { $_ -replace '<!-- Start Non UEFI -->','<!-- Start Non UEFI' } | % { $_ -replace '<!-- Finish Non UEFI -->','Finish Non UEFI -->' } | % { $_ -replace '<!-- Start UEFI compatible','<!-- Start UEFI compatible -->' } | % { $_ -replace 'Finish UEFI compatible -->','<!-- Finish UEFI compatible -->' } | sc -Path $textFile - -& .\mkisofs.exe -r -iso-level 4 -UDF -o windows\windows-2012R2-serverdatacenter-amd64\answer.iso $isoFolder - -if (test-path $isoFolder){ - remove-item $isoFolder -Force -Recurse -} -``` - -## Example For Windows Server 2012 R2 Generation 2 - -Packer config: - -```json -{ - "builders": [ - { - "vm_name": "windows2012r2", - "type": "hyperv-iso", - "disk_size": 61440, - "floppy_files": [], - "secondary_iso_images": [ - "./windows/windows-2012R2-serverdatacenter-amd64/answer.iso" - ], - "http_directory": "./windows/common/http/", - "boot_wait": "0s", - "boot_command": ["a<wait>a<wait>a"], - "iso_url": "http://download.microsoft.com/download/6/2/A/62A76ABB-9990-4EFC-A4FE-C7D698DAEB96/9600.16384.WINBLUE_RTM.130821-1623_X64FRE_SERVER_EVAL_EN-US-IRM_SSS_X64FREE_EN-US_DV5.ISO", - "iso_checksum": "md5:458ff91f8abc21b75cb544744bf92e6a", - "communicator": "winrm", - "winrm_username": "vagrant", - "winrm_password": "vagrant", - "winrm_timeout": "4h", - "shutdown_command": "f:\\run-sysprep.cmd", - "memory": 4096, - "cpus": 4, - "generation": 2, - "switch_name": "LAN", - "enable_secure_boot": true - } - ], - "provisioners": [ - { - "type": "powershell", - "elevated_user": "vagrant", - "elevated_password": "vagrant", - "scripts": [ - "./windows/common/install-7zip.ps1", - "./windows/common/install-chef.ps1", - "./windows/common/compile-dotnet-assemblies.ps1", - "./windows/common/cleanup.ps1", - "./windows/common/ultradefrag.ps1", - "./windows/common/sdelete.ps1" - ] - } - ], - "post-processors": [ - { - "type": "vagrant", - "keep_input_artifact": false, - "output": "{{.Provider}}_windows-2012r2_chef.box" - } - ] -} -``` - -autounattend.xml: - -```xml -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend"> - <settings pass="windowsPE"> - <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <SetupUILanguage> - <UILanguage>en-US</UILanguage> - </SetupUILanguage> - <InputLocale>en-US</InputLocale> - <SystemLocale>en-US</SystemLocale> - <UILanguage>en-US</UILanguage> - <UILanguageFallback>en-US</UILanguageFallback> - <UserLocale>en-US</UserLocale> - </component> - <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <!-- Start Non UEFI --> - <DiskConfiguration> - <Disk wcm:action="add"> - <CreatePartitions> - <CreatePartition wcm:action="add"> - <Type>Primary</Type> - <Order>1</Order> - <Size>350</Size> - </CreatePartition> - <CreatePartition wcm:action="add"> - <Order>2</Order> - <Type>Primary</Type> - <Extend>true</Extend> - </CreatePartition> - </CreatePartitions> - <ModifyPartitions> - <ModifyPartition wcm:action="add"> - <Active>true</Active> - <Format>NTFS</Format> - <Label>boot</Label> - <Order>1</Order> - <PartitionID>1</PartitionID> - </ModifyPartition> - <ModifyPartition wcm:action="add"> - <Format>NTFS</Format> - <Label>Windows 2012 R2</Label> - <Letter>C</Letter> - <Order>2</Order> - <PartitionID>2</PartitionID> - </ModifyPartition> - </ModifyPartitions> - <DiskID>0</DiskID> - <WillWipeDisk>true</WillWipeDisk> - </Disk> - </DiskConfiguration> - <ImageInstall> - <OSImage> - <InstallFrom> - <MetaData wcm:action="add"> - <Key>/IMAGE/NAME </Key> - <Value>Windows Server 2012 R2 SERVERSTANDARD</Value> - </MetaData> - </InstallFrom> - <InstallTo> - <DiskID>0</DiskID> - <PartitionID>2</PartitionID> - </InstallTo> - </OSImage> - </ImageInstall> - <!-- Finish Non UEFI --> - <!-- Start UEFI compatible - <DiskConfiguration> - <Disk wcm:action="add"> - <CreatePartitions> - <CreatePartition wcm:action="add"> - <Order>1</Order> - <Size>300</Size> - <Type>Primary</Type> - </CreatePartition> - <CreatePartition wcm:action="add"> - <Order>2</Order> - <Size>100</Size> - <Type>EFI</Type> - </CreatePartition> - <CreatePartition wcm:action="add"> - <Order>3</Order> - <Size>128</Size> - <Type>MSR</Type> - </CreatePartition> - <CreatePartition wcm:action="add"> - <Order>4</Order> - <Extend>true</Extend> - <Type>Primary</Type> - </CreatePartition> - </CreatePartitions> - <ModifyPartitions> - <ModifyPartition wcm:action="add"> - <Order>1</Order> - <PartitionID>1</PartitionID> - <Label>WINRE</Label> - <Format>NTFS</Format> - <TypeID>de94bba4-06d1-4d40-a16a-bfd50179d6ac</TypeID> - </ModifyPartition> - <ModifyPartition wcm:action="add"> - <Order>2</Order> - <PartitionID>2</PartitionID> - <Label>System</Label> - <Format>FAT32</Format> - </ModifyPartition> - <ModifyPartition wcm:action="add"> - <Order>3</Order> - <PartitionID>3</PartitionID> - </ModifyPartition> - <ModifyPartition wcm:action="add"> - <Order>4</Order> - <PartitionID>4</PartitionID> - <Label>Windows</Label> - <Format>NTFS</Format> - </ModifyPartition> - </ModifyPartitions> - <DiskID>0</DiskID> - <WillWipeDisk>true</WillWipeDisk> - </Disk> - <WillShowUI>OnError</WillShowUI> - </DiskConfiguration> - <ImageInstall> - <OSImage> - <InstallFrom> - <MetaData wcm:action="add"> - <Key>/IMAGE/NAME </Key> - <Value>Windows Server 2012 R2 SERVERSTANDARD</Value> - </MetaData> - </InstallFrom> - <InstallTo> - <DiskID>0</DiskID> - <PartitionID>4</PartitionID> - </InstallTo> - </OSImage> - </ImageInstall> - Finish UEFI compatible --> - <UserData> - <!-- Product Key from http://technet.microsoft.com/en-us/library/jj612867.aspx --> - <ProductKey> - <!-- Do not uncomment the Key element if you are using trial ISOs --> - <!-- You must uncomment the Key element (and optionally insert your own key) if you are using retail or volume license ISOs --> - <!--<Key>D2N9P-3P6X9-2R39C-7RTCD-MDVJX</Key>--> - <WillShowUI>OnError</WillShowUI> - </ProductKey> - <AcceptEula>true</AcceptEula> - <FullName>Vagrant</FullName> - <Organization>Vagrant</Organization> - </UserData> - </component> - </settings> - <settings pass="specialize"> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <OEMInformation> - <HelpCustomized>false</HelpCustomized> - </OEMInformation> - <ComputerName>vagrant-2012r2</ComputerName> - <TimeZone>Coordinated Universal Time</TimeZone> - <RegisteredOwner /> - </component> - <component name="Microsoft-Windows-ServerManager-SvrMgrNc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <DoNotOpenServerManagerAtLogon>true</DoNotOpenServerManagerAtLogon> - </component> - <component name="Microsoft-Windows-IE-ESC" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <IEHardenAdmin>false</IEHardenAdmin> - <IEHardenUser>false</IEHardenUser> - </component> - <component name="Microsoft-Windows-OutOfBoxExperience" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <DoNotOpenInitialConfigurationTasksAtLogon>true</DoNotOpenInitialConfigurationTasksAtLogon> - </component> - <component name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <SkipAutoActivation>true</SkipAutoActivation> - </component> - </settings> - <settings pass="oobeSystem"> -<!-- Start Setup cache proxy during installation - <component name="Microsoft-Windows-IE-ClientNetworkProtocolImplementation" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <POLICYProxySettingsPerUser>0</POLICYProxySettingsPerUser> - <HKLMProxyEnable>true</HKLMProxyEnable> - <HKLMProxyServer>cache-proxy:3142</HKLMProxyServer> - </component> -Finish Setup cache proxy during installation --> - <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <AutoLogon> - <Password> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </Password> - <Enabled>true</Enabled> - <Username>vagrant</Username> - </AutoLogon> - <FirstLogonCommands> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine> - <Description>Set Execution Policy 64 Bit</Description> - <Order>1</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>C:\Windows\SysWOW64\cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine> - <Description>Set Execution Policy 32 Bit</Description> - <Order>2</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm quickconfig -q</CommandLine> - <Description>winrm quickconfig -q</Description> - <Order>3</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm quickconfig -transport:http</CommandLine> - <Description>winrm quickconfig -transport:http</Description> - <Order>4</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config @{MaxTimeoutms="1800000"}</CommandLine> - <Description>Win RM MaxTimeoutms</Description> - <Order>5</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/winrs @{MaxMemoryPerShellMB="300"}</CommandLine> - <Description>Win RM MaxMemoryPerShellMB</Description> - <Order>6</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/service @{AllowUnencrypted="true"}</CommandLine> - <Description>Win RM AllowUnencrypted</Description> - <Order>7</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/service/auth @{Basic="true"}</CommandLine> - <Description>Win RM auth Basic</Description> - <Order>8</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/client/auth @{Basic="true"}</CommandLine> - <Description>Win RM client auth Basic</Description> - <Order>9</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/listener?Address=*+Transport=HTTP @{Port="5985"} </CommandLine> - <Description>Win RM listener Address/Port</Description> - <Order>10</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes </CommandLine> - <Description>Win RM adv firewall enable</Description> - <Order>11</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow</CommandLine> - <Description>Win RM port open</Description> - <Order>12</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow</CommandLine> - <Description>Win RM port open</Description> - <Order>13</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c net stop winrm </CommandLine> - <Description>Stop Win RM Service </Description> - <Order>14</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c sc config winrm start= disabled</CommandLine> - <Description>Win RM Autostart</Description> - <Order>15</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v HideFileExt /t REG_DWORD /d 0 /f</CommandLine> - <Order>16</Order> - <Description>Show file extensions in Explorer</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\Console /v QuickEdit /t REG_DWORD /d 1 /f</CommandLine> - <Order>17</Order> - <Description>Enable QuickEdit mode</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v Start_ShowRun /t REG_DWORD /d 1 /f</CommandLine> - <Order>18</Order> - <Description>Show Run command in Start Menu</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v StartMenuAdminTools /t REG_DWORD /d 1 /f</CommandLine> - <Order>19</Order> - <Description>Show Administrative Tools in Start Menu</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateFileSizePercent /t REG_DWORD /d 0 /f</CommandLine> - <Order>20</Order> - <Description>Zero Hibernation File</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateEnabled /t REG_DWORD /d 0 /f</CommandLine> - <Order>21</Order> - <Description>Disable Hibernation Mode</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c wmic useraccount where "name='vagrant'" set PasswordExpires=FALSE</CommandLine> - <Order>22</Order> - <Description>Disable password expiration for vagrant user</Description> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/winrs @{MaxShellsPerUser="30"}</CommandLine> - <Description>Win RM MaxShellsPerUser</Description> - <Order>23</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c winrm set winrm/config/winrs @{MaxProcessesPerShell="25"}</CommandLine> - <Description>Win RM MaxProcessesPerShell</Description> - <Order>24</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>%SystemRoot%\System32\reg.exe ADD "HKLM\System\CurrentControlSet\Services\Netlogon\Parameters" /v DisablePasswordChange /t REG_DWORD /d 1 /f</CommandLine> - <Description>Turn off computer password</Description> - <Order>25</Order> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow</CommandLine> - <Description>ICMP open for ping</Description> - <Order>26</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <!-- WITH WINDOWS UPDATES --> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c IF EXIST a:\set-power-config.ps1 (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\set-power-config.ps1) ELSE (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File f:\set-power-config.ps1)</CommandLine> - <Order>97</Order> - <Description>Turn off all power saving and timeouts</Description> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c IF EXIST a:\microsoft-updates.ps1 (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\microsoft-updates.ps1) ELSE (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File f:\microsoft-updates.ps1)</CommandLine> - <Order>98</Order> - <Description>Enable Microsoft Updates</Description> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <SynchronousCommand wcm:action="add"> - <CommandLine>cmd.exe /c IF EXIST a:\win-updates.ps1 (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\win-updates.ps1) ELSE (C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File f:\win-updates.ps1)</CommandLine> - <Description>Install Windows Updates</Description> - <Order>100</Order> - <RequiresUserInput>true</RequiresUserInput> - </SynchronousCommand> - <!-- END WITH WINDOWS UPDATES --> - </FirstLogonCommands> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <HideLocalAccountScreen>true</HideLocalAccountScreen> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Work</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - <LocalAccounts> - <LocalAccount wcm:action="add"> - <Password> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </Password> - <Group>administrators</Group> - <DisplayName>Vagrant</DisplayName> - <Name>vagrant</Name> - <Description>Vagrant User</Description> - </LocalAccount> - </LocalAccounts> - </UserAccounts> - <RegisteredOwner /> - <TimeZone>Coordinated Universal Time</TimeZone> - </component> - </settings> - <settings pass="offlineServicing"> - <component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <EnableLUA>false</EnableLUA> - </component> - </settings> - <cpi:offlineImage cpi:source="wim:c:/projects/baseboxes/9600.16384.winblue_rtm.130821-1623_x64fre_server_eval_en-us-irm_sss_x64free_en-us_dv5_slipstream/sources/install.wim#Windows Server 2012 R2 SERVERDATACENTER" xmlns:cpi="urn:schemas-microsoft-com:cpi" /> -</unattend> -``` - -sysprep-unattend.xml: - -```xml -<?xml version="1.0" encoding="utf-8"?> -<unattend xmlns="urn:schemas-microsoft-com:unattend"> - <settings pass="generalize"> - <component language="neutral" name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <SkipRearm>1</SkipRearm> - </component> - </settings> - <settings pass="oobeSystem"> -<!-- Setup proxy after sysprep - <component name="Microsoft-Windows-IE-ClientNetworkProtocolImplementation" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <POLICYProxySettingsPerUser>1</POLICYProxySettingsPerUser> - <HKLMProxyEnable>false</HKLMProxyEnable> - <HKLMProxyServer>cache-proxy:3142</HKLMProxyServer> - </component> -Finish proxy after sysprep --> - <component language="neutral" name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <InputLocale>0809:00000809</InputLocale> - <SystemLocale>en-GB</SystemLocale> - <UILanguage>en-US</UILanguage> - <UILanguageFallback>en-US</UILanguageFallback> - <UserLocale>en-GB</UserLocale> - </component> - <component language="neutral" name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <OOBE> - <HideEULAPage>true</HideEULAPage> - <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen> - <HideOnlineAccountScreens>true</HideOnlineAccountScreens> - <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> - <NetworkLocation>Work</NetworkLocation> - <ProtectYourPC>1</ProtectYourPC> - <SkipUserOOBE>true</SkipUserOOBE> - <SkipMachineOOBE>true</SkipMachineOOBE> - </OOBE> - <UserAccounts> - <AdministratorPassword> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </AdministratorPassword> - <LocalAccounts> - <LocalAccount wcm:action="add"> - <Password> - <Value>vagrant</Value> - <PlainText>true</PlainText> - </Password> - <Group>administrators</Group> - <DisplayName>Vagrant</DisplayName> - <Name>vagrant</Name> - <Description>Vagrant User</Description> - </LocalAccount> - </LocalAccounts> - </UserAccounts> - <DisableAutoDaylightTimeSet>true</DisableAutoDaylightTimeSet> - <TimeZone>Coordinated Universal Time</TimeZone> - <VisualEffects> - <SystemDefaultBackgroundColor>2</SystemDefaultBackgroundColor> - </VisualEffects> - </component> - </settings> -</unattend> -``` - --> **Warning:** Please note that if you're setting up WinRM for provisioning, you'll probably want to turn it off or restrict its permissions as part of a shutdown script at the end of Packer's provisioning process. For more details on the why/how, check out this useful blog post and the associated code: -https://cloudywindows.io/post/winrm-for-provisioning-close-the-door-on-the-way-out-eh/ - -## Example For Ubuntu Vivid Generation 2 - -If you are running Windows under virtualization, you may need to create a -virtual switch with an `External` connection type. - -### Packer config: - -```json -{ - "variables": { - "vm_name": "ubuntu-xenial", - "cpu": "2", - "memory": "1024", - "disk_size": "21440", - "iso_url": "http://releases.ubuntu.com/16.04/ubuntu-16.04.1-server-amd64.iso", - "iso_checksum": "sha1:DE5EE8665048F009577763EFBF4A6F0558833E59" - }, - "builders": [ - { - "vm_name": "{{user `vm_name`}}", - "type": "hyperv-iso", - "disk_size": "{{user `disk_size`}}", - "guest_additions_mode": "disable", - "iso_url": "{{user `iso_url`}}", - "iso_checksum": "{{user `iso_checksum`}}", - "communicator": "ssh", - "ssh_username": "packer", - "ssh_password": "packer", - "ssh_timeout": "4h", - "http_directory": "./", - "boot_wait": "5s", - "boot_command": [ - "<esc><wait10><esc><esc><enter><wait>", - "set gfxpayload=1024x768<enter>", - "linux /install/vmlinuz ", - "preseed/url=http://{{.HTTPIP}}:{{.HTTPPort}}/hyperv-taliesins.cfg ", - "debian-installer=en_US auto locale=en_US kbd-chooser/method=us ", - "hostname={{.Name}} ", - "fb=false debconf/frontend=noninteractive ", - "keyboard-configuration/modelcode=SKIP keyboard-configuration/layout=USA ", - "keyboard-configuration/variant=USA console-setup/ask_detect=false <enter>", - "initrd /install/initrd.gz<enter>", - "boot<enter>" - ], - "shutdown_command": "echo 'packer' | sudo -S -E shutdown -P now", - "memory": "{{user `memory`}}", - "cpu": "{{user `cpu`}}", - "generation": 2, - "enable_secure_boot": false - } - ] -} -``` - -### preseed.cfg: - -```text -## Options to set on the command line -d-i debian-installer/locale string en_US.utf8 -d-i console-setup/ask_detect boolean false -d-i console-setup/layout string us - -d-i netcfg/get_hostname string nl-ams-basebox3 -d-i netcfg/get_domain string unassigned-domain - -d-i time/zone string UTC -d-i clock-setup/utc-auto boolean true -d-i clock-setup/utc boolean true - -d-i kbd-chooser/method select American English - -d-i netcfg/wireless_wep string - -d-i base-installer/kernel/override-image string linux-server - -d-i debconf debconf/frontend select Noninteractive - -d-i pkgsel/install-language-support boolean false -tasksel tasksel/first multiselect standard, ubuntu-server - -## Partitioning -d-i partman-auto/method string lvm - -d-i partman-lvm/confirm boolean true -d-i partman-lvm/device_remove_lvm boolean true -d-i partman-lvm/confirm boolean true - -d-i partman-auto-lvm/guided_size string max -d-i partman-auto/choose_recipe select atomic - -d-i partman/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 - -# Write the changes to disks and configure LVM? -d-i partman-lvm/confirm boolean true -d-i partman-lvm/confirm_nooverwrite boolean true - -d-i partman-partitioning/no_bootable_gpt_biosgrub boolean false -d-i partman-partitioning/no_bootable_gpt_efi boolean false -d-i partman-efi/non_efi_system boolean true - -# Default user -d-i passwd/user-fullname string packer -d-i passwd/username string packer -d-i passwd/user-password password packer -d-i passwd/user-password-again password packer -d-i user-setup/encrypt-home boolean false -d-i user-setup/allow-password-weak boolean true - -# Minimum packages -d-i pkgsel/include string openssh-server ntp linux-tools-$(uname -r) linux-cloud-tools-$(uname -r) linux-cloud-tools-common - -# Upgrade packages after debootstrap? (none, safe-upgrade, full-upgrade) -# (note: set to none for speed) -d-i pkgsel/upgrade select none - -d-i grub-installer/only_debian boolean true -d-i grub-installer/with_other_os boolean true -d-i finish-install/reboot_in_progress note - -d-i pkgsel/update-policy select none - -choose-mirror-bin mirror/http/proxy string -``` diff --git a/website/content/partials/builder/hyperv/common/CommonConfig-not-required.mdx b/website/content/partials/builder/hyperv/common/CommonConfig-not-required.mdx deleted file mode 100644 index 29344edb3..000000000 --- a/website/content/partials/builder/hyperv/common/CommonConfig-not-required.mdx +++ /dev/null @@ -1,141 +0,0 @@ -<!-- Code generated from the comments of the CommonConfig struct in builder/hyperv/common/config.go; DO NOT EDIT MANUALLY --> - -- `disk_block_size` (uint) - The block size of the VHD to be created. - Recommended disk block size for Linux hyper-v guests is 1 MiB. This - defaults to "32" MiB. - -- `memory` (uint) - The amount, in megabytes, of RAM to assign to the - VM. By default, this is 1 GB. - -- `secondary_iso_images` ([]string) - A list of ISO paths to - attach to a VM when it is booted. This is most useful for unattended - Windows installs, which look for an Autounattend.xml file on removable - media. By default, no secondary ISO will be attached. - -- `disk_additional_size` ([]uint) - The size or sizes of any - additional hard disks for the VM in megabytes. If this is not specified - then the VM will only contain a primary hard disk. Additional drives - will be attached to the SCSI interface only. The builder uses - expandable rather than fixed-size virtual hard disks, so the actual - file representing the disk will not use the full size unless it is - full. - -- `guest_additions_mode` (string) - If set to attach then attach and - mount the ISO image specified in guest_additions_path. If set to - none then guest additions are not attached and mounted; This is the - default. - -- `guest_additions_path` (string) - The path to the ISO image for guest - additions. - -- `vm_name` (string) - This is the name of the new virtual machine, - without the file extension. By default this is "packer-BUILDNAME", - where "BUILDNAME" is the name of the build. - -- `switch_name` (string) - The name of the switch to connect the virtual - machine to. By default, leaving this value unset will cause Packer to - try and determine the switch to use by looking for an external switch - that is up and running. - -- `switch_vlan_id` (string) - This is the VLAN of the virtual switch's - network card. By default none is set. If none is set then a VLAN is not - set on the switch's network card. If this value is set it should match - the VLAN specified in by vlan_id. - -- `mac_address` (string) - This allows a specific MAC address to be used on - the default virtual network card. The MAC address must be a string with - no delimiters, for example "0000deadbeef". - -- `vlan_id` (string) - This is the VLAN of the virtual machine's network - card for the new virtual machine. By default none is set. If none is set - then VLANs are not set on the virtual machine's network card. - -- `cpus` (uint) - The number of CPUs the virtual machine should use. If - this isn't specified, the default is 1 CPU. - -- `generation` (uint) - The Hyper-V generation for the virtual machine. By - default, this is 1. Generation 2 Hyper-V virtual machines do not support - floppy drives. In this scenario use secondary_iso_images instead. Hard - drives and DVD drives will also be SCSI and not IDE. - -- `enable_mac_spoofing` (bool) - If true enable MAC address spoofing - for the virtual machine. This defaults to false. - -- `enable_dynamic_memory` (bool) - If true enable dynamic memory for - the virtual machine. This defaults to false. - -- `enable_secure_boot` (bool) - If true enable secure boot for the - virtual machine. This defaults to false. See secure_boot_template - below for additional settings. - -- `secure_boot_template` (string) - The secure boot template to be - configured. Valid values are "MicrosoftWindows" (Windows) or - "MicrosoftUEFICertificateAuthority" (Linux). This only takes effect if - enable_secure_boot is set to "true". This defaults to "MicrosoftWindows". - -- `enable_virtualization_extensions` (bool) - If true enable - virtualization extensions for the virtual machine. This defaults to - false. For nested virtualization you need to enable MAC spoofing, - disable dynamic memory and have at least 4GB of RAM assigned to the - virtual machine. - -- `temp_path` (string) - The location under which Packer will create a directory to house all the - VM files and folders during the build. By default `%TEMP%` is used - which, for most systems, will evaluate to - `%USERPROFILE%/AppData/Local/Temp`. - - The build directory housed under `temp_path` will have a name similar to - `packerhv1234567`. The seven digit number at the end of the name is - automatically generated by Packer to ensure the directory name is - unique. - -- `configuration_version` (string) - This allows you to set the vm version when calling New-VM to generate - the vm. - -- `keep_registered` (bool) - If "true", Packer will not delete the VM from - The Hyper-V manager. - -- `skip_compaction` (bool) - If true skip compacting the hard disk for - the virtual machine when exporting. This defaults to false. - -- `skip_export` (bool) - If true Packer will skip the export of the VM. - If you are interested only in the VHD/VHDX files, you can enable this - option. The resulting VHD/VHDX file will be output to - <output_directory>/Virtual Hard Disks. By default this option is false - and Packer will export the VM to output_directory. - -- `headless` (bool) - Packer defaults to building Hyper-V virtual - machines by launching a GUI that shows the console of the machine being - built. When this value is set to true, the machine will start without a - console. - -- `first_boot_device` (string) - When configured, determines the device or device type that is given preferential - treatment when choosing a boot device. - - For Generation 1: - - `IDE` - - `CD` *or* `DVD` - - `Floppy` - - `NET` - - For Generation 2: - - `IDE:x:y` - - `SCSI:x:y` - - `CD` *or* `DVD` - - `NET` - -- `boot_order` ([]string) - When configured, the boot order determines the order of the devices - from which to boot. - - The device name must be in the form of `SCSI:x:y`, for example, - to boot from the first scsi device use `SCSI:0:0`. - - **NB** You should also set `first_boot_device` (e.g. `DVD`). - - **NB** Although the VM will have this initial boot order, the OS can - change it, for example, Ubuntu 18.04 will modify the boot order to - include itself as the first boot option. - - **NB** This only works for Generation 2 machines. - -<!-- End of code generated from the comments of the CommonConfig struct in builder/hyperv/common/config.go; --> diff --git a/website/content/partials/builder/hyperv/common/OutputConfig-not-required.mdx b/website/content/partials/builder/hyperv/common/OutputConfig-not-required.mdx deleted file mode 100644 index 7fe7d5ce4..000000000 --- a/website/content/partials/builder/hyperv/common/OutputConfig-not-required.mdx +++ /dev/null @@ -1,11 +0,0 @@ -<!-- Code generated from the comments of the OutputConfig struct in builder/hyperv/common/output_config.go; DO NOT EDIT MANUALLY --> - -- `output_directory` (string) - This setting specifies the directory that - artifacts from the build, such as the virtual machine files and disks, - will be output to. The path to the directory may be relative or - absolute. If relative, the path is relative to the working directory - packer is executed from. This directory must not exist or, if - created, must be empty prior to running the builder. By default this is - "output-BUILDNAME" where "BUILDNAME" is the name of the build. - -<!-- End of code generated from the comments of the OutputConfig struct in builder/hyperv/common/output_config.go; --> diff --git a/website/content/partials/builder/hyperv/iso/Builder.mdx b/website/content/partials/builder/hyperv/iso/Builder.mdx deleted file mode 100644 index 779bc2330..000000000 --- a/website/content/partials/builder/hyperv/iso/Builder.mdx +++ /dev/null @@ -1,6 +0,0 @@ -<!-- Code generated from the comments of the Builder struct in builder/hyperv/iso/builder.go; DO NOT EDIT MANUALLY --> - -Builder implements packersdk.Builder and builds the actual Hyperv -images. - -<!-- End of code generated from the comments of the Builder struct in builder/hyperv/iso/builder.go; --> diff --git a/website/content/partials/builder/hyperv/iso/Config-not-required.mdx b/website/content/partials/builder/hyperv/iso/Config-not-required.mdx deleted file mode 100644 index 0554b02cb..000000000 --- a/website/content/partials/builder/hyperv/iso/Config-not-required.mdx +++ /dev/null @@ -1,24 +0,0 @@ -<!-- Code generated from the comments of the Config struct in builder/hyperv/iso/builder.go; DO NOT EDIT MANUALLY --> - -- `disk_size` (uint) - The size, in megabytes, of the hard disk to create - for the VM. By default, this is 40 GB. - -- `use_legacy_network_adapter` (bool) - If true use a legacy network adapter as the NIC. - This defaults to false. A legacy network adapter is fully emulated NIC, and is thus - supported by various exotic operating systems, but this emulation requires - additional overhead and should only be used if absolutely necessary. - -- `differencing_disk` (bool) - If true enables differencing disks. Only - the changes will be written to the new disk. This is especially useful if - your source is a VHD/VHDX. This defaults to false. - -- `use_fixed_vhd_format` (bool) - If true, creates the boot disk on the - virtual machine as a fixed VHD format disk. The default is false, which - creates a dynamic VHDX format disk. This option requires setting - generation to 1, skip_compaction to true, and - differencing_disk to false. Additionally, any value entered for - disk_block_size will be ignored. The most likely use case for this - option is outputing a disk that is in the format required for upload to - Azure. - -<!-- End of code generated from the comments of the Config struct in builder/hyperv/iso/builder.go; --> diff --git a/website/content/partials/builder/hyperv/vmcx/Builder.mdx b/website/content/partials/builder/hyperv/vmcx/Builder.mdx deleted file mode 100644 index 1670a5e47..000000000 --- a/website/content/partials/builder/hyperv/vmcx/Builder.mdx +++ /dev/null @@ -1,6 +0,0 @@ -<!-- Code generated from the comments of the Builder struct in builder/hyperv/vmcx/builder.go; DO NOT EDIT MANUALLY --> - -Builder implements packersdk.Builder and builds the actual Hyperv -images. - -<!-- End of code generated from the comments of the Builder struct in builder/hyperv/vmcx/builder.go; --> diff --git a/website/content/partials/builder/hyperv/vmcx/Config-not-required.mdx b/website/content/partials/builder/hyperv/vmcx/Config-not-required.mdx deleted file mode 100644 index fd2b6c65f..000000000 --- a/website/content/partials/builder/hyperv/vmcx/Config-not-required.mdx +++ /dev/null @@ -1,25 +0,0 @@ -<!-- Code generated from the comments of the Config struct in builder/hyperv/vmcx/builder.go; DO NOT EDIT MANUALLY --> - -- `clone_from_vmcx_path` (string) - This is the path to a directory containing an exported virtual machine. - -- `clone_from_vm_name` (string) - This is the name of the virtual machine to clone from. - -- `clone_from_snapshot_name` (string) - The name of a snapshot in the - source machine to use as a starting point for the clone. If the value - given is an empty string, the last snapshot present in the source will - be chosen as the starting point for the new VM. - -- `clone_all_snapshots` (bool) - If set to true all snapshots - present in the source machine will be copied when the machine is - cloned. The final result of the build will be an exported virtual - machine that contains all the snapshots of the parent. - -- `differencing_disk` (bool) - If true enables differencing disks. Only - the changes will be written to the new disk. This is especially useful if - your source is a VHD/VHDX. This defaults to false. - -- `copy_in_compare` (bool) - When cloning a vm to build from, we run a powershell - Compare-VM command, which, depending on your version of Windows, may need - the "Copy" flag to be set to true or false. Defaults to "false". Command: - -<!-- End of code generated from the comments of the Config struct in builder/hyperv/vmcx/builder.go; --> diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index 2d6a2c93f..b84549af3 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -708,23 +708,6 @@ "title": "Hetzner Cloud", "path": "builders/hetzner-cloud" }, - { - "title": "Hyper-V", - "routes": [ - { - "title": "Overview", - "path": "builders/hyperv" - }, - { - "title": "ISO", - "path": "builders/hyperv/iso" - }, - { - "title": "VMCX", - "path": "builders/hyperv/vmcx" - } - ] - }, { "title": "Linode", "path": "builders/linode" diff --git a/website/data/docs-remote-plugins.json b/website/data/docs-remote-plugins.json index 60cc3bcc4..d42194d15 100644 --- a/website/data/docs-remote-plugins.json +++ b/website/data/docs-remote-plugins.json @@ -52,6 +52,13 @@ "version": "latest", "pluginTier": "community" }, + { + "title": "Hyper-V", + "path": "hyperv", + "repo": "hashicorp/packer-plugin-hyperv", + "version": "latest", + "pluginTier": "community" + }, { "title": "Naver Cloud", "path": "ncloud",