github.phpd.cn/hashicorp/packer@v1.3.2/builder/hyperv/common/driver_ps_4.go (about)

     1  package common
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  	"runtime"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/hashicorp/packer/common/powershell"
    12  	"github.com/hashicorp/packer/common/powershell/hyperv"
    13  )
    14  
    15  type HypervPS4Driver struct {
    16  }
    17  
    18  func NewHypervPS4Driver() (Driver, error) {
    19  	appliesTo := "Applies to Windows 8.1, Windows PowerShell 4.0, Windows Server 2012 R2 only"
    20  
    21  	// Check this is Windows
    22  	if runtime.GOOS != "windows" {
    23  		err := fmt.Errorf("%s", appliesTo)
    24  		return nil, err
    25  	}
    26  
    27  	ps4Driver := &HypervPS4Driver{}
    28  
    29  	if err := ps4Driver.Verify(); err != nil {
    30  		return nil, err
    31  	}
    32  
    33  	return ps4Driver, nil
    34  }
    35  
    36  func (d *HypervPS4Driver) IsRunning(vmName string) (bool, error) {
    37  	return hyperv.IsRunning(vmName)
    38  }
    39  
    40  func (d *HypervPS4Driver) IsOff(vmName string) (bool, error) {
    41  	return hyperv.IsOff(vmName)
    42  }
    43  
    44  func (d *HypervPS4Driver) Uptime(vmName string) (uint64, error) {
    45  	return hyperv.Uptime(vmName)
    46  }
    47  
    48  // Start starts a VM specified by the name given.
    49  func (d *HypervPS4Driver) Start(vmName string) error {
    50  	return hyperv.StartVirtualMachine(vmName)
    51  }
    52  
    53  // Stop stops a VM specified by the name given.
    54  func (d *HypervPS4Driver) Stop(vmName string) error {
    55  	return hyperv.StopVirtualMachine(vmName)
    56  }
    57  
    58  func (d *HypervPS4Driver) Verify() error {
    59  
    60  	if err := d.verifyPSVersion(); err != nil {
    61  		return err
    62  	}
    63  
    64  	if err := d.verifyPSHypervModule(); err != nil {
    65  		return err
    66  	}
    67  
    68  	if err := d.verifyHypervPermissions(); err != nil {
    69  		return err
    70  	}
    71  
    72  	return nil
    73  }
    74  
    75  // Get mac address for VM.
    76  func (d *HypervPS4Driver) Mac(vmName string) (string, error) {
    77  	res, err := hyperv.Mac(vmName)
    78  
    79  	if err != nil {
    80  		return res, err
    81  	}
    82  
    83  	if res == "" {
    84  		err := fmt.Errorf("%s", "No mac address.")
    85  		return res, err
    86  	}
    87  
    88  	return res, err
    89  }
    90  
    91  // Get ip address for mac address.
    92  func (d *HypervPS4Driver) IpAddress(mac string) (string, error) {
    93  	res, err := hyperv.IpAddress(mac)
    94  
    95  	if err != nil {
    96  		return res, err
    97  	}
    98  
    99  	if res == "" {
   100  		err := fmt.Errorf("%s", "No ip address.")
   101  		return res, err
   102  	}
   103  	return res, err
   104  }
   105  
   106  // Get host name from ip address
   107  func (d *HypervPS4Driver) GetHostName(ip string) (string, error) {
   108  	return powershell.GetHostName(ip)
   109  }
   110  
   111  func (d *HypervPS4Driver) GetVirtualMachineGeneration(vmName string) (uint, error) {
   112  	return hyperv.GetVirtualMachineGeneration(vmName)
   113  }
   114  
   115  // Finds the IP address of a host adapter connected to switch
   116  func (d *HypervPS4Driver) GetHostAdapterIpAddressForSwitch(switchName string) (string, error) {
   117  	res, err := hyperv.GetHostAdapterIpAddressForSwitch(switchName)
   118  
   119  	if err != nil {
   120  		return res, err
   121  	}
   122  
   123  	if res == "" {
   124  		err := fmt.Errorf("%s", "No ip address.")
   125  		return res, err
   126  	}
   127  	return res, err
   128  }
   129  
   130  // Type scan codes to virtual keyboard of vm
   131  func (d *HypervPS4Driver) TypeScanCodes(vmName string, scanCodes string) error {
   132  	return hyperv.TypeScanCodes(vmName, scanCodes)
   133  }
   134  
   135  // Get network adapter address
   136  func (d *HypervPS4Driver) GetVirtualMachineNetworkAdapterAddress(vmName string) (string, error) {
   137  	return hyperv.GetVirtualMachineNetworkAdapterAddress(vmName)
   138  }
   139  
   140  //Set the vlan to use for switch
   141  func (d *HypervPS4Driver) SetNetworkAdapterVlanId(switchName string, vlanId string) error {
   142  	return hyperv.SetNetworkAdapterVlanId(switchName, vlanId)
   143  }
   144  
   145  //Set the vlan to use for machine
   146  func (d *HypervPS4Driver) SetVirtualMachineVlanId(vmName string, vlanId string) error {
   147  	return hyperv.SetVirtualMachineVlanId(vmName, vlanId)
   148  }
   149  
   150  func (d *HypervPS4Driver) SetVmNetworkAdapterMacAddress(vmName string, mac string) error {
   151  	return hyperv.SetVmNetworkAdapterMacAddress(vmName, mac)
   152  }
   153  
   154  func (d *HypervPS4Driver) UntagVirtualMachineNetworkAdapterVlan(vmName string, switchName string) error {
   155  	return hyperv.UntagVirtualMachineNetworkAdapterVlan(vmName, switchName)
   156  }
   157  
   158  func (d *HypervPS4Driver) CreateExternalVirtualSwitch(vmName string, switchName string) error {
   159  	return hyperv.CreateExternalVirtualSwitch(vmName, switchName)
   160  }
   161  
   162  func (d *HypervPS4Driver) GetVirtualMachineSwitchName(vmName string) (string, error) {
   163  	return hyperv.GetVirtualMachineSwitchName(vmName)
   164  }
   165  
   166  func (d *HypervPS4Driver) ConnectVirtualMachineNetworkAdapterToSwitch(vmName string, switchName string) error {
   167  	return hyperv.ConnectVirtualMachineNetworkAdapterToSwitch(vmName, switchName)
   168  }
   169  
   170  func (d *HypervPS4Driver) DeleteVirtualSwitch(switchName string) error {
   171  	return hyperv.DeleteVirtualSwitch(switchName)
   172  }
   173  
   174  func (d *HypervPS4Driver) CreateVirtualSwitch(switchName string, switchType string) (bool, error) {
   175  	return hyperv.CreateVirtualSwitch(switchName, switchType)
   176  }
   177  
   178  func (d *HypervPS4Driver) AddVirtualMachineHardDrive(vmName string, vhdFile string, vhdName string,
   179  	vhdSizeBytes int64, diskBlockSize int64, controllerType string) error {
   180  	return hyperv.AddVirtualMachineHardDiskDrive(vmName, vhdFile, vhdName, vhdSizeBytes,
   181  		diskBlockSize, controllerType)
   182  }
   183  
   184  func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, ram int64,
   185  	diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool,
   186  	fixedVHD bool) error {
   187  	return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, ram, diskSize, diskBlockSize, switchName,
   188  		generation, diffDisks, fixedVHD)
   189  }
   190  
   191  func (d *HypervPS4Driver) CloneVirtualMachine(cloneFromVmcxPath string, cloneFromVmName string,
   192  	cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string,
   193  	ram int64, switchName string) error {
   194  	return hyperv.CloneVirtualMachine(cloneFromVmcxPath, cloneFromVmName, cloneFromSnapshotName,
   195  		cloneAllSnapshots, vmName, path, harddrivePath, ram, switchName)
   196  }
   197  
   198  func (d *HypervPS4Driver) DeleteVirtualMachine(vmName string) error {
   199  	return hyperv.DeleteVirtualMachine(vmName)
   200  }
   201  
   202  func (d *HypervPS4Driver) SetVirtualMachineCpuCount(vmName string, cpu uint) error {
   203  	return hyperv.SetVirtualMachineCpuCount(vmName, cpu)
   204  }
   205  
   206  func (d *HypervPS4Driver) SetVirtualMachineMacSpoofing(vmName string, enable bool) error {
   207  	return hyperv.SetVirtualMachineMacSpoofing(vmName, enable)
   208  }
   209  
   210  func (d *HypervPS4Driver) SetVirtualMachineDynamicMemory(vmName string, enable bool) error {
   211  	return hyperv.SetVirtualMachineDynamicMemory(vmName, enable)
   212  }
   213  
   214  func (d *HypervPS4Driver) SetVirtualMachineSecureBoot(vmName string, enable bool, templateName string) error {
   215  	return hyperv.SetVirtualMachineSecureBoot(vmName, enable, templateName)
   216  }
   217  
   218  func (d *HypervPS4Driver) SetVirtualMachineVirtualizationExtensions(vmName string, enable bool) error {
   219  	return hyperv.SetVirtualMachineVirtualizationExtensions(vmName, enable)
   220  }
   221  
   222  func (d *HypervPS4Driver) EnableVirtualMachineIntegrationService(vmName string,
   223  	integrationServiceName string) error {
   224  	return hyperv.EnableVirtualMachineIntegrationService(vmName, integrationServiceName)
   225  }
   226  
   227  func (d *HypervPS4Driver) ExportVirtualMachine(vmName string, path string) error {
   228  	return hyperv.ExportVirtualMachine(vmName, path)
   229  }
   230  
   231  func (d *HypervPS4Driver) PreserveLegacyExportBehaviour(srcPath string, dstPath string) error {
   232  	return hyperv.PreserveLegacyExportBehaviour(srcPath, dstPath)
   233  }
   234  
   235  func (d *HypervPS4Driver) MoveCreatedVHDsToOutputDir(srcPath string, dstPath string) error {
   236  	return hyperv.MoveCreatedVHDsToOutputDir(srcPath, dstPath)
   237  }
   238  
   239  func (d *HypervPS4Driver) CompactDisks(path string) (result string, err error) {
   240  	return hyperv.CompactDisks(path)
   241  }
   242  
   243  func (d *HypervPS4Driver) RestartVirtualMachine(vmName string) error {
   244  	return hyperv.RestartVirtualMachine(vmName)
   245  }
   246  
   247  func (d *HypervPS4Driver) CreateDvdDrive(vmName string, isoPath string, generation uint) (uint, uint, error) {
   248  	return hyperv.CreateDvdDrive(vmName, isoPath, generation)
   249  }
   250  
   251  func (d *HypervPS4Driver) MountDvdDrive(vmName string, path string, controllerNumber uint,
   252  	controllerLocation uint) error {
   253  	return hyperv.MountDvdDrive(vmName, path, controllerNumber, controllerLocation)
   254  }
   255  
   256  func (d *HypervPS4Driver) SetBootDvdDrive(vmName string, controllerNumber uint, controllerLocation uint,
   257  	generation uint) error {
   258  	return hyperv.SetBootDvdDrive(vmName, controllerNumber, controllerLocation, generation)
   259  }
   260  
   261  func (d *HypervPS4Driver) UnmountDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
   262  	return hyperv.UnmountDvdDrive(vmName, controllerNumber, controllerLocation)
   263  }
   264  
   265  func (d *HypervPS4Driver) DeleteDvdDrive(vmName string, controllerNumber uint, controllerLocation uint) error {
   266  	return hyperv.DeleteDvdDrive(vmName, controllerNumber, controllerLocation)
   267  }
   268  
   269  func (d *HypervPS4Driver) MountFloppyDrive(vmName string, path string) error {
   270  	return hyperv.MountFloppyDrive(vmName, path)
   271  }
   272  
   273  func (d *HypervPS4Driver) UnmountFloppyDrive(vmName string) error {
   274  	return hyperv.UnmountFloppyDrive(vmName)
   275  }
   276  
   277  func (d *HypervPS4Driver) verifyPSVersion() error {
   278  
   279  	log.Printf("Enter method: %s", "verifyPSVersion")
   280  	// check PS is available and is of proper version
   281  	versionCmd := "$host.version.Major"
   282  
   283  	var ps powershell.PowerShellCmd
   284  	cmdOut, err := ps.Output(versionCmd)
   285  	if err != nil {
   286  		return err
   287  	}
   288  
   289  	versionOutput := strings.TrimSpace(cmdOut)
   290  	log.Printf("%s output: %s", versionCmd, versionOutput)
   291  
   292  	ver, err := strconv.ParseInt(versionOutput, 10, 32)
   293  
   294  	if err != nil {
   295  		return err
   296  	}
   297  
   298  	if ver < 4 {
   299  		err := fmt.Errorf("%s", "Windows PowerShell version 4.0 or higher is expected")
   300  		return err
   301  	}
   302  
   303  	return nil
   304  }
   305  
   306  func (d *HypervPS4Driver) verifyPSHypervModule() error {
   307  
   308  	log.Printf("Enter method: %s", "verifyPSHypervModule")
   309  
   310  	versionCmd := "function foo(){try{ $commands = Get-Command -Module Hyper-V;if($commands.Length -eq 0){return $false} }catch{return $false}; return $true} foo"
   311  
   312  	var ps powershell.PowerShellCmd
   313  	cmdOut, err := ps.Output(versionCmd)
   314  	if err != nil {
   315  		return err
   316  	}
   317  
   318  	if powershell.IsFalse(cmdOut) {
   319  		err := fmt.Errorf("%s", "PS Hyper-V module is not loaded. Make sure Hyper-V feature is on.")
   320  		return err
   321  	}
   322  
   323  	return nil
   324  }
   325  
   326  func (d *HypervPS4Driver) isCurrentUserAHyperVAdministrator() (bool, error) {
   327  	//SID:S-1-5-32-578 = 'BUILTIN\Hyper-V Administrators'
   328  	//https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
   329  
   330  	var script = `
   331  $identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
   332  $principal = new-object System.Security.Principal.WindowsPrincipal($identity)
   333  $hypervrole = [System.Security.Principal.SecurityIdentifier]"S-1-5-32-578"
   334  return $principal.IsInRole($hypervrole)
   335  `
   336  
   337  	var ps powershell.PowerShellCmd
   338  	cmdOut, err := ps.Output(script)
   339  	if err != nil {
   340  		return false, err
   341  	}
   342  
   343  	return powershell.IsTrue(cmdOut), nil
   344  }
   345  
   346  func (d *HypervPS4Driver) verifyHypervPermissions() error {
   347  
   348  	log.Printf("Enter method: %s", "verifyHypervPermissions")
   349  
   350  	hyperVAdmin, err := d.isCurrentUserAHyperVAdministrator()
   351  	if err != nil {
   352  		log.Printf("Error discovering if current is is a Hyper-V Admin: %s", err)
   353  	}
   354  	if !hyperVAdmin {
   355  
   356  		isAdmin, _ := powershell.IsCurrentUserAnAdministrator()
   357  
   358  		if !isAdmin {
   359  			err := fmt.Errorf("%s", "Current user is not a member of 'Hyper-V Administrators' or 'Administrators' group")
   360  			return err
   361  		}
   362  	}
   363  
   364  	return nil
   365  }
   366  
   367  // Connect connects to a VM specified by the name given.
   368  func (d *HypervPS4Driver) Connect(vmName string) (context.CancelFunc, error) {
   369  	return hyperv.ConnectVirtualMachine(vmName)
   370  }
   371  
   372  // Disconnect disconnects to a VM specified by calling the context cancel function returned
   373  // from Connect.
   374  func (d *HypervPS4Driver) Disconnect(cancel context.CancelFunc) {
   375  	hyperv.DisconnectVirtualMachine(cancel)
   376  }