foreman_fog_proxmox 0.13.1 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -14
  3. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_compute_resource.js +6 -8
  4. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm.js +59 -60
  5. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_server.js +2 -4
  6. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_volume.js +10 -10
  7. data/app/assets/javascripts/foreman_fog_proxmox/proxmox_volume_cloudinit.js +0 -1
  8. data/app/controllers/concerns/foreman_fog_proxmox/compute_resources_vms_controller.rb +80 -0
  9. data/app/controllers/concerns/foreman_fog_proxmox/hosts_controller.rb +53 -0
  10. data/app/helpers/proxmox_compute_resources_vms_helper.rb +99 -0
  11. data/app/helpers/proxmox_form_helper.rb +1 -1
  12. data/app/models/concerns/fog_extensions/proxmox/server.rb +3 -3
  13. data/app/models/concerns/host_ext/proxmox/associator.rb +46 -0
  14. data/app/models/concerns/host_ext/proxmox/for_vm.rb +33 -0
  15. data/app/models/concerns/orchestration/proxmox/compute.rb +18 -8
  16. data/app/models/foreman_fog_proxmox/proxmox.rb +4 -0
  17. data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +2 -6
  18. data/app/models/foreman_fog_proxmox/proxmox_images.rb +13 -4
  19. data/app/models/foreman_fog_proxmox/proxmox_interfaces.rb +14 -12
  20. data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +4 -2
  21. data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +2 -4
  22. data/app/models/foreman_fog_proxmox/proxmox_vm_queries.rb +6 -1
  23. data/app/models/foreman_fog_proxmox/vms.rb +1 -1
  24. data/app/overrides/compute_resources_vms/form/add_clone_to_new_vm_compute_detail.rb +1 -1
  25. data/app/services/concerns/foreman_fog_proxmox/compute_resource_host_associator.rb +34 -0
  26. data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_compute_form.html.erb +2 -2
  27. data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_hosts_compute_detail_form.html.erb +4 -2
  28. data/app/views/compute_resources_vms/form/proxmox/_base.html.erb +0 -1
  29. data/app/views/compute_resources_vms/form/proxmox/container/_network.html.erb +1 -1
  30. data/app/views/compute_resources_vms/form/proxmox/server/_network.html.erb +2 -2
  31. data/app/views/compute_resources_vms/index/_proxmox.html.erb +2 -2
  32. data/lib/foreman_fog_proxmox/engine.rb +7 -1
  33. data/lib/foreman_fog_proxmox/version.rb +1 -1
  34. data/test/unit/foreman_fog_proxmox/proxmox_images_test.rb +3 -3
  35. data/test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb +40 -38
  36. metadata +9 -3
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Tristan Robert
4
+
5
+ # This file is part of ForemanFogProxmox.
6
+
7
+ # ForemanFogProxmox is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+
12
+ # ForemanFogProxmox is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ module ForemanFogProxmox
21
+ module HostsController
22
+ extend ActiveSupport::Concern
23
+ included do
24
+ prepend Overrides
25
+ end
26
+ module Overrides
27
+ include ForemanFogProxmox::ProxmoxVmNew
28
+ # Clone the host
29
+ def clone
30
+ super
31
+ return true unless @host.compute_resource.class == ForemanFogProxmox::Proxmox
32
+
33
+ @host.compute_attributes[:vmid] = next_vmid
34
+ @host.compute_attributes[:interfaces_attributes].each { |index, interface_attributes| @host.compute_attributes[:interfaces_attributes][index] = interface_attributes.merge(macaddr: nil).merge(hwaddr: nil).merge(ip: nil).merge(ip6: nil) }
35
+ @host.compute_attributes[:volumes_attributes].each { |index, volume_attributes| @host.compute_attributes[:volumes_attributes][index] = volume_attributes.merge(volid: nil) }
36
+ end
37
+
38
+ private
39
+
40
+ def bridges
41
+ @host.compute_resource.bridges
42
+ end
43
+
44
+ def nodes
45
+ @host.compute_resource.nodes
46
+ end
47
+
48
+ def storages
49
+ @host.compute_resource.storages
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Tristan Robert
4
+
5
+ # This file is part of ForemanFogProxmox.
6
+
7
+ # ForemanFogProxmox is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+
12
+ # ForemanFogProxmox is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ module ProxmoxComputeResourcesVmsHelper
21
+ def proxmox_vm_id(compute_resource, vm)
22
+ id = vm.identity
23
+ id = vm.unique_cluster_identity(compute_resource) if compute_resource.class == ForemanFogProxmox::Proxmox
24
+ id
25
+ end
26
+
27
+ def vm_host_action(vm)
28
+ host = Host.for_vm_uuid(@compute_resource, vm).first
29
+ return unless host
30
+
31
+ display_link_if_authorized(_("Host"), hash_for_host_path(:id => host), :class => 'btn btn-default')
32
+ end
33
+
34
+ def vm_power_action(vm, authorizer = nil)
35
+ opts = hash_for_power_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => proxmox_vm_id(@compute_resource, vm)).merge(:auth_object => @compute_resource, :permission => 'power_compute_resources_vms', :authorizer => authorizer)
36
+ html = power_action_html(vm)
37
+
38
+ display_link_if_authorized "Power #{action_string(vm)}", opts, html.merge(:method => :put)
39
+ end
40
+
41
+ def vm_associate_action(vm)
42
+ display_link_if_authorized(
43
+ _('Associate VM'),
44
+ hash_for_associate_compute_resource_vm_path(
45
+ :compute_resource_id => @compute_resource,
46
+ :id => proxmox_vm_id(@compute_resource, vm)
47
+ ).merge(
48
+ :auth_object => @compute_resource,
49
+ :permission => 'edit_compute_resources'),
50
+ :title => _('Associate VM to a Foreman host'),
51
+ :method => :put,
52
+ :class => 'btn btn-default'
53
+ )
54
+ end
55
+
56
+ def vm_import_action(vm, html_options = {})
57
+ @_linked_hosts_cache ||= Host.where(:compute_resource_id => @compute_resource.id).pluck(:uuid)
58
+ return if @_linked_hosts_cache.include?(proxmox_vm_id(@compute_resource, vm).to_s)
59
+
60
+ import_managed_link = display_link_if_authorized(
61
+ _('Import as managed Host'),
62
+ hash_for_import_compute_resource_vm_path(
63
+ :compute_resource_id => @compute_resource,
64
+ :id => proxmox_vm_id(@compute_resource, vm),
65
+ :type => 'managed'),
66
+ html_options
67
+ )
68
+ import_unmanaged_link = display_link_if_authorized(
69
+ _('Import as unmanaged Host'),
70
+ hash_for_import_compute_resource_vm_path(
71
+ :compute_resource_id => @compute_resource,
72
+ :id => proxmox_vm_id(@compute_resource, vm),
73
+ :type => 'unmanaged'),
74
+ html_options
75
+ )
76
+
77
+ import_managed_link + import_unmanaged_link
78
+ end
79
+
80
+ def vm_console_action(vm)
81
+ return unless vm.ready?
82
+
83
+ link_to_if_authorized(
84
+ _('Console'),
85
+ hash_for_console_compute_resource_vm_path.merge(
86
+ :auth_object => @compute_resource,
87
+ :id => proxmox_vm_id(@compute_resource, vm)
88
+ ),
89
+ {
90
+ :id => 'console-button',
91
+ :class => 'btn btn-info'
92
+ }
93
+ )
94
+ end
95
+
96
+ def vm_delete_action(vm, authorizer = nil)
97
+ display_delete_if_authorized(hash_for_compute_resource_vm_path(:compute_resource_id => @compute_resource, :id => proxmox_vm_id(@compute_resource, vm)).merge(:auth_object => @compute_resource, :authorizer => authorizer), :class => 'btn btn-danger')
98
+ end
99
+ end
@@ -66,7 +66,7 @@ module ProxmoxFormHelper
66
66
  opts[:"data-association"] = (type + '_' + association.to_s).to_sym
