Coder Social home page Coder Social logo

fog-hyperv's Introduction

Fog Hyper-V

Build Status Gem Version

Manage your Hyper-V instance with the help of the Fog cloud service abstractions.

Installation

Add this line to your application's Gemfile:

gem 'fog-hyperv'

And then execute:

$ bundle

Or install it yourself as:

$ gem install fog-hyperv

Usage

To remotely manage your Hyper-V instance;

require 'fog/hyperv'

compute = Fog::Compute.new(
  provider: :hyperv,
  hyperv_host: 'hyperv.example.com',
  hyperv_username: 'domain\\user',
  hyperv_password: 'password'
)

compute.servers.all
#=> [<Fog::Compute::Hyperv::Server
#=>   id='',
#=>   name='example',
#=>   computer_name='HYPERV',
#=>   dynamic_memory_enabled=false,
#=>   ...

Troubleshooting

If you're getting WinRM::AuthorizationErrors from the negotiate transport even when using a valid user, make sure that the WinRM service is configured for Negotiate auth.

If you're using a local (non-domain) user, you may also need to set the DWORD registry value LocalAccountTokenFilterPolicy at HKLM\software\Microsoft\Windows\CurrentVersion\Policies\system to 1.

Development

After checking out the repo, run bundle install to install dependencies. Then, run rake test to run the tests. You can also run bundle exec irb for an interactive prompt that will allow you to experiment.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ananace/fog-hyperv

fog-hyperv's People

Contributors

ananace avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

ksagle77

fog-hyperv's Issues

Hosted collections don't pass through host parameters correctly

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.

Missing set_vm_network_adapter_vlan.rb

Hey,

After updating to version 0.0.6, I am unable to create or view VMs. The following error is thrown:

image

Following error is thrown when testing from command line:

image

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

image

Kevin

Don't pass around option hashes all over the place

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

Always support executing commands on computers other than the first hop

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.

Figure out a better way to handle clustering

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.

Implement missing Hyper-V models

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.

Convert read operations over to WQL queries where applicable

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.

Possible Models;

  • Fog::Compute::Hyperv::Bios
  • Fog::Compute::Hyperv::DvdDrive(s)
  • Fog::Compute::Hyperv::Firmware
  • Fog::Compute::Hyperv::FloppyDrive(s)
  • Fog::Compute::Hyperv::HardDrive(s)
  • Fog::Compute::Hyperv::NetworkAdapter(s)
  • Fog::Compute::Hyperv::Server(s)
  • Fog::Compute::Hyperv::Switch(es)
    • Only gets the name and UUID, which is just enough to use it for VM creation or for getting additional data with the reload command.
  • Fog::Compute::Hyperv::Vhd

Possible Requests;

  • Version query

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.

Case sensitive MAC Address

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?

Use argument splatting

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.

IP address change of provisioned VM

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?

Implement cluster support

This has only been developed and tested against a single machine, make sure it supports Hyper-V clusters.

Support boot order changes on generation 2

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

error when examine VM on hyper-v

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.

Detect Hyper-V version for using newer cmdlets

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

State not recognized correctly

Hey,

I'm seeing the following issue, likely related to 4574e20#diff-71f294f976a361bc4b9099a12f5c25ae.

State is returned as null from fog at command line:

image

In the foreman, VMs all show as powered off.

image

image

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.

image

Trying to power on the VM throws the following:
image

However, the VM does actually start:

image

Kevin

Support VM Snapshots as well

Most of the cmdlets support providing snapshot objects for queries, probably depends on #5 to allow for the object lookup though.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.