foreman_hyperv 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +22 -0
- data/.rubocop_todo.yml +20 -0
- data/.travis.yml +5 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +14 -0
- data/Rakefile +10 -0
- data/app/assets/javascripts/compute_resources/hyperv/base.js +6 -0
- data/app/helpers/hyperv_helpers.rb +7 -0
- data/app/models/concerns/fog_extensions/hyperv/compute.rb +0 -0
- data/app/models/concerns/fog_extensions/hyperv/network_adapter.rb +29 -0
- data/app/models/concerns/fog_extensions/hyperv/server.rb +77 -0
- data/app/models/concerns/fog_extensions/hyperv/vhd.rb +12 -0
- data/app/models/foreman_hyperv/hyperv.rb +246 -0
- data/app/views/compute_resources/form/_hyperv.html.erb +7 -0
- data/app/views/compute_resources/show/_hyperv.html.erb +1 -0
- data/app/views/compute_resources_vms/form/hyperv/_base.html.erb +20 -0
- data/app/views/compute_resources_vms/form/hyperv/_network.html.erb +10 -0
- data/app/views/compute_resources_vms/form/hyperv/_volume.html.erb +5 -0
- data/app/views/compute_resources_vms/index/_hyperv.html.erb +25 -0
- data/app/views/compute_resources_vms/show/_hyperv.html.erb +25 -0
- data/foreman_hyperv.gemspec +27 -0
- data/lib/foreman_hyperv/engine.rb +35 -0
- data/lib/foreman_hyperv/version.rb +3 -0
- data/lib/foreman_hyperv.rb +4 -0
- data/test/foreman_hyperv_test.rb +11 -0
- data/test/test_helper.rb +4 -0
- metadata +130 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA1:
         | 
| 3 | 
            +
              metadata.gz: 095c817dd697a8c2bde70d4b2a4d4dad16eba039
         | 
| 4 | 
            +
              data.tar.gz: 59761e7d008a15a913ee8951678c8467a5ed85ec
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 61ef39ff83c31aa3e9fd8b8a6c8151163b4eba692b8c54025c3ab0544e9c6b22990c44cdb5d71d7f3b81fe2ec5073def03354d513c0c8a6483ea3689724202f0
         | 
| 7 | 
            +
              data.tar.gz: 35cc0657a3474aacb7033550580478fd4285599e290147fb95713f57c8a918b9f4fce48a7977d14574d39a7f21f74637be7dbc8e432497752e816cf0658a3bd7
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/.rubocop.yml
    ADDED
    
    | @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            inherit_from:
         | 
| 2 | 
            +
              - .rubocop_todo.yml
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Rails:
         | 
| 5 | 
            +
              Enabled: true # always run the rails cops
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            # Don't enforce documentation
         | 
| 8 | 
            +
            Style/Documentation:
         | 
| 9 | 
            +
              Enabled: false
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Style/HashSyntax:
         | 
| 12 | 
            +
              Enabled: false
         | 
| 13 | 
            +
              SupportedStyles:
         | 
| 14 | 
            +
                - ruby19
         | 
| 15 | 
            +
                - hash_rockets
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            # Force before_filter until upgrade to Rails 4
         | 
| 18 | 
            +
            Rails/ActionFilter:
         | 
| 19 | 
            +
              EnforcedStyle: filter
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            Metrics/MethodLength:
         | 
| 22 | 
            +
              Max: 20
         | 
    
        data/.rubocop_todo.yml
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # This configuration was generated by `rubocop --auto-gen-config`
         | 
| 2 | 
            +
            # on 2015-05-21 16:13:17 +0300 using RuboCop version 0.26.1.
         | 
| 3 | 
            +
            # The point is for the user to remove these configuration records
         | 
| 4 | 
            +
            # one by one as the offenses are removed from the code base.
         | 
| 5 | 
            +
            # Note that changes in the inspected code, or installation of new
         | 
| 6 | 
            +
            # versions of RuboCop, may require this file to be generated again.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # Offense count: 11
         | 
| 9 | 
            +
            # Configuration parameters: AllowURI, URISchemes.
         | 
| 10 | 
            +
            Metrics/LineLength:
         | 
| 11 | 
            +
              Max: 111
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            # Offense count: 8
         | 
| 14 | 
            +
            Style/Documentation:
         | 
| 15 | 
            +
              Enabled: false
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            # Offense count: 1
         | 
| 18 | 
            +
            # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
         | 
| 19 | 
            +
            Style/Next:
         | 
| 20 | 
            +
              Enabled: false
         | 
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            The MIT License (MIT)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Copyright (c) 2017 Alexander Olofsson
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         | 
| 6 | 
            +
            of this software and associated documentation files (the "Software"), to deal
         | 