67
67
  hide = ''
68
68
  hide += '$("[data-association=' + type + '_volumes]").hide();' unless ['hard_disk', 'mp'].include?(type)
69
- link_to_function(name.to_s, 'add_child_node(this);tfm.numFields.initAll();' + hide, opts)
69
+ link_to_function(name.to_s, 'add_child_node(this);' + hide, opts)
70
70
  end
71
71
 
72
72
  def remove_child_link_typed(name, f, type, opts = {})
@@ -23,8 +23,8 @@ module FogExtensions
23
23
  extend ActiveSupport::Concern
24
24
  attr_accessor :image_id, :templated, :ostemplate_storage, :ostemplate_file, :password, :start_after_create
25
25
 
26
- def unique_cluster_identity
27
- compute_resource.name + '_' + identity
26
+ def unique_cluster_identity(compute_resource)
27
+ compute_resource.id.to_s + '_' + identity
28
28
  end
29
29
 
30
30
  def start
@@ -63,7 +63,7 @@ module FogExtensions
63
63
  end
64
64
 
65
65
  def select_nic(fog_nics, nic)
66
- fog_nics.find { |fog_nic| fog_nic.identity.to_s == nic.identifier }
66
+ fog_nics.find { |fog_nic| fog_nic.identity.to_s == nic.compute_attributes[:id] }
67
67
  end
