foreman_fog_proxmox 0.13.1 → 0.14.0

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.
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