| 7 | 
            +
            in the Software without restriction, including without limitation the rights
         | 
| 8 | 
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         | 
| 9 | 
            +
            copies of the Software, and to permit persons to whom the Software is
         | 
| 10 | 
            +
            furnished to do so, subject to the following conditions:
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            The above copyright notice and this permission notice shall be included in
         | 
| 13 | 
            +
            all copies or substantial portions of the Software.
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 16 | 
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 17 | 
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         | 
| 18 | 
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 19 | 
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         | 
| 20 | 
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         | 
| 21 | 
            +
            THE SOFTWARE.
         | 
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            # Foreman Hyper-V
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Microsoft Hyper-V compute resource for Foreman
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Uses the in-development `fog-hyperv` gem found [here](https://github.com/ace13/fog-hyperv).
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ## Contributing
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Bug reports and pull requests are welcome on GitHub at https://github.com/ace13/foreman_hyperv.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## License
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
         | 
| 14 | 
            +
             | 
    
        data/Rakefile
    ADDED
    
    
| 
            File without changes
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            module FogExtensions
         | 
| 2 | 
            +
              module Hyperv
         | 
| 3 | 
            +
                module NetworkAdapter
         | 
| 4 | 
            +
                  extend ActiveSupport::Concern
         | 
| 5 | 
            +
                  include ActionView::Helpers::NumberHelper
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def to_s
         | 
| 8 | 
            +
                    name
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def mac
         | 
| 12 | 
            +
                    m = mac_address
         | 
| 13 | 
            +
                    "#{m[0, 2]}:#{m[2, 2]}:#{m[4, 2]}:#{m[6, 2]}:#{m[8, 2]}:#{m[10, 2]}"
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def mac=(m)
         | 
| 17 | 
            +
                    self.mac_address = m.remove ':'
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def network
         | 
| 21 | 
            +
                    switch_name
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def network=(net)
         | 
| 25 | 
            +
                    self.switch_name = net
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,77 @@ | |
| 1 | 
            +
            module FogExtensions
         | 
| 2 | 
            +
              module Hyperv
         | 
| 3 | 
            +
                module Server
         | 
| 4 | 
            +
                  extend ActiveSupport::Concern
         | 
| 5 | 
            +
                  include ActionView::Helpers::NumberHelper
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  attr_accessor :start
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def to_s
         | 
| 10 | 
            +
                    name
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def folder_name
         | 
| 14 | 
            +
                    name.gsub(/[^0-9A-Za-z.\-]/, '_')
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def mac(m = mac_addresses.first)
         | 
| 18 | 
            +
                    "#{m[0, 2]}:#{m[2, 2]}:#{m[4, 2]}:#{m[6, 2]}:#{m[8, 2]}:#{m[10, 2]}"
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def clean_mac_addresses
         | 
| 22 | 
            +
                    network_adapters.map { |n| mac(n.mac_address) }
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  def interfaces
         | 
| 26 | 
            +
                    network_adapters
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  def volumes
         | 
| 30 | 
            +
                    vhds
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def persisted?
         | 
| 34 | 
            +
                    identity.present?
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  def interfaces_attributes=(_attributes); end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def volumes_attributes=(_attributes); end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  def secure_boot_enabled=(_); end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def secure_boot_enabled
         | 
| 44 | 
            +
                    return false if generation == 1
         | 
| 45 | 
            +
                    firmware.secure_boot == :On
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def reset
         | 
| 49 | 
            +
                    restart(force: true)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def stop
         | 
| 53 | 
            +
                    requires :name, :computer_name
         | 
| 54 | 
            +
                    service.stop_vm options.merge(
         | 
| 55 | 
            +
                      name: name,
         | 
| 56 | 
            +
                      computer_name: computer_name,
         | 
| 57 | 
            +
                      force: true
         | 
| 58 | 
            +
                    )
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  def vm_description
         | 
| 62 | 
            +
                    format _('%{cpus} CPUs and %{ram} memory'),
         | 
| 63 | 
            +
                           cpus: processor_count,
         | 
| 64 | 
            +
                           ram: number_to_human_size(memory_startup)
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  def select_nic(fog_nics, nic)
         | 
| 68 | 
            +
                    nic_attrs = nic.compute_attributes
         | 
| 69 | 
            +
                    logger.debug "select_nic(#{fog_nics}, #{nic}[#{nic_attrs}])"
         | 
| 70 | 
            +
                    match =   fog_nics.detect { |fn| fn.id == nic_attrs['id'] } # Check the id
         | 
| 71 | 
            +
                    match ||= fog_nics.detect { |fn| fn.name == nic_attrs['name'] } # Check the name
         | 
| 72 | 
            +
                    match ||= fog_nics.detect { |fn| fn.switch_name == nic_attrs['network'] } # Fall back to the switch
         | 
| 73 | 
            +
                    match
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| @@ -0,0 +1,246 @@ | |
| 1 | 
            +
            module ForemanHyperv
         | 
| 2 | 
            +
              class Hyperv < ::ComputeResource
         | 
| 3 | 
            +
                validates :url, :user, :password, presence: true
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def capabilities
         | 
| 6 | 
            +
                  [:build]
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def self.provider_friendly_name
         | 
| 10 | 
            +
                  'Hyper-V'
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def self.model_name
         | 
| 14 | 
            +
                  ComputeResource.model_name
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def test_connection(options = {})
         | 
| 18 | 
            +
                  super options
         | 
| 19 | 
            +
                  client.valid?
         | 
| 20 | 
            +
                rescue Fog::Hyperv::Errors::ServiceError, ArgumentError, WinRM::WinRMAuthorizationError
         | 
| 21 | 
            +
                  false
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def provided_attributes
         | 
| 25 | 
            +
                  super.merge(mac: :mac)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                # TODO
         | 
| 29 | 
            +
                def max_cpu_count
         | 
| 30 | 
            +
                  hypervisor.logical_processor_count
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def max_memory
         | 
| 34 | 
            +
                  hypervisor.memory_capacity
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def associated_host(vm)
         | 
| 38 | 
            +
                  associate_by('mac', vm.clean_mac_addresses)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def new_vm(attr = {})
         | 
| 42 | 
            +
                  vm = super
         | 
| 43 | 
            +
                  interfaces = nested_attributes_for :interfaces, attr[:interfaces_attributes]
         | 
| 44 | 
            +
                  interfaces.map { |i| vm.interfaces << new_interface(i) }
         | 
| 45 | 
            +
                  volumes = nested_attributes_for :volumes, attr[:volumes_attributes]
         | 
| 46 | 
            +
                  volumes.map { |v| vm.volumes << new_volume(v) }
         | 
| 47 | 
            +
                  vm
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def stop_vm(uuid)
         | 
| 51 | 
            +
                  find_vm_by_uuid(uuid).stop force: true
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def create_vm(args = {})
         | 
| 55 | 
            +
                  args = vm_instance_defaults.merge(args.to_hash.deep_symbolize_keys)
         | 
| 56 | 
            +
                  logger.debug "Creating a VM with arguments; #{args}"
         | 
| 57 | 
            +
                  pre_create = {
         | 
| 58 | 
            +
                    boot_device: 'NetworkAdapter',
         | 
| 59 | 
            +
                    generation: args[:generation].to_i,
         | 
| 60 | 
            +
                    memory_startup: args[:memory_startup].presence,
         | 
| 61 | 
            +
                    name: args[:name],
         | 
| 62 | 
            +
                    no_vhd: true
         | 
| 63 | 
            +
                  }
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  vm = client.servers.create pre_create
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  post_save = {
         | 
| 68 | 
            +
                    dynamic_memory_enabled: ActiveRecord::Type::Boolean.new.type_cast_from_user(args[:dynamic_memory_enabled]),
         | 
| 69 | 
            +
                    notes: args[:notes].presence,
         | 
| 70 | 
            +
                    processor_count: args[:processor_count].to_i
         | 
| 71 | 
            +
                  }
         | 
| 72 | 
            +
                  post_save.each do |k, v|
         | 
| 73 | 
            +
                    vm.send("#{k}=".to_sym, v)
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  vm.save if vm.dirty?
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  if vm.generation == 2 && !args[:secure_boot_enabled].nil?
         | 
| 79 | 
            +
                    f = vm.firmware
         | 
| 80 | 
            +
                    f.secure_boot = ActiveRecord::Type::Boolean.new.type_cast_from_user(args[:secure_boot_enabled]) ? :On : :Off
         | 
| 81 | 
            +
                    f.save if f.dirty?
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  create_interfaces(vm, args[:interfaces_attributes])
         | 
| 85 | 
            +
                  create_volumes(vm, args[:volumes_attributes])
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  vm
         | 
| 88 | 
            +
                rescue StandardError => e
         | 
| 89 | 
            +
                  vm.stop turn_off: true
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  raise e
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def save_vm(uuid, attr)
         | 
| 95 | 
            +
                  vm = find_vm_by_uuid(uuid)
         | 
| 96 | 
            +
                  logger.debug "Saving a VM with arguments; #{attr}"
         | 
| 97 | 
            +
                  attr.each do |k, v|
         | 
| 98 | 
            +
                    vm.send("#{k}=".to_sym, v) if vm.respond_to?("#{k}=".to_sym)
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                  if vm.generation == 2 && !args[:secure_boot_enabled].nil?
         | 
| 101 | 
            +
                    f = vm.firmware
         | 
| 102 | 
            +
                    f.secure_boot = ActiveRecord::Type::Boolean.new.type_cast_from_user(args[:secure_boot_enabled]) ? :On : :Off
         | 
| 103 | 
            +
                    f.save if f.dirty?
         | 
| 104 | 
            +
                  end
         | 
| 105 | 
            +
                  update_interfaces(vm, attr[:interfaces_attributes])
         | 
| 106 | 
            +
                  update_volumes(vm, attr[:volumes_attributes])
         | 
| 107 | 
            +
                  vm.save if vm.dirty?
         | 
| 108 | 
            +
                  vm
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                def destroy_vm(uuid)
         | 
| 112 | 
            +
                  vm = find_vm_by_uuid(uuid)
         | 
| 113 | 
            +
                  vm.stop force: true if vm.ready?
         | 
| 114 | 
            +
                  vm.hard_drives.each do |hd|
         | 
| 115 | 
            +
                    hd.vhd.destroy if hd.path
         | 
| 116 | 
            +
                  end
         | 
| 117 | 
            +
                  # TODO: Remove the empty VM folder
         | 
| 118 | 
            +
                  vm.destroy
         | 
| 119 | 
            +
                rescue ActiveRecord::RecordNotFound, Fog::Errors::NotFound
         | 
| 120 | 
            +
                  # if the VM does not exists, we don't really care.
         | 
| 121 | 
            +
                  true
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                def new_interface(attr = {})
         | 
| 125 | 
            +
                  client.network_adapters.new attr
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                def new_volume(attr = {})
         | 
| 129 | 
            +
                  client.vhds.new attr
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                def new_cdrom(attr = {})
         | 
| 133 | 
            +
                  client.dvd_drives.new attr
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                def editable_network_interfaces?
         | 
| 137 | 
            +
                  true
         | 
| 138 | 
            +
                end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                def switches
         | 
| 141 | 
            +
                  client.switches.all # _quick_query: true
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                def supports_update?
         | 
| 145 | 
            +
                  true
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                def available_hypervisors
         | 
| 149 | 
            +
                  client.hosts
         | 
| 150 | 
            +
                end
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                def hypervisor
         | 
| 153 | 
            +
                  client.hosts.first
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                protected
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                def client
         | 
| 159 | 
            +
                  @client ||= Fog::Compute.new(
         | 
| 160 | 
            +
                    provider: :HyperV,
         | 
| 161 | 
            +
                    hyperv_endpoint: url,
         | 
| 162 | 
            +
                    hyperv_username: user,
         | 
| 163 | 
            +
                    hyperv_password: password
         | 
| 164 | 
            +
                  )
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                def vm_instance_defaults
         | 
| 168 | 
            +
                  super.merge(
         | 
| 169 | 
            +
                    generation:      1,
         | 
| 170 | 
            +
                    memory_startup:  512.megabytes,
         | 
| 171 | 
            +
                    processor_count: 1,
         | 
| 172 | 
            +
                    boot_device:     'NetworkAdapter'
         | 
| 173 | 
            +
                  )
         | 
| 174 | 
            +
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                def create_interfaces(vm, attrs)
         | 
| 177 | 
            +
                  vm.network_adapters.each(&:destroy)
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                  interfaces = nested_attributes_for :interfaces, attrs
         | 
| 180 | 
            +
                  logger.debug "Building interfaces with: #{interfaces}"
         | 
| 181 | 
            +
                  interfaces.each do |iface|
         | 
| 182 | 
            +
                    nic = vm.network_adapters.create name: iface[:name], switch_name: iface[:network]
         | 
| 183 | 
            +
                    if iface[:mac]
         | 
| 184 | 
            +
                      nic.mac = iface[:mac]
         | 
| 185 | 
            +
                      nic.dynamic_mac_address_enabled = false
         | 
| 186 | 
            +
                    end
         | 
| 187 | 
            +
                    nic.save
         | 
| 188 | 
            +
                  end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                  # Populate the MAC addresses
         | 
| 191 | 
            +
                  vm.start
         | 
| 192 | 
            +
                  vm.stop turn_off: true
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                  vm.network_adapters.reload
         | 
| 195 | 
            +
                  vm.network_adapters.each do |nic|
         | 
| 196 | 
            +
                    nic.dynamic_mac_address_enabled = false
         | 
| 197 | 
            +
                    nic.save if nic.dirty?
         | 
| 198 | 
            +
                  end
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
             | 
| 201 | 
            +
                def create_volumes(vm, attrs)
         | 
| 202 | 
            +
                  volumes = nested_attributes_for :volumes, attrs
         | 
| 203 | 
            +
                  logger.debug "Building volumes with: #{volumes}"
         | 
| 204 | 
            +
                  volumes.each do |vol|
         | 
| 205 | 
            +
                    vhd = vm.vhds.create path: vm.folder_name + '\\' + vol[:path], size: vol[:size]
         | 
| 206 | 
            +
                    vm.hard_drives.create path: vhd.path
         | 
| 207 | 
            +
                  end
         | 
| 208 | 
            +
                  vm.hard_drives.reload
         | 
| 209 | 
            +
                end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                def update_interfaces(vm, attrs)
         | 
| 212 | 
            +
                  interfaces = nested_attributes_for :interfaces, attrs
         | 
| 213 | 
            +
                  logger.debug "Updating interfaces with: #{interfaces}"
         | 
| 214 | 
            +
                  interfaces.each do |interface|
         | 
| 215 | 
            +
                    if interface[:id].blank? && interface[:_delete] != '1'
         | 
| 216 | 
            +
                      nic = vm.network_adapters.create interface
         | 
| 217 | 
            +
                      nic.dynamic_mac_address_enabled = false if nic.mac
         | 
| 218 | 
            +
                      nic.save
         | 
| 219 | 
            +
                    elsif interface[:id].present?
         | 
| 220 | 
            +
                      nic = vm.network_adapters.find { |n| n.id == interface[:id] }
         | 
| 221 | 
            +
                      if interface[:_delete] == '1'
         | 
| 222 | 
            +
                        nic.delete
         | 
| 223 | 
            +
                      else
         | 
| 224 | 
            +
                        interface.each do |k, v|
         | 
| 225 | 
            +
                          nic.send("#{k}=".to_sym, v)
         | 
| 226 | 
            +
                        end
         | 
| 227 | 
            +
                        nic.save if nic.dirty?
         | 
| 228 | 
            +
                      end
         | 
| 229 | 
            +
                    end
         | 
| 230 | 
            +
                  end
         | 
| 231 | 
            +
                end
         | 
| 232 | 
            +
             | 
| 233 | 
            +
                def update_volumes(vm, attrs)
         | 
| 234 | 
            +
                  volumes = nested_attributes_for :volumes, attrs
         | 
| 235 | 
            +
                  logger.debug "Updating volumes with: #{volumes}"
         | 
| 236 | 
            +
                  volumes.each do |volume|
         | 
| 237 | 
            +
                    if volume[:_delete] == '1' && volume[:id].present?
         | 
| 238 | 
            +
                      hd = vm.hard_drives.get(path: volume[:path])
         | 
| 239 | 
            +
                      hd.vhd.destroy
         | 
| 240 | 
            +
                      hd.destroy
         | 
| 241 | 
            +
                    end
         | 
| 242 | 
            +
                    vm.hard_drives.create(path: volume[:path], size: volume[:size]) if volume[:id].blank?
         | 
| 243 | 
            +
                  end
         | 
| 244 | 
            +
                end
         | 
| 245 | 
            +
              end
         | 
| 246 | 
            +
            end
         | 
| @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            <%= text_f f, :url, label: _('WinRM Endpoint'), help_block: _('e.g. http://host.example.com:5985/wsman')%>
         | 
| 2 | 
            +
            <%= text_f f, :user, label: _('User') %>
         | 
| 3 | 
            +
            <%= password_f f, :password, label: _('Password') %>
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            <%= link_to_function _("Test Connection"), "testConnection(this)", :class => "btn + #{@compute_resource.test_connection.is_a?(FalseClass) ? "btn-default" : "btn-success"}", :'data-url' => test_connection_compute_resources_path %>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            <%= hidden_spinner('', :id => 'test_connection_indicator') %>
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            <%# Placeholder %>
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            <%#= compute_specific_js(compute_resource, 'base') %>
         | 
| 2 | 
            +
            <%= javascript_tag("$(document).on('ContentLoad', tfm.numFields.initAll)") %>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            <%
         | 
| 5 | 
            +
              generations = [ [1, 'Generation 1 (BIOS)'], [2, 'Generation 2 (UEFI)'] ]
         | 
| 6 | 
            +
            %>
         | 
| 7 | 
            +
            <%= select_f f, :generation, generations, :first, :last, {}, label: 'Generation', disabled: !new_host, onchange: 'hypervGenerationChange()'  %>
         | 
| 8 | 
            +
            <%= checkbox_f f, :secure_boot_enabled, { label: _('Use Secure Boot') }, 'true', 'false' %>
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            <%= counter_f f, :processor_count, label: _('CPUs'), label_size: 'col-md-2' %>
         | 
| 11 | 
            +
            <%= byte_size_f f, :memory_startup, class: 'col-md-2', label: _('Memory') %>
         | 
| 12 | 
            +
            <%= checkbox_f f, :dynamic_memory_enabled, { label: _('Use Dynamic Memory') }, 'true', 'false' %>
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            <% if new_host %>
         | 
| 15 | 
            +
            <% checked = params[:host] && params[:host][:compute_attributes] && params[:host][:compute_attributes][:start] || '1' %>
         | 
| 16 | 
            +
            <%= checkbox_f f, :start, { checked: (checked == '1'), help_inline: _("Power ON this machine"), label: _('Start'), label_size: "col-md-2"} if new_host && controller_name != "compute_attributes" %>
         | 
| 17 | 
            +
            <% end %>
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            <%= textarea_f f, :notes, rows: '3', label: _('Notes') %>
         | 
| 20 | 
            +
            <%= f.hidden_field :id %>
         | 
| @@ -0,0 +1,10 @@ | |
| 1 | 
            +
            <%
         | 
| 2 | 
            +
                networks = compute_resource.switches.map do |sw|
         | 
| 3 | 
            +
                  [ sw.name, "#{sw.name}#{sw.switch_type ? " (#{sw.switch_type})" : nil}" ]
         | 
| 4 | 
            +
                end
         | 
| 5 | 
            +
            %>
         | 
| 6 | 
            +
            <%= text_f f, :name, :label => _('Name'), :label_size => 'col-md-3' %>
         | 
| 7 | 
            +
            <%= select_f f, :network, networks, :first, :last,
         | 
| 8 | 
            +
                            { include_blank: true },
         | 
| 9 | 
            +
                            { label: _('Network switch'), :label_size => 'col-md-3' } %>
         | 
| 10 | 
            +
            <%= f.hidden_field :id %>
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            <thead>
         | 
| 2 | 
            +
            <tr>
         | 
| 3 | 
            +
              <th><%= _('Name') -%></th>
         | 
| 4 | 
            +
              <th><%= _('CPUs') -%></th>
         | 
| 5 | 
            +
              <th><%= _('Memory') -%></th>
         | 
| 6 | 
            +
              <th><%= _('Computer') -%></th>
         | 
| 7 | 
            +
              <th><%= _('Power') -%></th>
         | 
| 8 | 
            +
              <th><%= _('Actions') -%></th>
         | 
| 9 | 
            +
            </tr>
         | 
| 10 | 
            +
            </thead>
         | 
| 11 | 
            +
            <tbody>
         | 
| 12 | 
            +
            <% @vms.each do |vm| -%>
         | 
| 13 | 
            +
                <tr>
         | 
| 14 | 
            +
                  <td><%= link_to_if_authorized vm.name, hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :auth_action => 'view', :authorizer => authorizer) %></td>
         | 
| 15 | 
            +
                  <td><%= vm.processor_count %></td>
         | 
| 16 | 
            +
                  <td><%= number_to_human_size vm.memory_startup %></td>
         | 
| 17 | 
            +
                  <td><%= vm.computer_name %></td>
         | 
| 18 | 
            +
                  <td><span <%= vm_power_class(vm.ready?) %>><%= vm_state(vm) %></span></td>
         | 
| 19 | 
            +
                  <td>
         | 
| 20 | 
            +
                    <%= action_buttons(vm_power_action(vm, authorizer),
         | 
| 21 | 
            +
                        display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => vm.identity).merge(:auth_object => @compute_resource, :authorizer => authorizer))) %>
         | 
