2015-06-21 07:36:07 -04:00
package iso
import (
"errors"
"fmt"
2016-06-30 15:21:57 -04:00
"log"
"os"
2017-05-21 12:29:26 -04:00
"path/filepath"
2017-05-29 20:16:03 -04:00
"strings"
2016-06-30 15:21:57 -04:00
2017-04-04 16:39:01 -04:00
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"
2015-06-21 07:36:07 -04:00
"github.com/mitchellh/multistep"
)
const (
2015-10-30 15:57:27 -04:00
DefaultDiskSize = 40 * 1024 // ~40GB
MinDiskSize = 256 // 256MB
2015-10-18 12:11:38 -04:00
MaxDiskSize = 64 * 1024 * 1024 // 64TB
2015-06-21 07:36:07 -04:00
2016-08-07 07:26:27 -04:00
DefaultRamSize = 1 * 1024 // 1GB
MinRamSize = 32 // 32MB
MaxRamSize = 32 * 1024 // 32GB
MinNestedVirtualizationRamSize = 4 * 1024 // 4GB
2015-06-21 07:36:07 -04:00
2016-07-24 13:07:43 -04:00
LowRam = 256 // 256MB
2015-06-21 07:36:07 -04:00
2016-11-06 08:14:39 -05:00
DefaultUsername = ""
DefaultPassword = ""
2015-06-21 07:36:07 -04:00
)
// Builder implements packer.Builder and builds the actual Hyperv
// images.
type Builder struct {
2015-06-21 09:06:27 -04:00
config Config
2015-06-21 07:36:07 -04:00
runner multistep . Runner
}
2015-06-21 09:06:27 -04:00
type Config struct {
common . PackerConfig ` mapstructure:",squash" `
2016-01-25 17:43:40 -05:00
common . HTTPConfig ` mapstructure:",squash" `
2016-06-29 17:53:29 -04:00
common . ISOConfig ` mapstructure:",squash" `
2017-06-15 08:12:39 -04:00
common . FloppyConfig ` mapstructure:",squash" `
2015-06-21 09:06:27 -04:00
hypervcommon . OutputConfig ` mapstructure:",squash" `
hypervcommon . SSHConfig ` mapstructure:",squash" `
hypervcommon . RunConfig ` mapstructure:",squash" `
2015-06-27 17:36:39 -04:00
hypervcommon . ShutdownConfig ` mapstructure:",squash" `
2015-06-21 09:06:27 -04:00
2015-06-21 07:36:07 -04:00
// The size, in megabytes, of the hard disk to create for the VM.
// By default, this is 130048 (about 127 GB).
DiskSize uint ` mapstructure:"disk_size" `
// The size, in megabytes, of the computer memory in the VM.
// By default, this is 1024 (about 1 GB).
2016-11-06 09:07:46 -05:00
RamSize uint ` mapstructure:"ram_size" `
2015-06-21 07:36:07 -04:00
//
SecondaryDvdImages [ ] string ` mapstructure:"secondary_iso_images" `
2015-06-21 10:53:08 -04:00
2015-10-30 13:19:25 -04:00
// Should integration services iso be mounted
2015-10-30 15:57:27 -04:00
GuestAdditionsMode string ` mapstructure:"guest_additions_mode" `
2015-10-30 13:19:25 -04:00
// The path to the integration services iso
2015-10-30 15:57:27 -04:00
GuestAdditionsPath string ` mapstructure:"guest_additions_path" `
2015-06-21 10:53:08 -04:00
2015-06-21 07:36:07 -04:00
// This is the name of the new virtual machine.
// By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build.
VMName string ` mapstructure:"vm_name" `
2016-08-07 07:26:27 -04:00
BootCommand [ ] string ` mapstructure:"boot_command" `
SwitchName string ` mapstructure:"switch_name" `
2016-09-29 14:37:07 -04:00
SwitchVlanId string ` mapstructure:"switch_vlan_id" `
VlanId string ` mapstructure:"vlan_id" `
2016-08-07 07:26:27 -04:00
Cpu uint ` mapstructure:"cpu" `
Generation uint ` mapstructure:"generation" `
EnableMacSpoofing bool ` mapstructure:"enable_mac_spoofing" `
EnableDynamicMemory bool ` mapstructure:"enable_dynamic_memory" `
EnableSecureBoot bool ` mapstructure:"enable_secure_boot" `
EnableVirtualizationExtensions bool ` mapstructure:"enable_virtualization_extensions" `
2017-06-30 19:19:27 -04:00
TempPath string ` mapstructure:"temp_path" `
2015-06-21 07:36:07 -04:00
2017-08-01 05:23:19 -04:00
// A separate path can be used for storing the VM's disk image. The purpose is to enable
// reading and writing to take place on different physical disks (read from VHD temp path
// write to regular temp path while exporting the VM) to eliminate a single-disk bottleneck.
VhdTempPath string ` mapstructure:"vhd_temp_path" `
2015-06-21 07:36:07 -04:00
Communicator string ` mapstructure:"communicator" `
2017-10-19 18:29:17 -04:00
AdditionalDiskSize [ ] uint ` mapstructure:"disk_additional_size" `
2015-06-27 17:36:39 -04:00
SkipCompaction bool ` mapstructure:"skip_compaction" `
2017-10-12 06:35:31 -04:00
// Use differencing disk
DifferencingDisk bool ` mapstructure:"differencing_disk" `
2015-06-21 09:06:27 -04:00
ctx interpolate . Context
2015-06-21 07:36:07 -04:00
}
// Prepare processes the build configuration parameters.
func ( b * Builder ) Prepare ( raws ... interface { } ) ( [ ] string , error ) {
2015-06-21 09:06:27 -04:00
err := config . Decode ( & b . config , & config . DecodeOpts {
2017-08-08 09:21:53 -04:00
Interpolate : true ,
2017-07-27 10:53:15 -04:00
InterpolateContext : & b . config . ctx ,
2015-06-21 09:06:27 -04:00
InterpolateFilter : & interpolate . RenderFilter {
2015-06-27 17:36:39 -04:00
Exclude : [ ] string {
"boot_command" ,
} ,
2015-06-21 09:06:27 -04:00
} ,
} , raws ... )
2015-06-21 07:36:07 -04:00
if err != nil {
return nil , err
}
// Accumulate any errors and warnings
2015-06-21 09:06:27 -04:00
var errs * packer . MultiError
2016-06-29 17:53:29 -04:00
warnings := make ( [ ] string , 0 )
isoWarnings , isoErrs := b . config . ISOConfig . Prepare ( & b . config . ctx )
warnings = append ( warnings , isoWarnings ... )
errs = packer . MultiErrorAppend ( errs , isoErrs ... )
2017-05-29 20:16:03 -04:00
2015-06-21 09:06:27 -04:00
errs = packer . MultiErrorAppend ( errs , b . config . FloppyConfig . Prepare ( & b . config . ctx ) ... )
2016-01-25 17:43:40 -05:00
errs = packer . MultiErrorAppend ( errs , b . config . HTTPConfig . Prepare ( & b . config . ctx ) ... )
2015-06-21 09:06:27 -04:00
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 ) ... )
2017-05-28 21:36:01 -04:00
errs = packer . MultiErrorAppend ( errs , b . config . ShutdownConfig . Prepare ( & b . config . ctx ) ... )
2015-06-21 07:36:07 -04:00
2017-05-29 20:16:03 -04:00
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" ) {
2017-05-21 12:29:26 -04:00
//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 )
}
2015-06-21 07:36:07 -04:00
}
err = b . checkRamSize ( )
if err != nil {
errs = packer . MultiErrorAppend ( errs , err )
}
if b . config . VMName == "" {
2015-07-24 03:21:23 -04:00
b . config . VMName = fmt . Sprintf ( "packer-%s" , b . config . PackerBuildName )
2015-07-12 12:19:29 -04:00
}
2015-06-21 07:36:07 -04:00
2015-06-21 09:06:27 -04:00
log . Println ( fmt . Sprintf ( "%s: %v" , "VMName" , b . config . VMName ) )
2015-06-21 07:36:07 -04:00
if b . config . SwitchName == "" {
2016-06-30 15:21:57 -04:00
b . config . SwitchName = b . detectSwitchName ( )
2015-06-21 07:36:07 -04:00
}
2015-06-21 14:35:32 -04:00
if b . config . Cpu < 1 {
b . config . Cpu = 1
}
2017-05-29 20:16:03 -04:00
if b . config . Generation < 1 || b . config . Generation > 2 {
2015-06-21 14:35:32 -04:00
b . config . Generation = 1
}
2015-07-12 12:19:29 -04:00
if b . config . Generation == 2 {
2017-06-15 08:12:39 -04:00
if len ( b . config . FloppyFiles ) > 0 || len ( b . config . FloppyDirectories ) > 0 {
2015-07-12 12:19:29 -04:00
err = errors . New ( "Generation 2 vms don't support floppy drives. Use ISO image instead." )
errs = packer . MultiErrorAppend ( errs , err )
}
}
2017-10-19 18:29:17 -04:00
if len ( b . config . AdditionalDiskSize ) > 64 {
err = errors . New ( "VM's currently support a maximun of 64 additional SCSI attached disks." )
errs = packer . MultiErrorAppend ( errs , err )
}
2015-06-21 07:36:07 -04:00
log . Println ( fmt . Sprintf ( "Using switch %s" , b . config . SwitchName ) )
2015-06-21 09:06:27 -04:00
log . Println ( fmt . Sprintf ( "%s: %v" , "SwitchName" , b . config . SwitchName ) )
2015-06-21 07:36:07 -04:00
// Errors
2017-05-21 12:29:26 -04:00
2015-10-30 13:19:25 -04:00
if b . config . GuestAdditionsMode == "" {
2016-11-14 18:11:26 -05:00
if b . config . GuestAdditionsPath != "" {
b . config . GuestAdditionsMode = "attach"
} else {
b . config . GuestAdditionsPath = os . Getenv ( "WINDIR" ) + "\\system32\\vmguest.iso"
if _ , err := os . Stat ( b . config . GuestAdditionsPath ) ; os . IsNotExist ( err ) {
if err != nil {
b . config . GuestAdditionsPath = ""
b . config . GuestAdditionsMode = "none"
} else {
b . config . GuestAdditionsMode = "attach"
}
}
}
2015-10-30 13:19:25 -04:00
}
2016-11-14 18:11:26 -05:00
if b . config . GuestAdditionsPath == "" && b . config . GuestAdditionsMode == "attach" {
2015-10-30 13:19:25 -04:00
b . config . GuestAdditionsPath = os . Getenv ( "WINDIR" ) + "\\system32\\vmguest.iso"
2016-11-14 18:11:26 -05:00
if _ , err := os . Stat ( b . config . GuestAdditionsPath ) ; os . IsNotExist ( err ) {
if err != nil {
b . config . GuestAdditionsPath = ""
}
}
2015-10-30 13:19:25 -04:00
}
2015-10-30 15:57:27 -04:00
2015-10-30 13:19:25 -04:00
for _ , isoPath := range b . config . SecondaryDvdImages {
if _ , err := os . Stat ( isoPath ) ; os . IsNotExist ( err ) {
2015-10-30 15:57:27 -04:00
if err != nil {
2015-10-30 13:19:25 -04:00
errs = packer . MultiErrorAppend (
errs , fmt . Errorf ( "Secondary Dvd image does not exist: %s" , err ) )
}
}
}
2015-10-30 15:57:27 -04:00
2015-10-30 13:19:25 -04:00
numberOfIsos := len ( b . config . SecondaryDvdImages )
2015-10-30 15:57:27 -04:00
2015-10-30 13:19:25 -04:00
if b . config . GuestAdditionsMode == "attach" {
if _ , err := os . Stat ( b . config . GuestAdditionsPath ) ; os . IsNotExist ( err ) {
2015-10-30 15:57:27 -04:00
if err != nil {
2015-10-30 13:19:25 -04:00
errs = packer . MultiErrorAppend (
errs , fmt . Errorf ( "Guest additions iso does not exist: %s" , err ) )
}
2015-10-30 15:57:27 -04:00
}
2015-10-30 13:19:25 -04:00
numberOfIsos = numberOfIsos + 1
}
2015-10-30 15:57:27 -04:00
2015-10-30 13:19:25 -04:00
if b . config . Generation < 2 && numberOfIsos > 2 {
if b . config . GuestAdditionsMode == "attach" {
errs = packer . MultiErrorAppend ( errs , fmt . Errorf ( "There are only 2 ide controllers available, so we can't support guest additions and these secondary dvds: %s" , strings . Join ( b . config . SecondaryDvdImages , ", " ) ) )
} else {
errs = packer . MultiErrorAppend ( errs , fmt . Errorf ( "There are only 2 ide controllers available, so we can't support these secondary dvds: %s" , strings . Join ( b . config . SecondaryDvdImages , ", " ) ) )
}
} else if b . config . Generation > 1 && len ( b . config . SecondaryDvdImages ) > 16 {
if b . config . GuestAdditionsMode == "attach" {
2015-10-30 15:57:27 -04:00
errs = packer . MultiErrorAppend ( 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 ( b . config . SecondaryDvdImages , ", " ) ) )
2015-10-30 13:19:25 -04:00
} else {
2015-10-30 15:57:27 -04:00
errs = packer . MultiErrorAppend ( 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 ( b . config . SecondaryDvdImages , ", " ) ) )
2015-10-30 13:19:25 -04:00
}
}
2016-08-07 07:26:27 -04:00
if b . config . EnableVirtualizationExtensions {
hasVirtualMachineVirtualizationExtensions , err := powershell . HasVirtualMachineVirtualizationExtensions ( )
if err != nil {
errs = packer . MultiErrorAppend ( errs , fmt . Errorf ( "Failed detecting virtual machine virtualization extensions support: %s" , err ) )
} else {
if ! hasVirtualMachineVirtualizationExtensions {
errs = packer . MultiErrorAppend ( 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." ) )
}
}
}
2015-06-21 07:36:07 -04:00
// Warnings
2015-06-21 09:06:27 -04:00
2015-06-21 07:36:07 -04:00
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." )
}
2015-06-21 10:53:08 -04:00
warning := b . checkHostAvailableMemory ( )
if warning != "" {
warnings = appendWarnings ( warnings , warning )
}
2016-08-07 07:26:27 -04:00
if b . config . EnableVirtualizationExtensions {
if b . config . EnableDynamicMemory {
warning = fmt . Sprintf ( "For nested virtualization, when virtualization extension is enabled, dynamic memory should not be allowed." )
warnings = appendWarnings ( warnings , warning )
}
if ! b . config . EnableMacSpoofing {
warning = fmt . Sprintf ( "For nested virtualization, when virtualization extension is enabled, mac spoofing should be allowed." )
warnings = appendWarnings ( warnings , warning )
}
2016-11-06 09:07:46 -05:00
if b . config . RamSize < MinNestedVirtualizationRamSize {
2016-08-07 07:26:27 -04:00
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." )
warnings = appendWarnings ( warnings , warning )
}
}
2016-09-29 14:37:07 -04:00
if b . config . SwitchVlanId != "" {
if b . config . SwitchVlanId != b . config . 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." )
warnings = appendWarnings ( warnings , warning )
}
}
2015-06-21 07:36:07 -04:00
if errs != nil && len ( errs . Errors ) > 0 {
return warnings , errs
}
return warnings , nil
}
// Run executes a Packer build and returns a packer.Artifact representing
// a Hyperv appliance.
func ( b * Builder ) Run ( ui packer . Ui , hook packer . Hook , cache packer . Cache ) ( packer . 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 )
2015-10-30 15:57:27 -04:00
state . Put ( "cache" , cache )
2015-06-21 07:36:07 -04:00
state . Put ( "config" , & b . config )
2016-06-29 17:53:29 -04:00
state . Put ( "debug" , b . config . PackerDebug )
2015-06-21 07:36:07 -04:00
state . Put ( "driver" , driver )
state . Put ( "hook" , hook )
state . Put ( "ui" , ui )
2015-10-30 15:57:27 -04:00
steps := [ ] multistep . Step {
2017-06-30 19:19:27 -04:00
& hypervcommon . StepCreateTempDir {
2017-08-01 05:23:19 -04:00
TempPath : b . config . TempPath ,
VhdTempPath : b . config . VhdTempPath ,
2017-06-30 19:19:27 -04:00
} ,
2015-06-21 07:36:07 -04:00
& hypervcommon . StepOutputDir {
Force : b . config . PackerForce ,
Path : b . config . OutputDir ,
} ,
2015-10-30 13:19:25 -04:00
& common . StepDownload {
Checksum : b . config . ISOChecksum ,
ChecksumType : b . config . ISOChecksumType ,
Description : "ISO" ,
ResultKey : "iso_path" ,
Url : b . config . ISOUrls ,
2016-12-17 05:49:54 -05:00
Extension : b . config . TargetExtension ,
2015-10-30 13:19:25 -04:00
TargetPath : b . config . TargetPath ,
2015-10-30 15:57:27 -04:00
} ,
2015-06-21 07:36:07 -04:00
& common . StepCreateFloppy {
2017-06-15 08:12:39 -04:00
Files : b . config . FloppyConfig . FloppyFiles ,
Directories : b . config . FloppyConfig . FloppyDirectories ,
2015-06-21 07:36:07 -04:00
} ,
2016-01-25 17:43:40 -05:00
& common . StepHTTPServer {
2015-06-27 17:36:39 -04:00
HTTPDir : b . config . HTTPDir ,
HTTPPortMin : b . config . HTTPPortMin ,
HTTPPortMax : b . config . HTTPPortMax ,
} ,
2015-06-21 07:36:07 -04:00
& hypervcommon . StepCreateSwitch {
SwitchName : b . config . SwitchName ,
} ,
& hypervcommon . StepCreateVM {
2016-08-07 07:26:27 -04:00
VMName : b . config . VMName ,
SwitchName : b . config . SwitchName ,
2016-11-06 09:07:46 -05:00
RamSize : b . config . RamSize ,
2016-08-07 07:26:27 -04:00
DiskSize : b . config . DiskSize ,
Generation : b . config . Generation ,
Cpu : b . config . Cpu ,
EnableMacSpoofing : b . config . EnableMacSpoofing ,
EnableDynamicMemory : b . config . EnableDynamicMemory ,
EnableSecureBoot : b . config . EnableSecureBoot ,
2016-08-06 02:09:33 -04:00
EnableVirtualizationExtensions : b . config . EnableVirtualizationExtensions ,
2017-10-19 18:29:17 -04:00
AdditionalDiskSize : b . config . AdditionalDiskSize ,
2017-10-12 06:35:31 -04:00
DifferencingDisk : b . config . DifferencingDisk ,
2015-06-21 07:36:07 -04:00
} ,
& hypervcommon . StepEnableIntegrationService { } ,
& hypervcommon . StepMountDvdDrive {
2015-10-30 13:19:25 -04:00
Generation : b . config . Generation ,
} ,
& hypervcommon . StepMountFloppydrive {
Generation : b . config . Generation ,
} ,
& hypervcommon . StepMountGuestAdditions {
GuestAdditionsMode : b . config . GuestAdditionsMode ,
GuestAdditionsPath : b . config . GuestAdditionsPath ,
2015-10-30 15:57:27 -04:00
Generation : b . config . Generation ,
2015-06-21 07:36:07 -04:00
} ,
2015-07-12 12:19:29 -04:00
& hypervcommon . StepMountSecondaryDvdImages {
2015-10-30 15:57:27 -04:00
IsoPaths : b . config . SecondaryDvdImages ,
2015-07-12 13:57:42 -04:00
Generation : b . config . Generation ,
2015-07-12 12:19:29 -04:00
} ,
2016-09-29 14:37:07 -04:00
2016-09-21 14:31:06 -04:00
& hypervcommon . StepConfigureVlan {
2016-09-29 14:37:07 -04:00
VlanId : b . config . VlanId ,
SwitchVlanId : b . config . SwitchVlanId ,
2016-09-21 14:31:06 -04:00
} ,
2015-06-21 07:36:07 -04:00
2015-06-27 17:36:39 -04:00
& hypervcommon . StepRun {
BootWait : b . config . BootWait ,
} ,
& hypervcommon . StepTypeBootCommand {
BootCommand : b . config . BootCommand ,
SwitchName : b . config . SwitchName ,
Ctx : b . config . ctx ,
2015-06-21 07:36:07 -04:00
} ,
// configure the communicator ssh, winrm
& communicator . StepConnect {
Config : & b . config . SSHConfig . Comm ,
Host : hypervcommon . CommHost ,
2015-06-22 17:26:06 -04:00
SSHConfig : hypervcommon . SSHConfigFunc ( & b . config . SSHConfig ) ,
2015-06-21 07:36:07 -04:00
} ,
// provision requires communicator to be setup
& common . StepProvision { } ,
& hypervcommon . StepShutdown {
Command : b . config . ShutdownCommand ,
Timeout : b . config . ShutdownTimeout ,
} ,
2015-06-21 14:35:32 -04:00
// wait for the vm to be powered off
& hypervcommon . StepWaitForPowerOff { } ,
2015-10-30 15:57:27 -04:00
2015-10-30 13:19:25 -04:00
// remove the secondary dvd images
2015-06-24 14:52:42 -04:00
// after we power down
& hypervcommon . StepUnmountSecondaryDvdImages { } ,
2015-10-30 13:19:25 -04:00
& hypervcommon . StepUnmountGuestAdditions { } ,
& hypervcommon . StepUnmountDvdDrive { } ,
2015-07-14 02:51:03 -04:00
& hypervcommon . StepUnmountFloppyDrive {
Generation : b . config . Generation ,
} ,
2015-06-21 07:36:07 -04:00
& hypervcommon . StepExportVm {
2015-06-27 17:36:39 -04:00
OutputDir : b . config . OutputDir ,
SkipCompaction : b . config . SkipCompaction ,
2015-06-21 07:36:07 -04:00
} ,
// the clean up actions for each step will be executed reverse order
}
// Run the steps.
2017-08-31 13:43:00 -04:00
b . runner = common . NewRunner ( steps , b . config . PackerConfig , ui )
2015-06-21 07:36:07 -04:00
b . runner . Run ( 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." )
}
return hypervcommon . NewArtifact ( b . config . OutputDir )
}
// Cancel.
func ( b * Builder ) Cancel ( ) {
if b . runner != nil {
log . Println ( "Cancelling the step runner..." )
b . runner . Cancel ( )
}
}
func appendWarnings ( 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
}
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 {
2016-11-06 10:51:48 -05:00
return fmt . Errorf ( "disk_size: Virtual machine requires disk space >= %v GB, but defined: %v" , MinDiskSize , b . config . DiskSize / 1024 )
2015-06-21 07:36:07 -04:00
} else if b . config . DiskSize > MaxDiskSize {
2016-11-06 10:51:48 -05:00
return fmt . Errorf ( "disk_size: Virtual machine requires disk space <= %v GB, but defined: %v" , MaxDiskSize , b . config . DiskSize / 1024 )
2015-06-21 07:36:07 -04:00
}
return nil
}
func ( b * Builder ) checkRamSize ( ) error {
2016-11-06 09:07:46 -05:00
if b . config . RamSize == 0 {
b . config . RamSize = DefaultRamSize
2015-06-21 07:36:07 -04:00
}
2016-11-06 09:07:46 -05:00
log . Println ( fmt . Sprintf ( "%s: %v" , "RamSize" , b . config . RamSize ) )
2015-06-21 07:36:07 -04:00
2016-11-06 09:07:46 -05:00
if b . config . RamSize < MinRamSize {
2016-11-06 10:51:48 -05:00
return fmt . Errorf ( "ram_size: Virtual machine requires memory size >= %v MB, but defined: %v" , MinRamSize , b . config . RamSize )
2016-11-06 09:07:46 -05:00
} else if b . config . RamSize > MaxRamSize {
2016-11-06 10:51:48 -05:00
return fmt . Errorf ( "ram_size: Virtual machine requires memory size <= %v MB, but defined: %v" , MaxRamSize , b . config . RamSize )
2015-06-21 07:36:07 -04:00
}
return nil
}
func ( b * Builder ) checkHostAvailableMemory ( ) string {
2016-06-30 15:21:57 -04:00
powershellAvailable , _ , _ := powershell . IsPowershellAvailable ( )
if powershellAvailable {
freeMB := powershell . GetHostAvailableMemory ( )
2015-06-21 07:36:07 -04:00
2016-11-06 09:07:46 -05:00
if ( freeMB - float64 ( b . config . RamSize ) ) < LowRam {
2016-06-30 15:21:57 -04:00
return fmt . Sprintf ( "Hyper-V might fail to create a VM if there is not enough free memory in the system." )
}
2015-06-21 07:36:07 -04:00
}
return ""
2015-06-21 09:06:27 -04:00
}
2016-06-30 15:21:57 -04:00
func ( b * Builder ) detectSwitchName ( ) 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" , b . config . PackerBuildName )
}