Can specify an iso, vhd or vhdx for download. If it is a vhd or vhdx it is used as the hard drive for spinning up a new machine, importing an exported virtual machine or cloning a virtual machine.
Can import a virtual machine from a folder Can clone an existing virtual machine
This commit is contained in:
parent
452fcbd9a1
commit
efa62e1550
@ -64,9 +64,9 @@ type Driver interface {
|
||||
|
||||
DeleteVirtualSwitch(string) error
|
||||
|
||||
CreateVirtualMachine(string, string, string, int64, int64, string, uint) error
|
||||
CreateVirtualMachine(string, string, string, string, int64, int64, string, uint) error
|
||||
|
||||
CloneVirtualMachine(string, string, bool, string, string, int64, string) error
|
||||
CloneVirtualMachine(string, string, string, bool, string, string, string, int64, string) error
|
||||
|
||||
DeleteVirtualMachine(string) error
|
||||
|
||||
|
@ -170,12 +170,12 @@ func (d *HypervPS4Driver) CreateVirtualSwitch(switchName string, switchType stri
|
||||
return hyperv.CreateVirtualSwitch(switchName, switchType)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, vhdPath string, ram int64, diskSize int64, switchName string, generation uint) error {
|
||||
return hyperv.CreateVirtualMachine(vmName, path, vhdPath, ram, diskSize, switchName, generation)
|
||||
func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, switchName string, generation uint) error {
|
||||
return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, vhdPath, ram, diskSize, switchName, generation)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) CloneVirtualMachine(cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, ram int64, switchName string) error {
|
||||
return hyperv.CloneVirtualMachine(cloneFromVmName, cloneFromSnapshotName, cloneAllSnapshots, vmName, path, ram, switchName)
|
||||
func (d *HypervPS4Driver) CloneVirtualMachine(cloneFromVmxcPath string, cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string, ram int64, switchName string) error {
|
||||
return hyperv.CloneVirtualMachine(cloneFromVmxcPath, cloneFromVmName, cloneFromSnapshotName, cloneAllSnapshots, vmName, path, harddrivePath, ram, switchName)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) DeleteVirtualMachine(vmName string) error {
|
||||
|
@ -2,9 +2,12 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
// This step clones an existing virtual machine.
|
||||
@ -12,6 +15,7 @@ import (
|
||||
// Produces:
|
||||
// VMName string - The name of the VM
|
||||
type StepCloneVM struct {
|
||||
CloneFromVMXCPath string
|
||||
CloneFromVMName string
|
||||
CloneFromSnapshotName string
|
||||
CloneAllSnapshots bool
|
||||
@ -31,11 +35,24 @@ func (s *StepCloneVM) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Say("Cloning virtual machine...")
|
||||
|
||||
path := state.Get("packerTempDir").(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.CloneFromVMName, s.CloneFromSnapshotName, s.CloneAllSnapshots, s.VMName, path, ramSize, s.SwitchName)
|
||||
err := driver.CloneVirtualMachine(s.CloneFromVMXCPath, s.CloneFromVMName, s.CloneFromSnapshotName, s.CloneAllSnapshots, s.VMName, path, harddrivePath, ramSize, s.SwitchName)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error cloning virtual machine: %s", err)
|
||||
state.Put("error", err)
|
||||
|
@ -2,7 +2,10 @@ package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"log"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/mitchellh/multistep"
|
||||
)
|
||||
@ -14,6 +17,7 @@ import (
|
||||
type StepCreateVM struct {
|
||||
VMName string
|
||||
SwitchName string
|
||||
HarddrivePath string
|
||||
RamSize uint
|
||||
DiskSize uint
|
||||
Generation uint
|
||||
@ -30,13 +34,26 @@ func (s *StepCreateVM) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ui.Say("Creating virtual machine...")
|
||||
|
||||
path := state.Get("packerTempDir").(string)
|
||||
vhdPath := state.Get("packerVhdTempDir").(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.")
|
||||
}
|
||||
|
||||
vhdPath := state.Get("packerVhdTempDir").(string)
|
||||
// convert the MB to bytes
|
||||
ramSize := int64(s.RamSize * 1024 * 1024)
|
||||
diskSize := int64(s.DiskSize * 1024 * 1024)
|
||||
|
||||
err := driver.CreateVirtualMachine(s.VMName, path, vhdPath, ramSize, diskSize, s.SwitchName, s.Generation)
|
||||
err := driver.CreateVirtualMachine(s.VMName, path, harddrivePath, vhdPath, ramSize, diskSize, s.SwitchName, s.Generation)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating virtual machine: %s", err)
|
||||
state.Put("error", err)
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"path/filepath"
|
||||
|
||||
hypervcommon "github.com/hashicorp/packer/builder/hyperv/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
@ -117,16 +118,26 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
warnings = append(warnings, isoWarnings...)
|
||||
errs = packer.MultiErrorAppend(errs, isoErrs...)
|
||||
|
||||
if len(b.config.ISOConfig.ISOUrls) > 0 {
|
||||
extension := strings.ToLower(filepath.Ext(b.config.ISOConfig.ISOUrls[0]))
|
||||
if extension == "vhd" || extension == "vhdx" {
|
||||
b.config.ISOConfig.TargetExtension = extension
|
||||
}
|
||||
}
|
||||
|
||||
errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.HTTPConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.OutputConfig.Prepare(&b.config.ctx, &b.config.PackerConfig)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.SSHConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...)
|
||||
|
||||
err = b.checkDiskSize()
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
if b.config.ISOConfig.TargetExtension != "vhd" && b.config.ISOConfig.TargetExtension != "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 = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = b.checkRamSize()
|
||||
@ -163,6 +174,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
log.Println(fmt.Sprintf("%s: %v", "SwitchName", b.config.SwitchName))
|
||||
|
||||
// Errors
|
||||
|
||||
if b.config.GuestAdditionsMode == "" {
|
||||
if b.config.GuestAdditionsPath != "" {
|
||||
b.config.GuestAdditionsMode = "attach"
|
||||
|
@ -235,7 +235,7 @@ func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
delete(config, "iso_url")
|
||||
delete(config, "iso_urls")
|
||||
|
||||
// Test both epty
|
||||
// Test both empty
|
||||
config["iso_url"] = ""
|
||||
b = Builder{}
|
||||
warns, err := b.Prepare(config)
|
||||
|
@ -7,15 +7,16 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
hypervcommon "github.com/hashicorp/packer/builder/hyperv/common"
|
||||
"github.com/hashicorp/packer/common"
|
||||
powershell "github.com/hashicorp/packer/common/powershell"
|
||||
"github.com/hashicorp/packer/common/powershell/hyperv"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/config"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
"github.com/mitchellh/multistep"
|
||||
hypervcommon "github.com/mitchellh/packer/builder/hyperv/common"
|
||||
"github.com/mitchellh/packer/common"
|
||||
powershell "github.com/mitchellh/packer/common/powershell"
|
||||
"github.com/mitchellh/packer/common/powershell/hyperv"
|
||||
"github.com/mitchellh/packer/helper/communicator"
|
||||
"github.com/mitchellh/packer/helper/config"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -69,6 +70,9 @@ type Config struct {
|
||||
// The path to the integration services iso
|
||||
GuestAdditionsPath string `mapstructure:"guest_additions_path"`
|
||||
|
||||
// This is the path to a directory containing an exported virtual machine.
|
||||
CloneFromVMXCPath string `mapstructure:"clone_from_vmxc_path"`
|
||||
|
||||
// This is the name of the virtual machine to clone from.
|
||||
CloneFromVMName string `mapstructure:"clone_from_vm_name"`
|
||||
|
||||
@ -122,6 +126,11 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
isoWarnings, isoErrs := b.config.ISOConfig.Prepare(&b.config.ctx)
|
||||
warnings = append(warnings, isoWarnings...)
|
||||
errs = packer.MultiErrorAppend(errs, isoErrs...)
|
||||
|
||||
extension := strings.ToLower(filepath.Ext(b.config.ISOConfig.ISOUrls[0]))
|
||||
if extension == "vhd" || extension == "vhdx" {
|
||||
b.config.ISOConfig.TargetExtension = extension
|
||||
}
|
||||
}
|
||||
|
||||
errs = packer.MultiErrorAppend(errs, b.config.FloppyConfig.Prepare(&b.config.ctx)...)
|
||||
@ -153,7 +162,9 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
b.config.Generation = 1
|
||||
|
||||
if b.config.CloneFromVMName == "" {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("The clone_from_vm_name must be specified."))
|
||||
if b.config.CloneFromVMXCPath == "" {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("The clone_from_vm_name must be specified if clone_from_vmxc_path is not specified."))
|
||||
}
|
||||
} else {
|
||||
virtualMachineExists, err := powershell.DoesVirtualMachineExist(b.config.CloneFromVMName)
|
||||
if err != nil {
|
||||
@ -190,8 +201,21 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if b.config.CloneFromVMXCPath == "" {
|
||||
if b.config.CloneFromVMName == "" {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("The clone_from_vmxc_path be specified if clone_from_vm_name must is not specified."))
|
||||
}
|
||||
} else {
|
||||
if _, err := os.Stat(b.config.CloneFromVMXCPath); os.IsNotExist(err) {
|
||||
if err != nil {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, fmt.Errorf("CloneFromVMXCPath does not exist: %s", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if b.config.Generation != 2 {
|
||||
if b.config.Generation != 1 || b.config.Generation != 2 {
|
||||
b.config.Generation = 1
|
||||
}
|
||||
|
||||
@ -377,6 +401,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
SwitchName: b.config.SwitchName,
|
||||
},
|
||||
&hypervcommon.StepCloneVM{
|
||||
CloneFromVMXCPath: b.config.CloneFromVMXCPath,
|
||||
CloneFromVMName: b.config.CloneFromVMName,
|
||||
CloneFromSnapshotName: b.config.CloneFromSnapshotName,
|
||||
CloneAllSnapshots: b.config.CloneAllSnapshots,
|
||||
|
@ -4,7 +4,9 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
@ -15,8 +17,8 @@ func testConfig() map[string]interface{} {
|
||||
"shutdown_command": "yes",
|
||||
"ssh_username": "foo",
|
||||
"ram_size": 64,
|
||||
"disk_size": 256,
|
||||
"guest_additions_mode": "none",
|
||||
"clone_from_vmxc_path": "generated",
|
||||
packer.BuildNameConfigKey: "foo",
|
||||
}
|
||||
}
|
||||
@ -33,6 +35,14 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
//Create vmxc folder
|
||||
td, err := ioutil.TempDir("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
config["clone_from_vmxc_path"] = td
|
||||
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
@ -46,42 +56,18 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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_InvalidKey(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
//Create vmxc folder
|
||||
td, err := ioutil.TempDir("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
config["clone_from_vmxc_path"] = td
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
warns, err := b.Prepare(config)
|
||||
@ -97,6 +83,14 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
//Create vmxc folder
|
||||
td, err := ioutil.TempDir("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
config["clone_from_vmxc_path"] = td
|
||||
|
||||
// Test bad
|
||||
config["iso_checksum"] = ""
|
||||
warns, err := b.Prepare(config)
|
||||
@ -127,6 +121,14 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
//Create vmxc folder
|
||||
td, err := ioutil.TempDir("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
config["clone_from_vmxc_path"] = td
|
||||
|
||||
// Test bad
|
||||
config["iso_checksum_type"] = ""
|
||||
warns, err := b.Prepare(config)
|
||||
@ -182,18 +184,27 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
//Create vmxc folder
|
||||
td, err := ioutil.TempDir("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(td)
|
||||
config["clone_from_vmxc_path"] = td
|
||||
|
||||
delete(config, "iso_url")
|
||||
delete(config, "iso_urls")
|
||||
|
||||
// Test both epty
|
||||
// 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 have error")
|
||||
if err != nil {
|
||||
t.Fatal("should not have an error")
|
||||
}
|
||||
|
||||
// Test iso_url set
|
||||
|
@ -26,8 +26,12 @@ import (
|
||||
filebuilder "github.com/hashicorp/packer/builder/file"
|
||||
googlecomputebuilder "github.com/hashicorp/packer/builder/googlecompute"
|
||||
hypervisobuilder "github.com/hashicorp/packer/builder/hyperv/iso"
|
||||
<<<<<<< HEAD
|
||||
lxcbuilder "github.com/hashicorp/packer/builder/lxc"
|
||||
lxdbuilder "github.com/hashicorp/packer/builder/lxd"
|
||||
=======
|
||||
hypervvmcxbuilder "github.com/hashicorp/packer/builder/hyperv/vmcx"
|
||||
>>>>>>> Can specify an iso, vhd or vhdx for download. If it is a vhd or vhdx it is used as the hard drive for spinning up a new machine, importing an exported virtual machine or cloning a virtual machine.
|
||||
nullbuilder "github.com/hashicorp/packer/builder/null"
|
||||
oneandonebuilder "github.com/hashicorp/packer/builder/oneandone"
|
||||
openstackbuilder "github.com/hashicorp/packer/builder/openstack"
|
||||
|
@ -187,28 +187,38 @@ Set-VMFloppyDiskDrive -VMName $vmName -Path $null
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateVirtualMachine(vmName string, path string, vhdRoot string, ram int64, diskSize int64, switchName string, generation uint) error {
|
||||
func CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdRoot string, ram int64, diskSize int64, switchName string, generation uint) error {
|
||||
|
||||
if generation == 2 {
|
||||
var script = `
|
||||
param([string]$vmName, [string]$path, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName, [int]$generation)
|
||||
param([string]$vmName, [string]$path, [string]$harddrivePath, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName, [int]$generation)
|
||||
$vhdx = $vmName + '.vhdx'
|
||||
$vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdx
|
||||
New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName -Generation $generation
|
||||
if ($harddrivePath){
|
||||
Copy-Item -Path $harddrivePath -Destination $vhdPath
|
||||
New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -VHDPath $vhdPath -SwitchName $switchName -Generation $generation
|
||||
} else {
|
||||
New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName -Generation $generation
|
||||
}
|
||||
`
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, vmName, path, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName, strconv.FormatInt(int64(generation), 10))
|
||||
err := ps.Run(script, vmName, path, harddrivePath, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName, strconv.FormatInt(int64(generation), 10))
|
||||
return err
|
||||
} else {
|
||||
var script = `
|
||||
param([string]$vmName, [string]$path, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName)
|
||||
param([string]$vmName, [string]$path, [string]$harddrivePath, [string]$vhdRoot, [long]$memoryStartupBytes, [long]$newVHDSizeBytes, [string]$switchName)
|
||||
$vhdx = $vmName + '.vhdx'
|
||||
$vhdPath = Join-Path -Path $vhdRoot -ChildPath $vhdx
|
||||
New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName
|
||||
if ($harddrivePath){
|
||||
Copy-Item -Path $harddrivePath -Destination $vhdPath
|
||||
New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -VHDPath $vhdPath -SwitchName $switchName
|
||||
} else {
|
||||
New-VM -Name $vmName -Path $path -MemoryStartupBytes $memoryStartupBytes -NewVHDPath $vhdPath -NewVHDSizeBytes $newVHDSizeBytes -SwitchName $switchName
|
||||
}
|
||||
`
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, vmName, path, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName)
|
||||
|
||||
err := ps.Run(script, vmName, path, harddrivePath, vhdRoot, strconv.FormatInt(ram, 10), strconv.FormatInt(diskSize, 10), switchName)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -234,58 +244,111 @@ if ((Get-Command Set-Vm).Parameters["AutomaticCheckpointsEnabled"]) {
|
||||
return err
|
||||
}
|
||||
|
||||
func DisableAutomaticCheckpoints(vmName string) error {
|
||||
func ExportVmxcVirtualMachine(exportPath string, vmName string, snapshotName string, allSnapshots bool) error {
|
||||
var script = `
|
||||
param([string]$vmName)
|
||||
if ((Get-Command Set-Vm).Parameters["AutomaticCheckpointsEnabled"]) {
|
||||
Set-Vm -Name $vmName -AutomaticCheckpointsEnabled $false }
|
||||
`
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, vmName)
|
||||
return err
|
||||
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!"
|
||||
}
|
||||
|
||||
func CloneVirtualMachine(cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, ram int64, switchName string) error {
|
||||
$allSnapshots = [System.Boolean]::Parse($allSnapshotsString)
|
||||
|
||||
var script = `
|
||||
param([string]$CloneFromVMName, [string]$CloneFromSnapshotName, [string]$CloneAllSnapshotsString, [string]$vmName, [string]$path, [long]$memoryStartupBytes, [string]$switchName)
|
||||
|
||||
$CloneAllSnapshots = [System.Boolean]::Parse($CloneAllSnapshotsString)
|
||||
|
||||
$ExportPath = Join-Path $path $VMName
|
||||
|
||||
if ($CloneFromSnapshotName) {
|
||||
$snapshot = Get-VMSnapshot -VMName $CloneFromVMName -Name $CloneFromSnapshotName
|
||||
Export-VMSnapshot -VMSnapshot $snapshot -Path $ExportPath -ErrorAction Stop
|
||||
if ($snapshotName) {
|
||||
$snapshot = Get-VMSnapshot -VMName $vmName -Name $snapshotName
|
||||
Export-VMSnapshot -VMSnapshot $snapshot -Path $exportPath -ErrorAction Stop
|
||||
} else {
|
||||
if (!$CloneAllSnapshots) {
|
||||
if (!$allSnapshots) {
|
||||
#Use last snapshot if one was not specified
|
||||
$snapshot = Get-VMSnapshot -VMName $CloneFromVMName | Select -Last 1
|
||||
$snapshot = Get-VMSnapshot -VMName $vmName | Select -Last 1
|
||||
} else {
|
||||
$snapshot = $null
|
||||
}
|
||||
|
||||
if (!$snapshot) {
|
||||
#No snapshot clone
|
||||
Export-VM -Name $CloneFromVMName -Path $ExportPath -ErrorAction Stop
|
||||
Export-VM -Name $vmName -Path $exportPath -ErrorAction Stop
|
||||
} else {
|
||||
#Snapshot clone
|
||||
Export-VMSnapshot -VMSnapshot $snapshot -Path $ExportPath -ErrorAction Stop
|
||||
Export-VMSnapshot -VMSnapshot $snapshot -Path $exportPath -ErrorAction Stop
|
||||
}
|
||||
}
|
||||
|
||||
$result = Get-ChildItem -Path (Join-Path $ExportPath $CloneFromVMName) | Move-Item -Destination $ExportPath -Force
|
||||
$result = Remove-Item -Path (Join-Path $ExportPath $CloneFromVMName)
|
||||
$result = Get-ChildItem -Path $WorkingPath | Move-Item -Destination $exportPath -Force
|
||||
$result = Remove-Item -Path $WorkingPath
|
||||
`
|
||||
|
||||
$VirtualMachinePath = Get-ChildItem -Path (Join-Path $ExportPath 'Virtual Machines') -Filter *.vmcx -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName}
|
||||
if (!$VirtualMachinePath){
|
||||
$VirtualMachinePath = Get-ChildItem -Path (Join-Path $ExportPath 'Virtual Machines') -Filter *.xml -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName}
|
||||
}
|
||||
if (!$VirtualMachinePath){
|
||||
$VirtualMachinePath = Get-ChildItem -Path $ExportPath -Filter *.xml -Recurse -ErrorAction SilentlyContinue | select -First 1 | %{$_.FullName}
|
||||
allSnapshotsString := "False"
|
||||
if allSnapshots {
|
||||
allSnapshotsString = "True"
|
||||
}
|
||||
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, exportPath, vmName, snapshotName, allSnapshotsString)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
$compatibilityReport = Compare-VM -Path $VirtualMachinePath -VirtualMachinePath $ExportPath -SmartPagingFilePath $ExportPath -SnapshotFilePath $ExportPath -VhdDestinationPath (Join-Path -Path $ExportPath -ChildPath 'Virtual Hard Disks') -GenerateNewId -Copy:$false
|
||||
func CopyVmxcVirtualMachine(exportPath string, cloneFromVmxcPath string) error {
|
||||
var script = `
|
||||
param([string]$exportPath, [string]$cloneFromVmxcPath)
|
||||
if (!(Test-Path $cloneFromVmxcPath)){
|
||||
throw "Clone from vmxc directory: $cloneFromVmxcPath does not exist!"
|
||||
}
|
||||
|
||||
if (!(Test-Path $exportPath)){
|
||||
New-Item -ItemType Directory -Force -Path $exportPath
|
||||
}
|
||||
$cloneFromVmxcPath = Join-Path $cloneFromVmxcPath '\*'
|
||||
Copy-Item $cloneFromVmxcPath $exportPath -Recurse -Force
|
||||
`
|
||||
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, exportPath, cloneFromVmxcPath)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func ImportVmxcVirtualMachine(importPath string, vmName string, harddrivePath string, ram int64, switchName string) error {
|
||||
var script = `
|
||||
param([string]$importPath, [string]$vmName, [string]$harddrivePath, [long]$memoryStartupBytes, [string]$switchName)
|
||||
|
||||
$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}
|
||||
}
|
||||
|
||||
$compatibilityReport = 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 | Set-VMHardDiskDrive -Path $vhdPath
|
||||
} else {
|
||||
Add-VMHardDiskDrive -VM $compatibilityReport.VM -Path $vhdPath
|
||||
}
|
||||
}
|
||||
Set-VMMemory -VM $compatibilityReport.VM -StartupBytes $memoryStartupBytes
|
||||
$networkAdaptor = $compatibilityReport.VM.NetworkAdapters | Select -First 1
|
||||
Disconnect-VMNetworkAdapter -VMNetworkAdapter $networkAdaptor
|
||||
@ -295,22 +358,35 @@ $vm = Import-VM -CompatibilityReport $compatibilityReport
|
||||
if ($vm) {
|
||||
$result = Rename-VM -VM $vm -NewName $VMName
|
||||
}
|
||||
`
|
||||
|
||||
CloneAllSnapshotsString := "False"
|
||||
if cloneAllSnapshots {
|
||||
CloneAllSnapshotsString = "True"
|
||||
}
|
||||
`
|
||||
|
||||
var ps powershell.PowerShellCmd
|
||||
err := ps.Run(script, cloneFromVmName, cloneFromSnapshotName, CloneAllSnapshotsString, vmName, path, strconv.FormatInt(ram, 10), switchName)
|
||||
err := ps.Run(script, importPath, vmName, harddrivePath, strconv.FormatInt(ram, 10), switchName)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func CloneVirtualMachine(cloneFromVmxcPath string, cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string, ram int64, switchName string) error {
|
||||
if cloneFromVmName != "" {
|
||||
err := ExportVmxcVirtualMachine(path, cloneFromVmName, cloneFromSnapshotName, cloneAllSnapshots)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if cloneFromVmxcPath != "" {
|
||||
err := CopyVmxcVirtualMachine(path, cloneFromVmxcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := ImportVmxcVirtualMachine(path, vmName, harddrivePath, ram, switchName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return DeleteAllDvdDrives(vmName)
|
||||
|
||||
}
|
||||
|
||||
func GetVirtualMachineGeneration(vmName string) (uint, error) {
|
||||
|
@ -53,21 +53,22 @@ can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
|
||||
- `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
|
||||
files are so large, this is required and Packer will verify it prior
|
||||
to booting a virtual machine with the ISO attached. The type of the
|
||||
checksum is specified with `iso_checksum_type`, documented below.
|
||||
- `iso_checksum` (string) - The checksum for the OS ISO file or virtual
|
||||
harddrive file. Because these files are so large, this is required and
|
||||
Packer will verify it prior to booting a virtual machine with the ISO or
|
||||
virtual harddrive attached. The type of the checksum is specified with
|
||||
`iso_checksum_type`, documented below.
|
||||
|
||||
- `iso_checksum_type` (string) - The type of the checksum specified in
|
||||
`iso_checksum`. Valid values are "none", "md5", "sha1", "sha256", or
|
||||
"sha512" currently. While "none" will skip checksumming, this is not
|
||||
recommended since ISO files are generally large and corruption does happen
|
||||
from time to time.
|
||||
recommended since ISO files and virtual harddrive files are generally large
|
||||
and corruption does happen from time to time.
|
||||
|
||||
- `iso_url` (string) - A URL to the ISO containing the installation image.
|
||||
This URL can be either an HTTP URL or a file URL (or path to a file).
|
||||
If this is an HTTP URL, Packer will download iso and cache it between
|
||||
runs.
|
||||
- `iso_url` (string) - A URL to the ISO containing the installation image or
|
||||
virtual harddrive vhd or vhdx file to clone. This URL can be either an HTTP
|
||||
URL or a file URL (or path to a file). If this is an HTTP URL, Packer will
|
||||
download the file and cache it between runs.
|
||||
|
||||
### Optional:
|
||||
|
||||
|
@ -9,12 +9,14 @@ page_title: "Hyper-V Builder (from an vmcx)"
|
||||
|
||||
Type: `hyperv-vmcx`
|
||||
|
||||
The Hyper-V Packer builder is able to clone [Hyper-V](https://www.microsoft.com/en-us/server-cloud/solutions/virtualization.aspx)
|
||||
virtual machines and export them.
|
||||
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.
|
||||
|
||||
The builder clones an existing virtual machine boots it, and provisioning software within
|
||||
the OS, then shutting it down. The result of the Hyper-V builder is a directory
|
||||
containing all the files necessary to run the virtual machine portably.
|
||||
The builder imports a virtual machine or clones an existing virtual machine boots it,
|
||||
and provisioning software within the OS, then shutting it down. The result of the
|
||||
Hyper-V builder is a directory containing all the files necessary to run the virtual
|
||||
machine portably.
|
||||
|
||||
## Basic Example
|
||||
|
||||
@ -22,6 +24,18 @@ 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:
|
||||
|
||||
Import from folder:
|
||||
```javascript
|
||||
{
|
||||
"type": "hyperv-vmcx",
|
||||
"clone_from_vmxc_path": "c:\virtual machines\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:
|
||||
```javascript
|
||||
{
|
||||
"type": "hyperv-vmcx",
|
||||
@ -46,7 +60,11 @@ In addition to the options listed here, a
|
||||
[communicator](/docs/templates/communicator.html)
|
||||
can be configured for this builder.
|
||||
|
||||
### Required:
|
||||
### Required for virtual machine import:
|
||||
- `clone_from_vmxc_path` (string) - The path to the exported
|
||||
virtual machine folder.
|
||||
|
||||
### 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.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user