| 22 | 
            +
                  </td>
         | 
| 23 | 
            +
                </tr>
         | 
| 24 | 
            +
            <% end -%>
         | 
| 25 | 
            +
            </tbody>
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            <% title @vm.name %>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <div class='col-md-12'>
         | 
| 4 | 
            +
              <table class="<%= table_css_classes %>">
         | 
| 5 | 
            +
                <thead>
         | 
| 6 | 
            +
                  <tr><th colspan="2"><%=_('Properties') %></th></tr>
         | 
| 7 | 
            +
                </thead>
         | 
| 8 | 
            +
                <tbody>
         | 
| 9 | 
            +
                  <%= prop :id %>
         | 
| 10 | 
            +
                  <%#= prop :cluster %>
         | 
| 11 | 
            +
                  <%= prop :memory_startup %>
         | 
| 12 | 
            +
                  <% if @vm.dynamic_memory_enabled %>
         | 
| 13 | 
            +
                    <%= prop :memory_minimum %>
         | 
| 14 | 
            +
                    <%= prop :memory_maximum %>
         | 
| 15 | 
            +
                  <% end %>
         | 
| 16 | 
            +
                  <%= prop :public_ip_address %>
         | 
| 17 | 
            +
                  <%= prop :mac %>
         | 
| 18 | 
            +
                  <%= prop :processor_count %>
         | 
