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 }