ananace / fog-hyperv Goto Github PK
View Code? Open in Web Editor NEWHyper-V provider for fog
License: MIT License
Hyper-V provider for fog
License: MIT License
To replace stupidly long command lists with something more shell-ish.
New-VM -BootDevice NetworkAdapter -Generation 1 -Name aimee-nappo.example.com -NewVHDPath C:\VHD\Disk.vhdx -NewVHDSizeBytes 68719467636 -SwitchName net_switch -MemoryStartupBytes 536870912
Would instead become;
$Args = @(
'BootDevice' = "NetworkAdapter";
'Generation' = 1;
'Name' = "aimee-nappo.example.com";
'NewVHDPath' = "C:\VHD\Disk.vhdx";
'NewVHDSizeBytes' = 68719467636;
'SwitchName' = "net_switch";
'MemoryStartupBytes' = 536870912;
)
New-VM @Args
This would probably also allow transferring argument values in JSON format, which would drastically reduce the risk of encoding problems and code execution issues.
Some cmdlets (*-VMGroup
, *-VMHostCluster
, etc) are only available on new enough versions of Hyper-V.
This should be detected so such actions can be handled intelligently.
Vagrant's method of doing this;
$VmmsPath = if ([environment]::Is64BitProcess) { "$($env:SystemRoot)\System32\vmms.exe" } else { "$($env:SystemRoot)\Sysnative\vmms.exe" }
$HyperVVersion = [version](Get-Item $VmmsPath).VersionInfo.ProductVersion
This seems to be necessary to properly support clusters
Currently, trying to access a second computer in a PSRemoting session with most transports will fail, like such;
> c
=> #<Fog::Compute::Hyperv::Real:225660160380 ... @hyperv_transport=:negotiate ... >
> c.hosts.get '.'
=> <Fog::Compute::Hyperv::Host
name="EXAMPLE1",
...
>
> c.hosts.get 'example2'
Fog::Hyperv::Errors::PSError: You do not have permission to perform the operation. Contact your administrator if you believe you should have permission to perform this operation.
When executing Get-VMHost -ComputerName example2
This can be solved by setting up advanced CredSSP chaining or Kerberos credential passing.
But a simple solution could also be to launch multiple connections by reusing the original credentials, running the given command on all provided computers, and then aggregating the results.
Most of the cmdlets support providing snapshot objects for queries, probably depends on #5 to allow for the object lookup though.
Hi there,
Been running into a bug with Hyper-V, dhcp-isc and Foreman 1.16. (All running latest version on Debian 9 or Windows Server 2016). Creating a host from the foreman interface works just as intended, the VM is created and the boots correctly and I am able to start the Debian preseed for the host. However, during the final step of the unattended installation, a finish script will run: calling the foreman api and telling it that the build has finished. During this step, foreman finilises the machine. One of the step that it does is delete the DCHP lease and recreate it removing the requirement for provising. This is where the bug occurs.
Hyper-V output the MAC in uppercase, while ISC-DHCP records the in lowercase. So whenever you require Foreman for the lowcase MAC address, the tell you that the mac address does not exist:
$ curl -k https://foreman.example.com:8443/dhcp/192.168.0.0/mac/00:15:5D:11:73:0F --cert /etc/puppetlabs/puppet/ssl/certs/foreman.example.com.pem --key /etc/puppetlabs/puppet/ssl/private_keys/foreman.example.com.pem
$ No DHCP record for MAC 192.168.0.0/00:15:5D:11:73:0F
And if we request it with lower case:
curl -k https://foreman.example.com:8443/dhcp/192.168.0.0/mac/00:15:5d:11:73:0f --cert /etc/puppetlabs/puppet/ssl/certs/foreman.example.com.pem --key /etc/puppetlabs/puppet/ssl/private_keys/foreman.example.com.pem
{"name":"boyd-chafin.example.com","ip":"192.168.0.54","mac":"00:15:5d:11:73:0f","subnet":"192.168.0.0/255.255.255.0","type":"reservation","hostname":"boyd-chafin.example.com","deleteable":true,"hardware_type":"ethernet","filename":"pxelinux.0","nextServer":"192.168.0.1"}
But what happens when you sent a delete for this record that 'does not excist'?
$ curl -k -XDELETE https://foreman.example.com:8443/dhcp/192.168.0.0/mac/00:15:5D:11:73:0F --cert /etc/puppetlabs/puppet/ssl/certs/foreman.example.com.pem --key /etc/puppetlabs/puppet/ssl/private_keys/foreman.example.com.pem
$ echo $?
$ 0
Looking at the log file of the foreman proxy, you will see just a simple http 200 response for this call, but no communication will be done to the DHCP server. This is because Foreman 'thinks' that the record isn't there and thus not delete it. The next call after that is recreating the DHCP lease, but this time ISC-DHCP will tell you: 'no gonna happen, this lease already exist'. Resulting in the API returning an error and making the provision fail.
The problem here is that during the creation of the VM, dynamic mac address is disabled and a static mac address is assigned. Hyper-V determines the new mac address and then fog-hyperv requests the mac address using the 'Get-VMNetworkAdapter' cmdlet. This cmdlet always returns the mac in upercase:
Get-VMNetworkAdapter -VmName boyd-chafin.example.com | select Id,ComputerName,Connected,Dynamic
MacAddressEnabled,IpAddresses,IsExternalAdapter,IsLegacy,IsManagementOs,MacAddress,Name,SwitchId,SwitchName,VmId,VmName
Id : <REMOVED>
ComputerName : <REMOVED>
Connected : True
DynamicMacAddressEnabled : False
IPAddresses : {}
IsExternalAdapter : False
IsLegacy : True
IsManagementOs : False
MacAddress : 00155D11730F
Name : Legacy Network Adapter
SwitchId : <removed>
SwitchName : Default Switch
VMId : <removed>
VMName : boyd-chafin.example.com
Now, I will also reports this bug at the foreman project, because a mac address is NOT case sensitive, thus the API should not handle it with case sensitivy. However, you could also help with this; If this plugin would convert the mac-address to lowercase; there wouldn't be a problem. Some dirty hack I did to make this work is the following code in the network_adapter request:
module Fog
module Compute
class Hyperv
class Real
def get_vm_network_adapter(options = {})
requires_one options, :vm_name, :all, :management_os
data = run_shell('Get-VMNetworkAdapter', options)
data[:mac_address] = data[:mac_address].downcase
data
end
end
class Mock
def get_vm_network_adapter(args = {})
requires_one args, :vm_name, :all, :management_os
data = handle_mock_response(args)
if args[:all]
data
elsif args[:vm_name]
data.find { |i| i[:vm_name].casecmp(args[:vm_name]).zero? }
elsif args[:management_os]
data.find { |i| i[:is_management_os] }
end
end
end
end
end
end
Maybe you have a beter (cleaner) solution for this?
https://docs.microsoft.com/en-us/powershell/module/hyper-v/set-vmnetworkadaptervlan
Might need to look into doing object passthrough for this, as network adapter names are not unique.
Is there a way to change ip_address of the created HyperV VM , such that we can RDP into it. Right now, the only way is to use 'connect' option and then go in there and change TCP/IPv4 using GUI only.
PS- I see a field "ip_addresses" in network adapters, but unable to change it, there is no method as such.
Urgently need it for doing RDP.
In short- how to assign ip address to the generated HyperV Virtual machine using fog-hyperV?
See ananace/foreman_hyperv#10 for an example of issues caused by this.
It would seem that the creation_arguments
for ComputerCollection and VMCollection aren't doing their job properly, or maybe said collections aren't actually of the right type.
This will probably require a bit of debugging, so maybe the correct solution will just be to override the new
methods to force the additions in a duplicated manner until said debugging is done.
Most of the cmdlets will pause and ask for user input in case required arguments are missing, this is A Bad Thing™ if you're running without stdin connected.
Because of how UEFI handles the boot order, it's not as simple to change as it is on generation 1. (BIOS)
A thought would be to still read an array of enum values like the current BIOS config, and generate a PS script from that.
The generated script for a call could then look something like;
firmware.boot_order = [{NetworkAdapter: '<NIC ID>'}, {VHD: '<HD ID>'}, :VHD]
# Or possibly with fog models instead;
firmware.boot_order = [network_adapter.first, hard_drive.get('New disk')]
$VM = Get-VM -VMId "<VM ID>"
$NICs = Get-VMNetworkAdapter -VM $VM
$VHDs = Get-VMHardDiskDrive -VM $VM
$Boot1 = $NICs | where Id -eq "<NIC ID>" # NetworkAdapter: '<NIC ID/Name/etc>'
$Boot2 = $VHDs | where Id -eq "<HD ID>" # VHD: '<HD ID>/<Path>/<Controller number/etc>'
$Boot3 = $VHDs | select -First 1 # :VHD
Set-VMFirmware -BootOrder $Boot1, $Boot2, $Boot3
Currently, each server will have to check for clusters, and access all the model collections through said cluster to be able to use the cluster in question. Otherwise collections will only ever return what's running on the exact node you've connected to, which wouldn't be helpful if running the Hyper-V provider against a cluster management node.
A better solution might be to run some kind of query on connection, delegate it to a is_clustered?
method on the compute connection, and then default to reading cluster information if the machine is part of a cluster.
Or possibly provide a hyperv_default_cluster
(?) parameter that can be provided to the connection, so that collections default to reading clustered information from said cluster.
Of course, this would be best done in a way that doesn't hide the implementation of said feature from the user, so that they know why they get the data they actually receive.
Instead of having puts
spread through the code.
As the title suggests, set up Mock
instances of things and write tests to use them.
All the methods need to get some better - and more descriptive - input fields instead.
For instance, perhaps Server
could have its power off method split into multiples;
def turn_off
requires :name, :computer_name
service.stop_vm name: name,
computer_name: computer_name,
turn_off: true
end
def stop(force = false)
requires :name, :computer_name
service.stop_vm name: name,
computer_name: computer_name,
force: force
end
Or just simplifying down slightly;
def stop(method = nil)
requires :name, :computer_name
args = {
name: name,
computer_name: computer_name
}
args[method] = true if [:force, :turn_off].include? method
service.stop_vm args
end
Hey,
I'm seeing the following issue, likely related to 4574e20#diff-71f294f976a361bc4b9099a12f5c25ae.
State is returned as null from fog at command line:
In the foreman, VMs all show as powered off.
Clicking on one of the VMs throws the following:
| NoMethodError: undefined method `start_with?' for :id:Symbol
| /usr/share/foreman/.gem/ruby/gems/fog-hyperv-0.0.7/lib/fog/hyperv/compute.rb:240:in `block in run_shell'
| /usr/share/foreman/.gem/ruby/gems/fog-hyperv-0.0.7/lib/fog/hyperv/compute.rb:240:in `delete_if'
| /usr/share/foreman/.gem/ruby/gems/fog-hyperv-0.0.7/lib/fog/hyperv/compute.rb:240:in `run_shell'
| /usr/share/foreman/.gem/ruby/gems/fog-hyperv-0.0.7/lib/fog/hyperv/requests/compute/get_vm.rb:6:in `get_vm'
| /usr/share/foreman/.gem/ruby/gems/fog-hyperv-0.0.7/lib/fog/collection.rb:20:in `all'
| /usr/share/foreman/.gem/ruby/gems/fog-hyperv-0.0.7/lib/fog/collection.rb:27:in `get'
| /usr/share/foreman/.gem/ruby/gems/fog-hyperv-0.0.7/lib/fog/hyperv/models/compute/servers.rb:16:in `get'
| /usr/share/foreman/app/models/compute_resource.rb:173:in `find_vm_by_uuid'
| /usr/share/foreman/app/controllers/compute_resources_vms_controller.rb:117:in `find_vm'
| /opt/rh/sclo-ror42/root/usr/share/gems/gems/activesupport-4.2.5.1/lib/active_support/callbacks.rb:432:in `block in make_lambda'
If I comment out the following line in lib/fog/hyperv/compute.rb:
options.delete_if { |o| o.start_with? '_' }
I am able to see the VM details with N/A as the state.
Trying to power on the VM throws the following:
However, the VM does actually start:
Kevin
Hi,
I see a
Oops, we're sorry but something went wrong undefined method `start_with?' for 🆔Symbol
details:
undefined method start_with?' for :id:Symbol /opt/rh/rh-ruby22/root/usr/local/share/gems/gems/fog-hyperv-0.0.7/lib/fog/hyperv/compute.rb:240:in
block in run_shell'
/opt/rh/rh-ruby22/root/usr/local/share/gems/gems/fog-hyperv-0.0.7/lib/fog/hyperv/compute.rb:240:in delete_if' /opt/rh/rh-ruby22/root/usr/local/share/gems/gems/fog-hyperv-0.0.7/lib/fog/hyperv/compute.rb:240:in
run_shell'
/opt/rh/rh-ruby22/root/usr/local/share/gems/gems/fog-hyperv-0.0.7/lib/fog/hyperv/requests/compute/get_vm.rb:6:in get_vm' /opt/rh/rh-ruby22/root/usr/local/share/gems/gems/fog-hyperv-0.0.7/lib/fog/collection.rb:20:in
all'
/opt/rh/rh-ruby22/root/usr/local/share/gems/gems/fog-hyperv-0.0.7/lib/fog/collection.rb:27:in get' /opt/rh/rh-ruby22/root/usr/local/share/gems/gems/fog-hyperv-0.0.7/lib/fog/hyperv/models/compute/servers.rb:16:in
get'
/usr/share/foreman/app/models/compute_resource.rb:173:in `find_vm_by_uuid'
whenever I enter a VM from the table of virtual machines on any Hyper-V host.
Regards,
Rudi G.
To replace cmdlet calls like Add-VMNetworkAdapter -ComputerName <host> -VMName <vm_name> -Switch <switch>
With something more like;
$VM = Get-VM -Id "<guid>"
$VM | Add-VMNetworkAdapter -Switch <switch>
Hey,
After updating to version 0.0.6, I am unable to create or view VMs. The following error is thrown:
Following error is thrown when testing from command line:
Issue is missing file for set_vm_network_adapter_vlan referenced in compute.rb. It works correctly after creating the file.
[kevin@zabbix dev]$ vim fog-hyperv/lib/fog/hyperv/requests/compute/set_vm_network_adapter_vlan.rb
module Fog
module Compute
class Hyperv
class Real
def set_vm_network_adapter_vlan(options = {})
requires_one options, :vm_name, :management_os
run_shell('Set-VMNetworkAdapterVlan', options)
end
end
end
end
end
Kevin
As the title suggests, currently VHD paths will end up broken if the VM gets a checkpoint.
Launching the PS cmdlets for talking to Hyper-V takes quite a bit longer than just running the raw WMI queries to get the same information, so figuring out a series of queries to get the same data would be helpful.
There aren't any WMI RPC gems available from what I can see, so the cmdlets would still be used for all write operations.
reload
command.No idea which is these would actually be helped by having them as raw WMI queries, and which would just be more work than it's worth.
It's also very possible that it'd be better to ignore WMI completely and just work on implementing faster cmdlet queries.
This has only been developed and tested against a single machine, make sure it supports Hyper-V clusters.
This MVP only implements the basics of controlling VMs, none of the more advanced models are in place yet, so implementing them as well would be good.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.