| 19 | 
            +
                  <%= prop :computer_name %>
         | 
| 20 | 
            +
                  <%= prop :status %>
         | 
| 21 | 
            +
                  <%= prop :state %>
         | 
| 22 | 
            +
                  <%= prop :notes %>
         | 
| 23 | 
            +
                </tbody>
         | 
| 24 | 
            +
              </table>
         | 
| 25 | 
            +
            </div>
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            lib = File.expand_path('../lib', __FILE__)
         | 
| 4 | 
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         | 
| 5 | 
            +
            require 'foreman_hyperv/version'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Gem::Specification.new do |spec|
         | 
| 8 | 
            +
              spec.name          = 'foreman_hyperv'
         | 
| 9 | 
            +
              spec.version       = ForemanHyperv::VERSION
         | 
| 10 | 
            +
              spec.authors       = ['Alexander Olofsson']
         | 
| 11 | 
            +
              spec.email         = ['alexander.olofsson@liu.se']
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              spec.summary       = 'Hyper-V as a Compute Resource for Foreman'
         | 
| 14 | 
            +
              spec.description   = 'Hyper-V as a Compute Resource for Foreman'
         | 
| 15 | 
            +
              spec.homepage      = 'https://github.com/ace13/foreman_hyperv'
         | 
| 16 | 
            +
              spec.license       = 'MIT'
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              spec.files         = `git ls-files -z`.split("\x0")
         | 