68
68
 
69
69
  delegate :interfaces, to: :config
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Tristan Robert
4
+
5
+ # This file is part of ForemanFogProxmox.
6
+
7
+ # ForemanFogProxmox is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+
12
+ # ForemanFogProxmox is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ module HostExt
21
+ module Proxmox
22
+ module Associator
23
+ extend ActiveSupport::Concern
24
+ included do
25
+ prepend Overrides
26
+ end
27
+ module Overrides
28
+ def associate!(cr, vm)
29
+ self.uuid = proxmox_vm_id(cr, vm)
30
+ self.compute_resource_id = cr.id
31
+ save!(:validate => false) # don't want to trigger callbacks
32
+ end
33
+
34
+ def proxmox_vm_id(compute_resource, vm)
35
+ id = vm.identity
36
+ id = vm.unique_cluster_identity(compute_resource) if compute_resource.class == ForemanFogProxmox::Proxmox
37
+ id
38
+ end
39
+ end
40
+
41
+ def for_vm_uuid(cr, vm)
42
+ where(:compute_resource_id => cr.id, :uuid => Array.wrap(vm).compact.map(cr.id.to_s + '_' + vm&.identity).map(&:to_s))
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2021 Tristan Robert
4
+
5
+ # This file is part of ForemanFogProxmox.
6
+
7
+ # ForemanFogProxmox is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+
12
+ # ForemanFogProxmox is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ module HostExt
21
+ module Proxmox
22
+ module ForVm
23
+ extend ActiveSupport::Concern
24
+ module ClassMethods
25
+ def for_vm_uuid(cr, vm)
26
+ uuid = vm&.identity
27
+ uuid = cr.id.to_s + '_' + vm&.identity if cr.class == ForemanFogProxmox::Proxmox
28
+ where(:compute_resource_id => cr.id, :uuid => uuid)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -23,18 +23,26 @@ module Orchestration
23
23
  extend ActiveSupport::Concern
24
24
 
25
25
  def setComputeUpdate
26
- logger.info "Update Proxmox Compute instance for #{name}"
27
- final_compute_attributes = compute_attributes.merge(compute_resource.host_compute_attrs(self))
28
- logger.debug("setComputeUpdate: final_compute_attributes=#{final_compute_attributes}")
29
- compute_resource.save_vm uuid, final_compute_attributes
26
+ if compute_resource.class != ForemanFogProxmox::Proxmox
27
+ super
28
+ else
29
+ logger.info "Update Proxmox Compute instance for #{name}"
30
+ final_compute_attributes = compute_attributes.merge(compute_resource.host_compute_attrs(self))
31
+ logger.debug("setComputeUpdate: final_compute_attributes=#{final_compute_attributes}")
32
+ compute_resource.save_vm uuid, final_compute_attributes
33
+ end
30
34
  rescue StandardError => e
31
35
  failure format(_('Failed to update a compute %<compute_resource>s instance %<name>s: %<e>s'), :compute_resource => compute_resource, :name => name, :e => e), e
32
36
  end
33
37
 
34
38
  def delComputeUpdate
35
- logger.info "Undo Update Proxmox Compute instance for #{name}"
36
- final_compute_attributes = old.compute_attributes.merge(compute_resource.host_compute_attrs(old))
37
- compute_resource.save_vm uuid, final_compute_attributes
39
+ if compute_resource.class != ForemanFogProxmox::Proxmox
40
+ super
41
+ else
42
+ logger.info "Undo Update Proxmox Compute instance for #{name}"
43
+ final_compute_attributes = old.compute_attributes.merge(compute_resource.host_compute_attrs(old))
44
+ compute_resource.save_vm uuid, final_compute_attributes
45
+ end
38
46
  rescue StandardError => e
39
47
  failure format(_('Failed to undo update compute %<compute_resource>s instance %<name>s: %<e>s'), :compute_resource => compute_resource, :name => name, :e => e), e
40
48
  end
@@ -80,7 +88,9 @@ module Orchestration
80
88
  end
81
89
 
82
90
  def setComputeDetails
83
- if vm
91
+ if compute_resource.class != ForemanFogProxmox::Proxmox
92
+ super
93
+ elsif vm
84
94
  setVmDetails
