foreman_fog_proxmox 0.8.0 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of foreman_fog_proxmox might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +11 -1
- data/Rakefile +3 -1
- data/app/controllers/concerns/foreman_fog_proxmox/controller/parameters/compute_resource.rb +2 -2
- data/app/controllers/foreman_fog_proxmox/compute_resources_controller.rb +2 -2
- data/app/helpers/node_dashboard_helper.rb +13 -14
- data/app/helpers/proxmox_compute_selectors_helper.rb +49 -50
- data/app/helpers/proxmox_container_helper.rb +42 -36
- data/app/helpers/proxmox_form_helper.rb +38 -40
- data/app/helpers/proxmox_server_helper.rb +39 -41
- data/app/helpers/proxmox_vm_helper.rb +21 -25
- data/app/models/concerns/fog_extensions/proxmox/disk.rb +8 -8
- data/app/models/concerns/fog_extensions/proxmox/interface.rb +8 -8
- data/app/models/concerns/fog_extensions/proxmox/node.rb +24 -22
- data/app/models/concerns/fog_extensions/proxmox/server.rb +71 -59
- data/app/models/concerns/fog_extensions/proxmox/server_config.rb +47 -39
- data/app/models/concerns/fog_extensions/proxmox/volume.rb +8 -8
- data/app/models/concerns/host_ext/proxmox/interfaces.rb +21 -13
- data/app/models/concerns/orchestration/proxmox/compute.rb +14 -10
- data/app/models/foreman_fog_proxmox/options_select.rb +14 -14
- data/app/models/foreman_fog_proxmox/proxmox.rb +30 -466
- data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +54 -0
- data/app/models/foreman_fog_proxmox/proxmox_connection.rb +67 -0
- data/app/models/foreman_fog_proxmox/proxmox_console.rb +41 -0
- data/app/models/foreman_fog_proxmox/proxmox_images.rb +53 -0
- data/app/models/foreman_fog_proxmox/proxmox_interfaces.rb +60 -0
- data/app/models/foreman_fog_proxmox/proxmox_operating_systems.rb +49 -0
- data/app/models/foreman_fog_proxmox/proxmox_token_expiration.rb +30 -0
- data/app/models/foreman_fog_proxmox/proxmox_version.rb +36 -0
- data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +108 -0
- data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +162 -0
- data/app/models/foreman_fog_proxmox/proxmox_vm_queries.rb +74 -0
- data/app/models/foreman_fog_proxmox/proxmox_volumes.rb +85 -0
- data/app/overrides/compute_resources_vms/form/add_clone_to_new_vm_compute_detail.rb +7 -6
- data/app/overrides/compute_resources_vms/form/add_from_profile_to_compute_attributes_form.rb +13 -11
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_networks_form.rb +13 -11
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_nic_provider_specific_form.rb +8 -7
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_volumes_edit.rb +7 -6
- data/app/overrides/compute_resources_vms/form/add_vm_type_to_volumes_new_volume.rb +7 -6
- data/app/overrides/compute_resources_vms/form/remove_new_vm_from_removable_layout.rb +7 -6
- data/app/services/foreman_fog_proxmox/node_dashboard/data.rb +16 -16
- data/app/views/api/v2/compute_resources/proxmox.json.rabl +3 -1
- data/app/views/compute_resources/form/_proxmox.html.erb +3 -0
- data/app/views/compute_resources/show/_proxmox.html.erb +8 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_compute_attributes_form.html.erb +5 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_compute_form.html.erb +6 -1
- data/app/views/compute_resources_vms/form/proxmox/_add_from_profile_to_hosts_compute_detail_form.html.erb +6 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_networks_form.html.erb +6 -2
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_networks_new_childs_form.html.erb +8 -2
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_nic_provider_specific_form.html.erb +6 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_volumes_edit.html.erb +15 -1
- data/app/views/compute_resources_vms/form/proxmox/_base.html.erb +2 -2
- data/app/views/compute_resources_vms/form/proxmox/_general.html.erb +1 -1
- data/app/views/compute_resources_vms/form/proxmox/_removable_layout.html.erb +6 -1
- data/app/views/compute_resources_vms/form/proxmox/container/_extended.html.erb +1 -1
- data/app/views/compute_resources_vms/form/proxmox/container/_volume_mp.html.erb +1 -1
- data/app/views/compute_resources_vms/form/proxmox/server/_config.html.erb +1 -1
- data/app/views/compute_resources_vms/form/proxmox/server/_volume.html.erb +2 -2
- data/config/routes.rb +4 -4
- data/lib/foreman_fog_proxmox/engine.rb +14 -14
- data/lib/foreman_fog_proxmox/semver.rb +78 -78
- data/lib/foreman_fog_proxmox/value.rb +5 -3
- data/lib/foreman_fog_proxmox/version.rb +1 -1
- data/lib/tasks/foreman_fog_proxmox_tasks.rake +3 -13
- data/locale/en/foreman_fog_proxmox.edit.po +472 -0
- data/locale/en/foreman_fog_proxmox.po +48 -24
- data/locale/en/foreman_fog_proxmox.po.time_stamp +0 -0
- data/locale/foreman_fog_proxmox.pot +140 -102
- data/locale/fr/foreman_fog_proxmox.edit.po +472 -0
- data/locale/fr/foreman_fog_proxmox.po +52 -28
- data/locale/fr/foreman_fog_proxmox.po.time_stamp +0 -0
- data/locale/gemspec.rb +2 -0
- data/test/{unit/foreman_fog_proxmox/proxmox_test_helpers.rb → factories/foreman_fog_proxmox/proxmox_container_mock_factory.rb} +4 -140
- data/test/factories/foreman_fog_proxmox/proxmox_node_mock_factory.rb +61 -0
- data/test/factories/foreman_fog_proxmox/proxmox_server_mock_factory.rb +134 -0
- data/test/factories/proxmox_factory.rb +15 -15
- data/test/functional/compute_resources_controller_test.rb +12 -10
- data/test/test_plugin_helper.rb +2 -0
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_container_helper_test.rb +178 -182
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_server_helper_test.rb +122 -126
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_vm_helper_test.rb +180 -187
- data/test/unit/foreman_fog_proxmox/proxmox_compute_attributes_test.rb +116 -0
- data/test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb +71 -0
- data/test/unit/foreman_fog_proxmox/proxmox_test.rb +9 -479
- data/test/unit/foreman_fog_proxmox/proxmox_version_test.rb +82 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_container_test.rb +207 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_create_test.rb +92 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_update_test.rb +324 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_test.rb +43 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_new_test.rb +71 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_queries_test.rb +63 -0
- data/test/unit/foreman_fog_proxmox/semver_test.rb +67 -53
- metadata +52 -14
@@ -20,44 +20,52 @@
|
|
20
20
|
require 'fog/proxmox/helpers/cpu_helper'
|
21
21
|
|
22
22
|
module FogExtensions
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
disks.cdrom ? disks.cdrom.storage : ''
|
44
|
-
end
|
45
|
-
def cdrom_iso
|
46
|
-
disks.cdrom ? disks.cdrom.volid : ''
|
47
|
-
end
|
48
|
-
def cdrom_image
|
49
|
-
if disks.cdrom
|
50
|
-
%w[none cdrom].include?(disks.cdrom.volid) ? disks.cdrom.volid : 'image'
|
51
|
-
else
|
52
|
-
'none'
|
53
|
-
end
|
54
|
-
end
|
55
|
-
def rootfs_storage
|
56
|
-
disks.rootfs.storage if disks.rootfs
|
57
|
-
end
|
58
|
-
def rootfs_file
|
59
|
-
disks.rootfs.volid if disks.rootfs
|
60
|
-
end
|
23
|
+
module Proxmox
|
24
|
+
module ServerConfig
|
25
|
+
extend ActiveSupport::Concern
|
26
|
+
def cpu_type
|
27
|
+
Fog::Proxmox::CpuHelper.extract_type(cpu)
|
28
|
+
end
|
29
|
+
|
30
|
+
def spectre
|
31
|
+
Fog::Proxmox::CpuHelper.has_spectre?(cpu)
|
32
|
+
end
|
33
|
+
|
34
|
+
def pcid
|
35
|
+
Fog::Proxmox::CpuHelper.has_pcid?(cpu)
|
36
|
+
end
|
37
|
+
|
38
|
+
def cdrom
|
39
|
+
if disks.cdrom
|
40
|
+
['none', 'cdrom'].include?(disks.cdrom.volid) ? disks.cdrom.volid : 'image'
|
41
|
+
else
|
42
|
+
'none'
|
61
43
|
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def cdrom_storage
|
47
|
+
disks.cdrom ? disks.cdrom.storage : ''
|
48
|
+
end
|
49
|
+
|
50
|
+
def cdrom_iso
|
51
|
+
disks.cdrom ? disks.cdrom.volid : ''
|
52
|
+
end
|
53
|
+
|
54
|
+
def cdrom_image
|
55
|
+
if disks.cdrom
|
56
|
+
['none', 'cdrom'].include?(disks.cdrom.volid) ? disks.cdrom.volid : 'image'
|
57
|
+
else
|
58
|
+
'none'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def rootfs_storage
|
63
|
+
disks.rootfs&.storage
|
64
|
+
end
|
65
|
+
|
66
|
+
def rootfs_file
|
67
|
+
disks.rootfs&.volid
|
68
|
+
end
|
62
69
|
end
|
63
|
-
end
|
70
|
+
end
|
71
|
+
end
|
@@ -18,12 +18,12 @@
|
|
18
18
|
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
20
|
module FogExtensions
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
21
|
+
module Proxmox
|
22
|
+
module Volume
|
23
|
+
extend ActiveSupport::Concern
|
24
|
+
def templated?
|
25
|
+
volid ? volid.match(/^([\w-]+)[:]base-(\d+)-disk-(\d+)/) : false
|
26
|
+
end
|
28
27
|
end
|
29
|
-
end
|
28
|
+
end
|
29
|
+
end
|
@@ -17,21 +17,29 @@
|
|
17
17
|
# You should have received a copy of the GNU General Public License
|
18
18
|
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
|
-
module HostExt
|
21
|
-
|
22
|
-
|
20
|
+
module HostExt
|
21
|
+
module Proxmox
|
22
|
+
module Interfaces
|
23
|
+
extend ActiveSupport::Concern
|
24
|
+
def update(attributes = {})
|
23
25
|
add_interfaces_to_compute_attributes(attributes)
|
24
26
|
super(attributes)
|
25
|
-
|
26
|
-
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_interfaces_to_compute_attributes(attributes)
|
27
30
|
attributes['compute_attributes']['interfaces_attributes'] = {}
|
28
|
-
attributes['interfaces_attributes'].each
|
29
|
-
|
30
|
-
|
31
|
+
attributes['interfaces_attributes'].each do |index, interface_attributes|
|
32
|
+
add_interface_to_compute_attributes(index, interface_attributes, attributes['compute_attributes']['interfaces_attributes'])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_interface_to_compute_attributes(index, interface_attributes, compute_attributes)
|
31
37
|
compute_attributes[index] = {}
|
32
|
-
compute_attributes[index].store('id',interface_attributes['identifier'])
|
33
|
-
compute_attributes[index].store('_delete',interface_attributes['_destroy'])
|
34
|
-
compute_attributes[index].store('macaddr',interface_attributes['mac'])
|
35
|
-
compute_attributes[index].merge!(interface_attributes['compute_attributes'].reject { |k,_v| k == 'id' })
|
38
|
+
compute_attributes[index].store('id', interface_attributes['identifier'])
|
39
|
+
compute_attributes[index].store('_delete', interface_attributes['_destroy'])
|
40
|
+
compute_attributes[index].store('macaddr', interface_attributes['mac'])
|
41
|
+
compute_attributes[index].merge!(interface_attributes['compute_attributes'].reject { |k, _v| k == 'id' })
|
42
|
+
end
|
36
43
|
end
|
37
|
-
end
|
44
|
+
end
|
45
|
+
end
|
@@ -17,22 +17,26 @@
|
|
17
17
|
# You should have received a copy of the GNU General Public License
|
18
18
|
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
|
-
module Orchestration
|
21
|
-
|
20
|
+
module Orchestration
|
21
|
+
module Proxmox
|
22
|
+
module Compute
|
23
|
+
extend ActiveSupport::Concern
|
22
24
|
|
23
|
-
|
25
|
+
def setComputeUpdate
|
24
26
|
logger.info "Update Proxmox Compute instance for #{name}"
|
25
27
|
final_compute_attributes = compute_attributes.merge(compute_resource.host_compute_attrs(self))
|
26
28
|
compute_resource.save_vm uuid, final_compute_attributes
|
27
|
-
|
28
|
-
failure _(
|
29
|
-
|
29
|
+
rescue StandardError => e
|
30
|
+
failure format(_('Failed to update a compute %<compute_resource>s instance %<name>s: %<e>s'), :compute_resource => compute_resource, :name => name, :e => e), e
|
31
|
+
end
|
30
32
|
|
31
|
-
|
33
|
+
def delComputeUpdate
|
32
34
|
logger.info "Undo Update Proxmox Compute instance for #{name}"
|
33
35
|
final_compute_attributes = old.compute_attributes.merge(compute_resource.host_compute_attrs(old))
|
34
36
|
compute_resource.save_vm uuid, final_compute_attributes
|
35
|
-
|
36
|
-
failure _(
|
37
|
+
rescue StandardError => e
|
38
|
+
failure format(_('Failed to undo update compute %<compute_resource>s instance %<name>s: %<e>s'), :compute_resource => compute_resource, :name => name, :e => e), e
|
39
|
+
end
|
37
40
|
end
|
38
|
-
end
|
41
|
+
end
|
42
|
+
end
|
@@ -18,19 +18,19 @@
|
|
18
18
|
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
20
|
module ForemanFogProxmox
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
21
|
+
class OptionsSelect
|
22
|
+
attr_accessor :id
|
23
|
+
attr_accessor :name
|
24
|
+
attr_accessor :range
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
id
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(args = {})
|
31
|
+
@id = args[:id]
|
32
|
+
@name = args[:name]
|
33
|
+
@range = args[:range]
|
35
34
|
end
|
35
|
+
end
|
36
36
|
end
|
@@ -17,10 +17,8 @@
|
|
17
17
|
# You should have received a copy of the GNU General Public License
|
18
18
|
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
19
19
|
|
20
|
-
require 'fog/proxmox'
|
21
20
|
require 'fog/proxmox/helpers/nic_helper'
|
22
21
|
require 'fog/proxmox/helpers/disk_helper'
|
23
|
-
require 'foreman_fog_proxmox/semver'
|
24
22
|
require 'foreman_fog_proxmox/value'
|
25
23
|
|
26
24
|
module ForemanFogProxmox
|
@@ -28,6 +26,18 @@ module ForemanFogProxmox
|
|
28
26
|
include ProxmoxVmHelper
|
29
27
|
include ProxmoxServerHelper
|
30
28
|
include ProxmoxContainerHelper
|
29
|
+
include ProxmoxConnection
|
30
|
+
include ProxmoxTokenExpiration
|
31
|
+
include ProxmoxVmNew
|
32
|
+
include ProxmoxVmCommands
|
33
|
+
include ProxmoxVmQueries
|
34
|
+
include ProxmoxComputeAttributes
|
35
|
+
include ProxmoxVolumes
|
36
|
+
include ProxmoxInterfaces
|
37
|
+
include ProxmoxImages
|
38
|
+
include ProxmoxOperatingSystems
|
39
|
+
include ProxmoxVersion
|
40
|
+
include ProxmoxConsole
|
31
41
|
validates :url, :format => { :with => URI::DEFAULT_PARSER.make_regexp }, :presence => true
|
32
42
|
validates :user, :format => { :with => /(\w+)[@]{1}(\w+)/ }, :presence => true
|
33
43
|
validates :password, :presence => true
|
@@ -36,12 +46,12 @@ module ForemanFogProxmox
|
|
36
46
|
|
37
47
|
def provided_attributes
|
38
48
|
super.merge(
|
39
|
-
:mac
|
49
|
+
:mac => :mac
|
40
50
|
)
|
41
51
|
end
|
42
|
-
|
52
|
+
|
43
53
|
def self.provider_friendly_name
|
44
|
-
|
54
|
+
'Proxmox'
|
45
55
|
end
|
46
56
|
|
47
57
|
def capabilities
|
@@ -52,417 +62,62 @@ module ForemanFogProxmox
|
|
52
62
|
ComputeResource.model_name
|
53
63
|
end
|
54
64
|
|
55
|
-
def credentials_valid?
|
56
|
-
errors[:url].empty? && errors[:user].empty? && errors[:user].include?('@') && errors[:password].empty? && errors[:node_id].empty?
|
57
|
-
end
|
58
|
-
|
59
|
-
def version_suitable?
|
60
|
-
logger.debug(_("Proxmox compute resource version is %{version}") % { version: version })
|
61
|
-
raise ::Foreman::Exception.new(_("Proxmox version %{version} is not semver suitable") % { version: version }) unless ForemanFogProxmox::Semver.is_semver?(version)
|
62
|
-
ForemanFogProxmox::Semver.to_semver(version) >= ForemanFogProxmox::Semver.to_semver("5.3.0") && ForemanFogProxmox::Semver.to_semver(version) < ForemanFogProxmox::Semver.to_semver("5.5.0")
|
63
|
-
end
|
64
|
-
|
65
|
-
def test_connection(options = {})
|
66
|
-
super
|
67
|
-
credentials_valid?
|
68
|
-
version_suitable?
|
69
|
-
rescue => e
|
70
|
-
errors[:base] << e.message
|
71
|
-
if e.message.include?('SSL')
|
72
|
-
errors[:ssl_certs] << e.message
|
73
|
-
else
|
74
|
-
errors[:url] << e.message
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def nodes
|
79
|
-
nodes = client.nodes.all if client
|
80
|
-
nodes.sort_by(&:node) if nodes
|
81
|
-
end
|
82
|
-
|
83
|
-
def pools
|
84
|
-
pools = identity_client.pools.all
|
85
|
-
pools.sort_by(&:poolid)
|
86
|
-
end
|
87
|
-
|
88
|
-
def storages(type = 'images')
|
89
|
-
storages = node.storages.list_by_content_type type
|
90
|
-
storages.sort_by(&:storage)
|
91
|
-
end
|
92
|
-
|
93
|
-
def images_by_storage(type = 'iso', storage_id)
|
94
|
-
storage = node.storages.get storage_id if storage_id
|
95
|
-
storage.volumes.list_by_content_type(type).sort_by(&:volid) if storage
|
96
|
-
end
|
97
|
-
|
98
65
|
def associated_host(vm)
|
99
66
|
associate_by('mac', vm.mac)
|
100
67
|
end
|
101
68
|
|
102
|
-
def
|
103
|
-
|
104
|
-
bridges = node.networks.all(type: 'any_bridge')
|
105
|
-
bridges.sort_by(&:iface)
|
106
|
-
end
|
107
|
-
|
108
|
-
def available_images
|
109
|
-
templates.collect { |template| OpenStruct.new(id: template.vmid) }
|
110
|
-
end
|
111
|
-
|
112
|
-
def templates
|
113
|
-
storage = storages.first
|
114
|
-
images = storage.volumes.list_by_content_type('images')
|
115
|
-
images.select { |image| image.templated? }
|
116
|
-
end
|
117
|
-
|
118
|
-
def template(vmid)
|
119
|
-
find_vm_by_uuid(vmid)
|
120
|
-
end
|
121
|
-
|
122
|
-
def host_compute_attrs(host)
|
123
|
-
super.tap do |attrs|
|
124
|
-
ostype = host.compute_attributes['config_attributes']['ostype']
|
125
|
-
type = host.compute_attributes['type']
|
126
|
-
case type
|
127
|
-
when 'lxc'
|
128
|
-
host.compute_attributes['config_attributes'].store('hostname',host.name)
|
129
|
-
when 'qemu'
|
130
|
-
raise ::Foreman::Exception.new(_("Operating system family %{type} is not consistent with %{ostype}") % { type: host.operatingsystem.type, ostype: ostype }) unless compute_os_types(host).include?(ostype)
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def host_interfaces_attrs(host)
|
136
|
-
host.interfaces.select(&:physical?).each.with_index.reduce({}) do |hash, (nic, index)|
|
137
|
-
# Set default interface identifier to net[n]
|
138
|
-
nic.identifier = "net%{index}" % {index: index} if nic.identifier.empty?
|
139
|
-
raise ::Foreman::Exception.new _("Invalid identifier interface[%{index}]. Must be net[n] with n integer >= 0" % { index: index }) unless Fog::Proxmox::NicHelper.nic?(nic.identifier)
|
140
|
-
# Set default container interface name to eth[n]
|
141
|
-
container = host.compute_attributes['type'] == 'lxc'
|
142
|
-
nic.compute_attributes['name'] = "eth%{index}" % {index: index} if container && nic.compute_attributes['name'].empty?
|
143
|
-
raise ::Foreman::Exception.new _("Invalid name interface[%{index}]. Must be eth[n] with n integer >= 0" % { index: index }) if container && !/^(eth)(\d+)$/.match?(nic.compute_attributes['name'])
|
144
|
-
nic_compute_attributes = nic.compute_attributes.merge(id: nic.identifier)
|
145
|
-
mac = nic.mac
|
146
|
-
mac = nic.attributes['mac'] unless mac
|
147
|
-
nic_compute_attributes.store(:macaddr, mac) if (mac && !mac.empty?)
|
148
|
-
interface_compute_attributes = host.compute_attributes['interfaces_attributes'].select { |_k,v| v['id'] == nic.identifier }
|
149
|
-
nic_compute_attributes.store(:_delete, interface_compute_attributes[interface_compute_attributes.keys[0]]['_delete']) unless interface_compute_attributes.empty?
|
150
|
-
nic_compute_attributes.store(:ip, nic.ip) if (nic.ip && !nic.ip.empty?)
|
151
|
-
nic_compute_attributes.store(:ip6, nic.ip6) if (nic.ip6 && !nic.ip6.empty?)
|
152
|
-
hash.merge(index.to_s => nic_compute_attributes)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def new_volume(attr = {})
|
157
|
-
type = attr['type']
|
158
|
-
type = 'qemu' unless type
|
159
|
-
case type
|
160
|
-
when 'lxc'
|
161
|
-
return new_volume_server(attr)
|
162
|
-
when 'qemu'
|
163
|
-
return new_volume_container(attr)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def new_volume_server(attr = {})
|
168
|
-
opts = volume_server_defaults.merge(attr.to_h).deep_symbolize_keys
|
169
|
-
opts[:size] = opts[:size].to_s
|
170
|
-
Fog::Proxmox::Compute::Disk.new(opts)
|
171
|
-
end
|
172
|
-
|
173
|
-
def new_volume_container(attr = {})
|
174
|
-
opts = volume_container_defaults.merge(attr.to_h).deep_symbolize_keys
|
175
|
-
opts[:size] = opts[:size].to_s
|
176
|
-
Fog::Proxmox::Compute::Disk.new(opts)
|
177
|
-
end
|
178
|
-
|
179
|
-
def new_interface(attr = {})
|
180
|
-
type = attr['type']
|
181
|
-
type = 'qemu' unless type
|
182
|
-
case type
|
183
|
-
when 'lxc'
|
184
|
-
return new_container_interface(attr)
|
185
|
-
when 'qemu'
|
186
|
-
return new_server_interface(attr)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def new_server_interface(attr = {})
|
191
|
-
logger.debug("new_server_interface")
|
192
|
-
opts = interface_server_defaults.merge(attr.to_h).deep_symbolize_keys
|
193
|
-
Fog::Proxmox::Compute::Interface.new(opts)
|
194
|
-
end
|
195
|
-
|
196
|
-
def new_container_interface(attr = {})
|
197
|
-
logger.debug("new_container_interface")
|
198
|
-
opts = interface_container_defaults.merge(attr.to_h).deep_symbolize_keys
|
199
|
-
Fog::Proxmox::Compute::Interface.new(opts)
|
200
|
-
end
|
201
|
-
|
202
|
-
def vm_compute_attributes(vm)
|
203
|
-
vm_attrs = {}
|
204
|
-
if vm.respond_to?(:config)
|
205
|
-
vm_attrs = vm_attrs.merge(vmid: vm.identity, node_id: vm.node_id, type: vm.type)
|
206
|
-
if vm.config.respond_to?(:disks)
|
207
|
-
vm_attrs[:volumes_attributes] = Hash[vm.config.disks.each_with_index.map { |disk, idx| [idx.to_s, disk.attributes] }]
|
208
|
-
end
|
209
|
-
if vm.config.respond_to?(:interfaces)
|
210
|
-
vm_attrs[:interfaces_attributes] = Hash[vm.config.interfaces.each_with_index.map { |interface, idx| [idx.to_s, interface.attributes] }]
|
211
|
-
end
|
212
|
-
vm_attrs[:config_attributes] = vm.config.attributes.reject { |key,value| [:disks, :interfaces, :vmid, :node_id, :node, :type].include?(key) || !vm.config.respond_to?(key) || ForemanFogProxmox::Value.empty?(value.to_s) || Fog::Proxmox::DiskHelper.disk?(key.to_s) || Fog::Proxmox::NicHelper.nic?(key.to_s) }
|
213
|
-
end
|
214
|
-
vm_attrs
|
215
|
-
end
|
216
|
-
|
217
|
-
def vms(opts = {})
|
218
|
-
node
|
219
|
-
end
|
220
|
-
|
221
|
-
def new_vm(new_attr = {})
|
222
|
-
new_attr = ActiveSupport::HashWithIndifferentAccess.new(new_attr)
|
223
|
-
type = new_attr['type']
|
224
|
-
type = 'qemu' unless type
|
225
|
-
case type
|
226
|
-
when 'lxc'
|
227
|
-
vm = new_container_vm(new_attr)
|
228
|
-
when 'qemu'
|
229
|
-
vm = new_server_vm(new_attr)
|
230
|
-
end
|
231
|
-
logger.debug(_("new_vm() vm.config=%{config}") % { config: vm.config.inspect })
|
232
|
-
vm
|
233
|
-
end
|
234
|
-
|
235
|
-
def new_container_vm(new_attr = {})
|
236
|
-
options = new_attr
|
237
|
-
options = options.merge(node_id: node_id).merge(type: 'lxc').merge(vmid: next_vmid)
|
238
|
-
options= vm_container_instance_defaults.merge(options) if new_attr.empty?
|
239
|
-
vm = node.containers.new(parse_container_vm(options).deep_symbolize_keys)
|
240
|
-
logger.debug(_("new_container_vm() vm.config=%{config}") % { config: vm.config.inspect })
|
241
|
-
vm
|
242
|
-
end
|
243
|
-
|
244
|
-
def new_server_vm(new_attr = {})
|
245
|
-
options = new_attr
|
246
|
-
options = options.merge(node_id: node_id).merge(type: 'qemu').merge(vmid: next_vmid)
|
247
|
-
options = vm_server_instance_defaults.merge(options) if new_attr.empty?
|
248
|
-
vm = node.servers.new(parse_server_vm(options).deep_symbolize_keys)
|
249
|
-
logger.debug(_("new_server_vm() vm.config=%{config}") % { config: vm.config.inspect })
|
250
|
-
vm
|
251
|
-
end
|
252
|
-
|
253
|
-
def create_vm(args = {})
|
254
|
-
vmid = args[:vmid].to_i
|
255
|
-
type = args[:type]
|
256
|
-
raise ::Foreman::Exception.new N_("invalid vmid=%{vmid}") % { vmid: vmid } unless node.servers.id_valid?(vmid)
|
257
|
-
image_id = args[:image_id]
|
258
|
-
if image_id
|
259
|
-
logger.debug(_("create_vm(): clone %{image_id} in %{vmid}") % { image_id: image_id, vmid: vmid })
|
260
|
-
image = node.servers.get image_id
|
261
|
-
image.clone(vmid)
|
262
|
-
clone = node.servers.get vmid
|
263
|
-
clone.update(name: args[:name])
|
264
|
-
else
|
265
|
-
convert_sizes(args)
|
266
|
-
remove_deletes(args)
|
267
|
-
case type
|
268
|
-
when 'qemu'
|
269
|
-
vm = node.servers.create(parse_server_vm(args))
|
270
|
-
when 'lxc'
|
271
|
-
hash = parse_container_vm(args)
|
272
|
-
hash = hash.merge(vmid: vmid)
|
273
|
-
vm = node.containers.create(hash.reject { |key,_value| %w[ostemplate_storage ostemplate_file].include? key })
|
274
|
-
end
|
275
|
-
end
|
276
|
-
rescue => e
|
277
|
-
logger.warn(_("failed to create vm: %{e}") % { e: e })
|
278
|
-
destroy_vm vm.id if vm
|
279
|
-
raise e
|
280
|
-
end
|
281
|
-
|
282
|
-
def find_vm_by_uuid(uuid)
|
283
|
-
begin
|
284
|
-
vm = node.servers.get(uuid)
|
285
|
-
rescue Fog::Errors::NotFound
|
286
|
-
vm = nil
|
287
|
-
rescue Fog::Errors::Error => e
|
288
|
-
Foreman::Logging.exception(_("Failed retrieving proxmox server vm by vmid=%{uuid}") % { vmid: uuid }, e)
|
289
|
-
raise(ActiveRecord::RecordNotFound)
|
290
|
-
end
|
291
|
-
begin
|
292
|
-
vm = node.containers.get(uuid) unless vm
|
293
|
-
rescue Fog::Errors::NotFound
|
294
|
-
vm = nil
|
295
|
-
rescue Fog::Errors::Error => e
|
296
|
-
Foreman::Logging.exception(_("Failed retrieving proxmox container vm by vmid=%{uuid}") % { vmid: uuid }, e)
|
297
|
-
raise(ActiveRecord::RecordNotFound)
|
298
|
-
end
|
299
|
-
vm
|
300
|
-
end
|
301
|
-
|
302
|
-
def supports_update?
|
303
|
-
true
|
304
|
-
end
|
305
|
-
|
306
|
-
def update_required?(old_attrs, new_attrs)
|
307
|
-
return true if super(old_attrs, new_attrs)
|
308
|
-
|
309
|
-
new_attrs[:interfaces_attributes].each do |key, interface|
|
310
|
-
return true if (interface[:id].blank? || interface[:_delete] == '1') && key != 'new_interfaces' #ignore the template
|
311
|
-
end if new_attrs[:interfaces_attributes]
|
312
|
-
|
313
|
-
new_attrs[:volumes_attributes].each do |key, volume|
|
314
|
-
return true if (volume[:id].blank? || volume[:_delete] == '1') && key != 'new_volumes' #ignore the template
|
315
|
-
end if new_attrs[:volumes_attributes]
|
316
|
-
|
317
|
-
false
|
318
|
-
end
|
319
|
-
|
320
|
-
def editable_network_interfaces?
|
321
|
-
true
|
322
|
-
end
|
323
|
-
|
324
|
-
def user_data_supported?
|
325
|
-
true
|
326
|
-
end
|
327
|
-
|
328
|
-
def image_exists?(image)
|
329
|
-
!find_vm_by_uuid(image).nil?
|
330
|
-
end
|
331
|
-
|
332
|
-
def save_volumes(vm, volumes_attributes)
|
333
|
-
if volumes_attributes
|
334
|
-
volumes_attributes.each_value do |volume_attributes|
|
335
|
-
id = volume_attributes['id']
|
336
|
-
disk = vm.config.disks.get(id)
|
337
|
-
delete = volume_attributes['_delete']
|
338
|
-
if disk
|
339
|
-
if delete == '1'
|
340
|
-
vm.detach(id)
|
341
|
-
device = Fog::Proxmox::DiskHelper.extract_device(id)
|
342
|
-
vm.detach('unused' + device.to_s)
|
343
|
-
else
|
344
|
-
diff_size = volume_attributes['size'].to_i - disk.size
|
345
|
-
raise ::Foreman::Exception.new(_("Unable to shrink %{id} size. Proxmox allows only increasing size.") % { id: id }) unless diff_size >= 0
|
346
|
-
if diff_size > 0
|
347
|
-
extension = '+' + (diff_size / GIGA).to_s + 'G'
|
348
|
-
vm.extend(id,extension)
|
349
|
-
elsif disk.storage != volume_attributes['storage']
|
350
|
-
vm.move(id,volume_attributes['storage'])
|
351
|
-
end
|
352
|
-
end
|
353
|
-
else
|
354
|
-
options = {}
|
355
|
-
options.store(:mp, volume_attributes['mp']) if vm.container?
|
356
|
-
disk_attributes = { id: id, storage: volume_attributes['storage'], size: (volume_attributes['size'].to_i / GIGA).to_s }
|
357
|
-
vm.attach(disk_attributes, options) unless delete == '1'
|
358
|
-
end
|
359
|
-
end
|
360
|
-
end
|
361
|
-
end
|
362
|
-
|
363
|
-
def save_vm(uuid, new_attributes)
|
364
|
-
vm = find_vm_by_uuid(uuid)
|
365
|
-
templated = new_attributes['templated']
|
366
|
-
if (templated == '1' && !vm.templated?)
|
367
|
-
vm.create_template
|
368
|
-
else
|
369
|
-
volumes_attributes = new_attributes['volumes_attributes']
|
370
|
-
save_volumes(vm, volumes_attributes)
|
371
|
-
parsed_attr = vm.container? ? parse_container_vm(new_attributes.merge(type: vm.type)) : parse_server_vm(new_attributes.merge(type: vm.type))
|
372
|
-
config_attributes = parsed_attr.reject { |key,_value| [:templated,:ostemplate,:ostemplate_file,:ostemplate_storage,:volumes_attributes].include? key.to_sym }
|
373
|
-
config_attributes = config_attributes.reject { |_key,value| ForemanFogProxmox::Value.empty?(value) }
|
374
|
-
cdrom_attributes = parsed_attr.select { |_key,value| Fog::Proxmox::DiskHelper.cdrom?(value.to_s) }
|
375
|
-
config_attributes = config_attributes.reject { |key,_value| Fog::Proxmox::DiskHelper.disk?(key) }
|
376
|
-
vm.update(config_attributes.merge(cdrom_attributes))
|
377
|
-
end
|
378
|
-
vm = find_vm_by_uuid(uuid)
|
379
|
-
end
|
380
|
-
|
381
|
-
def next_vmid
|
382
|
-
node.servers.next_id
|
383
|
-
end
|
384
|
-
|
385
|
-
def node_id
|
386
|
-
self.attrs[:node_id]
|
69
|
+
def node_id
|
70
|
+
attrs[:node_id]
|
387
71
|
end
|
388
72
|
|
389
73
|
def node_id=(value)
|
390
|
-
|
74
|
+
attrs[:node_id] = value
|
391
75
|
end
|
392
76
|
|
393
77
|
def node
|
394
78
|
client.nodes.get node_id
|
395
79
|
end
|
396
80
|
|
397
|
-
def ssl_certs
|
398
|
-
|
81
|
+
def ssl_certs
|
82
|
+
attrs[:ssl_certs]
|
399
83
|
end
|
400
84
|
|
401
85
|
def ssl_certs=(value)
|
402
|
-
|
86
|
+
attrs[:ssl_certs] = value
|
403
87
|
end
|
404
88
|
|
405
89
|
def certs_to_store
|
406
90
|
return if ssl_certs.blank?
|
91
|
+
|
407
92
|
store = OpenSSL::X509::Store.new
|
408
93
|
ssl_certs.split(/(?=-----BEGIN)/).each do |cert|
|
409
94
|
x509_cert = OpenSSL::X509::Certificate.new cert
|
410
95
|
store.add_cert x509_cert
|
411
96
|
end
|
412
97
|
store
|
413
|
-
rescue => e
|
98
|
+
rescue StandardError => e
|
414
99
|
logger.error(e)
|
415
|
-
raise ::Foreman::Exception
|
100
|
+
raise ::Foreman::Exception, N_('Unable to store X509 certificates')
|
416
101
|
end
|
417
102
|
|
418
103
|
def ssl_verify_peer
|
419
|
-
|
104
|
+
attrs[:ssl_verify_peer].blank? ? false : Foreman::Cast.to_bool(attrs[:ssl_verify_peer])
|
420
105
|
end
|
421
106
|
|
422
107
|
def ssl_verify_peer=(value)
|
423
|
-
|
108
|
+
attrs[:ssl_verify_peer] = value
|
424
109
|
end
|
425
110
|
|
426
|
-
def
|
427
|
-
|
428
|
-
opts.store(:ssl_verify_peer, ssl_verify_peer)
|
429
|
-
opts.store(:ssl_cert_store, certs_to_store) if Foreman::Cast.to_bool(ssl_verify_peer)
|
430
|
-
opts
|
111
|
+
def renew
|
112
|
+
attrs[:renew].blank? ? false : Foreman::Cast.to_bool(attrs[:renew])
|
431
113
|
end
|
432
114
|
|
433
|
-
def
|
434
|
-
|
435
|
-
options = {}
|
436
|
-
if vm.container?
|
437
|
-
type_console = 'vnc'
|
438
|
-
options.store(:console, type_console)
|
439
|
-
else
|
440
|
-
type_console = vm.config.type_console
|
441
|
-
end
|
442
|
-
options.store(:websocket, 1) if type_console == 'vnc'
|
443
|
-
begin
|
444
|
-
vnc_console = vm.start_console(options)
|
445
|
-
WsProxy.start(:host => host, :host_port => vnc_console['port'], :password => vnc_console['ticket']).merge(:name => vm.name, :type => type_console)
|
446
|
-
rescue => e
|
447
|
-
logger.error(e)
|
448
|
-
raise ::Foreman::Exception.new(_("%s console is not supported at this time") % type_console)
|
449
|
-
end
|
450
|
-
end
|
451
|
-
|
452
|
-
def version
|
453
|
-
v = identity_client.read_version
|
454
|
-
"#{v['version']}.#{v['release']}"
|
115
|
+
def renew=(value)
|
116
|
+
attrs[:renew] = value
|
455
117
|
end
|
456
118
|
|
457
119
|
private
|
458
120
|
|
459
|
-
def fog_credentials
|
460
|
-
{ pve_url: url,
|
461
|
-
pve_username: user,
|
462
|
-
pve_password: password,
|
463
|
-
connection_options: connection_options }
|
464
|
-
end
|
465
|
-
|
466
121
|
def client
|
467
122
|
@client ||= ::Fog::Proxmox::Compute.new(fog_credentials)
|
468
123
|
end
|
@@ -475,99 +130,8 @@ module ForemanFogProxmox
|
|
475
130
|
@network_client ||= ::Fog::Proxmox::Network.new(fog_credentials)
|
476
131
|
end
|
477
132
|
|
478
|
-
def disconnect
|
479
|
-
client.terminate if @client
|
480
|
-
@client = nil
|
481
|
-
identity_client.terminate if @identity_client
|
482
|
-
@identity_client = nil
|
483
|
-
network_client.terminate if @network_client
|
484
|
-
@network_client = nil
|
485
|
-
end
|
486
|
-
|
487
|
-
def vm_server_instance_defaults
|
488
|
-
ActiveSupport::HashWithIndifferentAccess.new(
|
489
|
-
name: "foreman_#{Time.now.to_i}",
|
490
|
-
vmid: next_vmid,
|
491
|
-
type: 'qemu',
|
492
|
-
node_id: node_id,
|
493
|
-
cores: 1,
|
494
|
-
sockets: 1,
|
495
|
-
kvm: 0,
|
496
|
-
vga: 'std',
|
497
|
-
memory: 512 * MEGA,
|
498
|
-
ostype: 'l26',
|
499
|
-
keyboard: 'en-us',
|
500
|
-
cpu: 'kvm64',
|
501
|
-
scsihw: 'virtio-scsi-pci',
|
502
|
-
ide2: "none,media=cdrom",
|
503
|
-
templated: 0).merge(Fog::Proxmox::DiskHelper.flatten(volume_server_defaults)).merge(Fog::Proxmox::DiskHelper.flatten(volume_container_defaults)).merge(Fog::Proxmox::NicHelper.flatten(interface_defaults))
|
504
|
-
end
|
505
|
-
|
506
|
-
def vm_container_instance_defaults
|
507
|
-
ActiveSupport::HashWithIndifferentAccess.new(
|
508
|
-
name: "foreman_#{Time.now.to_i}",
|
509
|
-
vmid: next_vmid,
|
510
|
-
type: 'lxc',
|
511
|
-
node_id: node_id,
|
512
|
-
memory: 512 * MEGA,
|
513
|
-
templated: 0).merge(Fog::Proxmox::DiskHelper.flatten(volume_container_defaults)).merge(Fog::Proxmox::DiskHelper.flatten(volume_server_defaults)).merge(Fog::Proxmox::NicHelper.flatten(interface_defaults))
|
514
|
-
end
|
515
|
-
|
516
|
-
def vm_instance_defaults
|
517
|
-
super.merge(vmid: next_vmid, node_id: node_id)
|
518
|
-
end
|
519
|
-
|
520
|
-
def volume_server_defaults(controller = 'scsi', device = 0)
|
521
|
-
id = "#{controller}#{device}"
|
522
|
-
{ id: id, storage: storages.first.identity.to_s, size: (8 * GIGA), options: { cache: 'none' } }
|
523
|
-
end
|
524
|
-
|
525
|
-
def volume_container_defaults(id='rootfs')
|
526
|
-
{ id: id, storage: storages.first.identity.to_s, size: (8 * GIGA), options: { } }
|
527
|
-
end
|
528
|
-
|
529
|
-
def interface_defaults(id = 'net0')
|
530
|
-
{ id: id, model: 'virtio', name: 'eth0', bridge: bridges.first.identity.to_s }
|
531
|
-
end
|
532
|
-
|
533
|
-
def interface_server_defaults(id = 'net0')
|
534
|
-
{ id: id, model: 'virtio', bridge: bridges.first.identity.to_s }
|
535
|
-
end
|
536
|
-
|
537
|
-
def interface_container_defaults(id = 'net0')
|
538
|
-
{ id: id, name: 'eth0', bridge: bridges.first.identity.to_s }
|
539
|
-
end
|
540
|
-
|
541
|
-
def compute_os_types(host)
|
542
|
-
os_linux_types_mapping(host).empty? ? os_windows_types_mapping(host) : os_linux_types_mapping(host)
|
543
|
-
end
|
544
|
-
|
545
|
-
def available_operating_systems
|
546
|
-
operating_systems = %w[other solaris]
|
547
|
-
operating_systems += available_linux_operating_systems
|
548
|
-
operating_systems += available_windows_operating_systems
|
549
|
-
operating_systems
|
550
|
-
end
|
551
|
-
|
552
|
-
def available_linux_operating_systems
|
553
|
-
%w[l24 l26 debian ubuntu centos fedora opensuse archlinux gentoo alpine]
|
554
|
-
end
|
555
|
-
|
556
|
-
def available_windows_operating_systems
|
557
|
-
%w[wxp w2k w2k3 w2k8 wvista win7 win8 win10]
|
558
|
-
end
|
559
|
-
|
560
|
-
def os_linux_types_mapping(host)
|
561
|
-
%w[Debian Redhat Suse Altlinux Archlinux CoreOs Gentoo].include?(host.operatingsystem.type) ? available_linux_operating_systems : []
|
562
|
-
end
|
563
|
-
|
564
|
-
def os_windows_types_mapping(host)
|
565
|
-
%w[Windows].include?(host.operatingsystem.type) ? available_windows_operating_systems : []
|
566
|
-
end
|
567
|
-
|
568
133
|
def host
|
569
134
|
URI.parse(url).host
|
570
135
|
end
|
571
|
-
|
572
136
|
end
|
573
137
|
end
|