| 19 | 
            +
              spec.test_files    = spec.files.grep(%r{^test\/})
         | 
| 20 | 
            +
              spec.require_paths = ['lib']
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              spec.add_runtime_dependency 'fog-hyperv', '~> 0.0.1'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              spec.add_development_dependency 'bundler', '~> 1.13'
         | 
| 25 | 
            +
              spec.add_development_dependency 'rake', '~> 10.0'
         | 
| 26 | 
            +
              spec.add_development_dependency 'minitest', '~> 5.0'
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module ForemanHyperv
         | 
| 2 | 
            +
              class Engine < ::Rails::Engine
         | 
| 3 | 
            +
                engine_name 'foreman_hyperv'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                initializer 'foreman_hyperv.register_plugin', :before => :finisher_hook do
         | 
| 6 | 
            +
                  Foreman::Plugin.register :foreman_hyperv do
         | 
| 7 | 
            +
                    requires_foreman '>= 1.14'
         | 
| 8 | 
            +
                    compute_resource ForemanHyperv::Hyperv
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                initializer 'foreman_hyperv.assets.precompile' do |app|
         | 
| 13 | 
            +
                  app.config.assets.precompile += %w(compute_resources/hyperv/base.js)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                config.to_prepare do
         | 
| 17 | 
            +
                  require 'fog/hyperv'
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  require 'fog/hyperv/models/compute/server'
         | 