85
95
  else
86
96
  failure format(_('failed to save %<name>s'), name: name)
@@ -64,6 +64,10 @@ module ForemanFogProxmox
64
64
  associate_by('mac', vm.mac)
65
65
  end
66
66
 
67
+ def associate_by(name, attributes)
68
+ Host.authorized(:view_hosts, Host).joins(:primary_interface).where(:nics => { :primary => true }).where("nics.#{name}" => attributes).readonly(false).first
69
+ end
70
+
67
71
  def ssl_certs
68
72
  attrs[:ssl_certs]
69
73
  end
@@ -27,9 +27,7 @@ module ForemanFogProxmox
27
27
  host.compute_attributes['config_attributes'].store('hostname', host.name)
28
28
  when 'qemu'
29
29
  host.compute_attributes['config_attributes'].store('name', host.name)
30
- unless compute_os_types(host).include?(ostype)
31
- raise ::Foreman::Exception, format(_('Operating system family %<type>s is not consistent with %<ostype>s'), type: host.operatingsystem.type, ostype: ostype)
32
- end
30
+ raise ::Foreman::Exception, format(_('Operating system family %<type>s is not consistent with %<ostype>s'), type: host.operatingsystem.type, ostype: ostype) unless compute_os_types(host).include?(ostype)
33
31
  end
34
32
  super
35
33
  end
@@ -50,9 +48,7 @@ module ForemanFogProxmox
50
48
  vm_attrs = vm_attrs.merge(vmid: vm.identity, node_id: vm.node_id, type: vm.type)
51
49
  if vm.respond_to?(:config)
52
50
  vm_attrs[:volumes_attributes] = Hash[vm.config.disks.each_with_index.map { |disk, idx| [idx.to_s, disk.attributes] }] if vm.config.respond_to?(:disks)
53
- if vm.config.respond_to?(:interfaces)
54
- vm_attrs[:interfaces_attributes] = Hash[vm.config.interfaces.each_with_index.map { |interface, idx| [idx.to_s, interface_compute_attributes(interface.attributes)] }]
55
- end
51
+ vm_attrs[:interfaces_attributes] = Hash[vm.config.interfaces.each_with_index.map { |interface, idx| [idx.to_s, interface_compute_attributes(interface.attributes)] }] if vm.config.respond_to?(:interfaces)
56
52
  vm_attrs[:config_attributes] = vm.config.attributes.reject do |key, value|
57
53
  not_config_key?(vm, key) || ForemanFogProxmox::Value.empty?(value.to_s) || Fog::Proxmox::DiskHelper.disk?(key.to_s) || Fog::Proxmox::NicHelper.nic?(key.to_s)
58
54
  end
@@ -31,8 +31,17 @@ module ForemanFogProxmox
31
31
  storage.volumes.list_by_content_type(type).sort_by(&:volid) if storage
32
32
  end
33
33
 
34
+ def template_name(template)
35
+ image = find_vm_by_uuid(template_uuid(template))
36
+ image&.name
37
+ end
38
+
39
+ def template_uuid(template)
40
+ id.to_s + '_' + template.vmid.to_s
41
+ end
42
+
34
43
  def available_images
35
- templates.collect { |template| OpenStruct.new(id: template.vmid.to_s) }
44
+ templates.collect { |template| OpenStruct.new(id: template_uuid(template), name: template_name(template)) }
36
45
  end
37
46
 
38
47
  def templates
@@ -44,15 +53,15 @@ module ForemanFogProxmox
44
53
  volumes.select(&:template?)
45
54
  end
46
55
 
47
- def template(vmid)
48
- find_vm_by_uuid(vmid)
56
+ def template(uuid)
57
+ find_vm_by_uuid(uuid)
49
58
  end
50
59
 
51
60
  def clone_from_image(image_id, args, vmid)
52
61
  logger.debug(format(_('create_vm(): clone %<image_id>s in %<vmid>s'), image_id: image_id, vmid: vmid))
53
62
  image = find_vm_by_uuid(image_id)
54
63
  image.clone(vmid)
55
- clone = find_vm_by_uuid(vmid)
64
+ clone = find_vm_by_uuid(id.to_s + '_' + vmid.to_s)
56
65
  options = {}
57
66
  options.store(:name, args[:name]) unless clone.container?
58
67
  options.store(:hostname, args[:name]) if clone.container?
@@ -18,6 +18,7 @@
18
18
  # along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
  require 'fog/proxmox/helpers/ip_helper'