| 20 | 
            +
                  require File.expand_path(
         | 
| 21 | 
            +
                    '../../../app/models/concerns/fog_extensions/hyperv/server', __FILE__)
         | 
| 22 | 
            +
                  Fog::Compute::Hyperv::Server.send(:include, FogExtensions::Hyperv::Server)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  require 'fog/hyperv/models/compute/network_adapter'
         | 
| 25 | 
            +
                  require File.expand_path(
         | 
| 26 | 
            +
                    '../../../app/models/concerns/fog_extensions/hyperv/network_adapter', __FILE__)
         | 
| 27 | 
            +
                  Fog::Compute::Hyperv::NetworkAdapter.send(:include, FogExtensions::Hyperv::NetworkAdapter)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  require 'fog/hyperv/models/compute/vhd'
         | 
| 30 | 
            +
                  require File.expand_path(
         | 
| 31 | 
            +
                    '../../../app/models/concerns/fog_extensions/hyperv/vhd', __FILE__)
         | 
| 32 | 
            +
                  Fog::Compute::Hyperv::Vhd.send(:include, FogExtensions::Hyperv::Vhd)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
    
        data/test/test_helper.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | @@ -0,0 +1,130 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: foreman_hyperv
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.1
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Alexander Olofsson
         | 
| 8 | 
            +
            autorequire: 
         | 
| 9 | 
            +
            bindir: bin
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2017-08-28 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: fog-hyperv
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: 0.0.1
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: 0.0.1
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: bundler
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '1.13'
         | 
| 34 | 
            +
              type: :development
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '1.13'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: rake
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '10.0'
         | 
| 48 | 
            +
              type: :development
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '10.0'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: minitest
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - "~>"
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '5.0'
         | 
| 62 | 
            +
              type: :development
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - "~>"
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '5.0'
         | 
| 69 | 
            +
            description: Hyper-V as a Compute Resource for Foreman
         | 
| 70 | 
            +
            email:
         | 
| 71 | 
            +
            - alexander.olofsson@liu.se
         | 
| 72 | 
            +
            executables: []
         | 
| 73 | 
            +
            extensions: []
         | 
| 74 | 
            +
            extra_rdoc_files: []
         | 
| 75 | 
            +
            files:
         | 
| 76 | 
            +
            - ".gitignore"
         | 
| 77 | 
            +
            - ".rubocop.yml"
         | 
| 78 | 
            +
            - ".rubocop_todo.yml"
         | 
| 79 | 
            +
            - ".travis.yml"
         | 
| 80 | 
            +
            - Gemfile
         | 
| 81 | 
            +
            - LICENSE.txt
         | 