21
+ require 'net/validations'
21
22
 
22
23
  module ForemanFogProxmox
23
24
  module ProxmoxInterfaces
@@ -26,8 +27,10 @@ module ForemanFogProxmox
26
27
  end
27
28
 
28
29
  def set_nic_identifier(nic, index)
29
- nic.identifier = format('net%<index>s', index: index) if nic.identifier.empty?
30
- raise ::Foreman::Exception, _(format('Invalid identifier interface[%<index>s]. Must be net[n] with n integer >= 0', index: index)) unless Fog::Proxmox::NicHelper.nic?(nic.identifier)
30
+ nic.compute_attributes[:id] = format('net%<index>s', index: index) if nic.compute_attributes[:id].empty?
31
+ raise ::Foreman::Exception, _(format('Invalid proxmox NIC id on interface[%<index>s]. Must be net[n] with n integer >= 0', index: index)) unless Fog::Proxmox::NicHelper.nic?(nic.compute_attributes[:id])
32
+
33
+ nic.identifier = nic.compute_attributes['id'] if nic.identifier.empty?
31
34
  end
32
35
 
33
36
  def vm_type(host)
@@ -104,24 +107,23 @@ module ForemanFogProxmox
104
107
  def set_mac(nic_compute_attributes, mac, type)
105
108
  mac_attr_name = { 'qemu' => :macaddr, 'lxc' => :hwaddr }
106
109
  mac_key = mac_attr_name[type] || 'mac'
107
- nic_compute_attributes[mac_key] = mac
110
+ nic_compute_attributes[mac_key] = Net::Validations.normalize_mac(mac)
108
111
  end
109
112
 
110
113
  def host_interfaces_attrs(host)
111
114
  host.interfaces.select(&:physical?).each.with_index.reduce({}) do |hash, (nic, index)|
112
115
  set_nic_identifier(nic, index)
113
116
  set_container_interface_name(host, nic, index) if container?(host)
114
- nic_compute_attributes = nic.compute_attributes.merge(id: nic.identifier)
115
- ForemanFogProxmox::HashCollection.remove_empty_values(nic_compute_attributes)
117
+ ForemanFogProxmox::HashCollection.remove_empty_values(nic.compute_attributes)
116
118
  mac = nic.mac
117
119
  mac ||= nic.attributes['mac']
118
- set_mac(nic_compute_attributes, mac, vm_type(host)) if mac.present?
119
- interface_compute_attributes = host.compute_attributes['interfaces_attributes'] ? host.compute_attributes['interfaces_attributes'].select { |_k, v| v['id'] == nic.identifier } : {}
120
- nic_compute_attributes.store(:_delete, interface_compute_attributes[interface_compute_attributes.keys[0]]['_delete']) unless interface_compute_attributes.empty?
121
- set_ip(host, nic, nic_compute_attributes)
122
- set_ip(host, nic, nic_compute_attributes, true)
123
- ForemanFogProxmox::HashCollection.remove_keys(nic_compute_attributes, ['dhcp', 'dhcp6', 'cidr', 'cidr6'])
124
- hash.merge(index.to_s => nic_compute_attributes)
120
+ set_mac(nic.compute_attributes, mac, vm_type(host)) if mac.present?
121
+ interface_compute_attributes = host.compute_attributes['interfaces_attributes'] ? host.compute_attributes['interfaces_attributes'].select { |_k, v| v['id'] == nic.compute_attributes[:id] } : {}
122
+ nic.compute_attributes.store(:_delete, interface_compute_attributes[interface_compute_attributes.keys[0]]['_delete']) unless interface_compute_attributes.empty?
123
+ set_ip(host, nic, nic.compute_attributes)
124
+ set_ip(host, nic, nic.compute_attributes, true)
125
+ ForemanFogProxmox::HashCollection.remove_keys(nic.compute_attributes, ['dhcp', 'dhcp6', 'cidr', 'cidr6'])
126
+ hash.merge(index.to_s => nic.compute_attributes)
125
127
  end
126
128
  end
127
129
  end
@@ -56,8 +56,10 @@ module ForemanFogProxmox
56
56
 
57
57
  def destroy_vm(uuid)
58
58
  vm = find_vm_by_uuid(uuid)
59
- vm.stop if vm.ready?
60
- vm.destroy
59
+ unless vm.nil?
60
+ vm.stop if vm.ready?
61
+ vm.destroy
62
+ end
61
63
  rescue ActiveRecord::RecordNotFound
62
64
  # if the VM does not exists, we don't really care.
63
65
  true