| 82 | 
            +
            - README.md
         | 
| 83 | 
            +
            - Rakefile
         | 
| 84 | 
            +
            - app/assets/javascripts/compute_resources/hyperv/base.js
         | 
| 85 | 
            +
            - app/helpers/hyperv_helpers.rb
         | 
| 86 | 
            +
            - app/models/concerns/fog_extensions/hyperv/compute.rb
         | 
| 87 | 
            +
            - app/models/concerns/fog_extensions/hyperv/network_adapter.rb
         | 
| 88 | 
            +
            - app/models/concerns/fog_extensions/hyperv/server.rb
         | 
| 89 | 
            +
            - app/models/concerns/fog_extensions/hyperv/vhd.rb
         | 
| 90 | 
            +
            - app/models/foreman_hyperv/hyperv.rb
         | 
| 91 | 
            +
            - app/views/compute_resources/form/_hyperv.html.erb
         | 
| 92 | 
            +
            - app/views/compute_resources/show/_hyperv.html.erb
         | 
| 93 | 
            +
            - app/views/compute_resources_vms/form/hyperv/_base.html.erb
         | 
| 94 | 
            +
            - app/views/compute_resources_vms/form/hyperv/_network.html.erb
         | 
| 95 | 
            +
            - app/views/compute_resources_vms/form/hyperv/_volume.html.erb
         | 
| 96 | 
            +
            - app/views/compute_resources_vms/index/_hyperv.html.erb
         | 
| 97 | 
            +
            - app/views/compute_resources_vms/show/_hyperv.html.erb
         | 
| 98 | 
            +
            - foreman_hyperv.gemspec
         | 
| 99 | 
            +
            - lib/foreman_hyperv.rb
         | 
| 100 | 
            +
            - lib/foreman_hyperv/engine.rb
         | 
| 101 | 
            +
            - lib/foreman_hyperv/version.rb
         | 
| 102 | 
            +
            - test/foreman_hyperv_test.rb
         | 
| 103 | 
            +
            - test/test_helper.rb
         | 
| 104 | 
            +
            homepage: https://github.com/ace13/foreman_hyperv
         | 
| 105 | 
            +
            licenses:
         | 
| 106 | 
            +
            - MIT
         | 
| 107 | 
            +
            metadata: {}
         | 
| 108 | 
            +
            post_install_message: 
         | 
| 109 | 
            +
            rdoc_options: []
         | 
| 110 | 
            +
            require_paths:
         | 
| 111 | 
            +
            - lib
         | 
| 112 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 113 | 
            +
              requirements:
         | 
| 114 | 
            +
              - - ">="
         | 
| 115 | 
            +
                - !ruby/object:Gem::Version
         | 
| 116 | 
            +
                  version: '0'
         | 
| 117 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 118 | 
            +
              requirements:
         | 
| 119 | 
            +
              - - ">="
         | 
| 120 | 
            +
                - !ruby/object:Gem::Version
         | 
| 121 | 
            +
                  version: '0'
         | 
| 122 | 
            +
            requirements: []
         | 
| 123 | 
            +
            rubyforge_project: 
         | 
| 124 | 
            +
            rubygems_version: 2.6.12
         | 
| 125 | 
            +
            signing_key: 
         | 
| 126 | 
            +
            specification_version: 4
         | 
| 127 | 
            +
            summary: Hyper-V as a Compute Resource for Foreman
         | 
| 128 | 
            +
            test_files:
         | 
| 129 | 
            +
            - test/foreman_hyperv_test.rb
         | 
| 130 | 
            +
            - test/test_helper.rb
         |