foreman_fog_proxmox 0.21.0 → 0.23.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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/foreman_fog_proxmox/proxmox_vm_container.js +36 -1
- data/app/controllers/foreman_fog_proxmox/compute_resources_controller.rb +34 -0
- data/app/helpers/proxmox_form_helper.rb +69 -0
- data/app/helpers/proxmox_vm_attrs_helper.rb +11 -3
- data/app/helpers/proxmox_vm_interfaces_helper.rb +21 -4
- data/app/helpers/proxmox_vm_volumes_helper.rb +29 -3
- data/app/models/concerns/fog_extensions/proxmox/server.rb +7 -1
- data/app/models/concerns/host_ext/proxmox/interfaces.rb +1 -2
- data/app/models/foreman_fog_proxmox/proxmox.rb +3 -1
- data/app/models/foreman_fog_proxmox/proxmox_compute_attributes.rb +26 -5
- data/app/models/foreman_fog_proxmox/proxmox_operating_systems.rb +13 -2
- data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +6 -6
- data/app/models/foreman_fog_proxmox/proxmox_vm_queries.rb +13 -3
- data/app/models/foreman_fog_proxmox/proxmox_volumes.rb +16 -6
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_nic_provider_specific_form.html.erb +5 -6
- data/app/views/compute_resources_vms/form/proxmox/container/_network.html.erb +12 -10
- data/app/views/compute_resources_vms/form/proxmox/server/_network.html.erb +1 -2
- data/app/views/compute_resources_vms/index/_proxmox.html.erb +1 -0
- data/lib/foreman_fog_proxmox/version.rb +1 -1
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_container_helper_test.rb +2 -2
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_server_helper_test.rb +4 -4
- data/test/unit/foreman_fog_proxmox/helpers/proxmox_vm_volumes_helper_test.rb +8 -0
- data/test/unit/foreman_fog_proxmox/proxmox_compute_attributes_test.rb +71 -4
- data/test/unit/foreman_fog_proxmox/proxmox_interfaces_test.rb +1 -1
- data/test/unit/foreman_fog_proxmox/proxmox_operating_systems_test.rb +48 -0
- data/test/unit/foreman_fog_proxmox/proxmox_test.rb +6 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_new_test.rb +44 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_queries_test.rb +67 -0
- data/webpack/components/ProxmoxComputeSelectors.js +5 -0
- data/webpack/components/ProxmoxContainer/MountPoint.js +10 -0
- data/webpack/components/ProxmoxContainer/ProxmoxContainerNetwork.js +5 -1
- data/webpack/components/ProxmoxContainer/ProxmoxContainerOptions.js +13 -1
- data/webpack/components/ProxmoxContainer/ProxmoxContainerStorage.js +6 -3
- data/webpack/components/ProxmoxContainer/components/NetworkInterface.js +9 -2
- data/webpack/components/ProxmoxServer/ProxmoxServerStorage.js +181 -32
- data/webpack/components/ProxmoxServer/components/HardDisk.js +86 -17
- data/webpack/components/ProxmoxVmType.js +84 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a437699869ae38137e94761791e2a01d741e9dd36f924c286bfaa9afc139f9e7
|
|
4
|
+
data.tar.gz: 5698645c6f2a3a3278959989e5214357263f3ba7c0091830d1f41205033582ea
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d29712272ab785a33e4bdc70f345b0da96ff22d020820bbefc27c14302c24c1207d198d6ec742562a4d30a84083b1e081b43bb6a855c432e5a67ce60ca8a5b9
|
|
7
|
+
data.tar.gz: 9f3c39bbeca9d7364f4ee92cef02cc6fc7c398692cbc12f03a7c581324a9c21ca65ef1af33fcc892b1da02e3378f3f7c214fad2fb79bded7cfb028d55f5e5827
|
|
@@ -21,4 +21,39 @@ function storageOstemplateSelected(item) {
|
|
|
21
21
|
var node_id = $('#host_compute_attributes_node_id').val();
|
|
22
22
|
if (node_id == undefined) node_id = $("#compute_attribute_vm_attrs_node_id").val();
|
|
23
23
|
updateOptions('ostemplates', 'compute_attributes_ostemplate', 'file', undefined, undefined, 'volid', node_id, storage);
|
|
24
|
-
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function setDisabled($el, disabled) {
|
|
27
|
+
if (!$el || !$el.length) return;
|
|
28
|
+
$el.prop('disabled', disabled);
|
|
29
|
+
$el.toggleClass('disabled', disabled);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function syncDhcpIP(item, suffix) {
|
|
33
|
+
var $dhcp = $(item);
|
|
34
|
+
var checked = $dhcp.is(':checked');
|
|
35
|
+
var $fieldset = $dhcp.closest('fieldset');
|
|
36
|
+
var $cidr = $fieldset.find('input.proxmox-cidr-' + suffix).first();
|
|
37
|
+
var $gw = $fieldset.find('input.proxmox-gw-' + suffix).first();
|
|
38
|
+
|
|
39
|
+
setDisabled($cidr, checked);
|
|
40
|
+
setDisabled($gw, checked);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function dhcpIPSelected(item, suffix) {
|
|
44
|
+
syncDhcpIP(item, suffix);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function syncAllProxmoxDhcpFields() {
|
|
48
|
+
$('input.proxmox-dhcp-ipv4').each(function() {
|
|
49
|
+
syncDhcpIP(this, 'ipv4');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
$('input.proxmox-dhcp-ipv6').each(function() {
|
|
53
|
+
syncDhcpIP(this, 'ipv6');
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
$(document).on('turbolinks:load', function() {
|
|
58
|
+
syncAllProxmoxDhcpFields();
|
|
59
|
+
});
|
|
@@ -101,6 +101,7 @@ module ForemanFogProxmox
|
|
|
101
101
|
pools: extract_pools(cr),
|
|
102
102
|
storages: extract_storages(cr),
|
|
103
103
|
bridges: extract_bridges(cr),
|
|
104
|
+
images: extract_images(cr),
|
|
104
105
|
}
|
|
105
106
|
end
|
|
106
107
|
|
|
@@ -141,6 +142,39 @@ module ForemanFogProxmox
|
|
|
141
142
|
end
|
|
142
143
|
end
|
|
143
144
|
|
|
145
|
+
def extract_images(compute_resource)
|
|
146
|
+
images = compute_resource.images
|
|
147
|
+
images = images.order(:name) if images.respond_to?(:order)
|
|
148
|
+
|
|
149
|
+
Array(images).map do |image|
|
|
150
|
+
data = image.respond_to?(:as_json) ? image.as_json : image
|
|
151
|
+
uuid = image_value(image, data, :uuid, :id)
|
|
152
|
+
|
|
153
|
+
{
|
|
154
|
+
uuid: uuid,
|
|
155
|
+
name: image_value(image, data, :name),
|
|
156
|
+
disks: image_disks(compute_resource, uuid),
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def image_disks(compute_resource, uuid)
|
|
162
|
+
return nil unless uuid && compute_resource.respond_to?(:find_vm_by_uuid)
|
|
163
|
+
|
|
164
|
+
compute_resource.find_vm_by_uuid(uuid)&.disks
|
|
165
|
+
rescue ActiveRecord::RecordNotFound, StandardError
|
|
166
|
+
nil
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def image_value(image, data, *keys)
|
|
170
|
+
keys.each do |key|
|
|
171
|
+
value = [image.try(key), data.try(:[], key), data.try(:[], key.to_s)].find(&:present?)
|
|
172
|
+
return value if value.present?
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
nil
|
|
176
|
+
end
|
|
177
|
+
|
|
144
178
|
def load_compute_resource(compute_resource_id)
|
|
145
179
|
ComputeResource.find(compute_resource_id)
|
|
146
180
|
end
|
|
@@ -18,6 +18,47 @@
|
|
|
18
18
|
# along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>.
|
|
19
19
|
|
|
20
20
|
module ProxmoxFormHelper
|
|
21
|
+
include ProxmoxVMInterfacesHelper
|
|
22
|
+
|
|
23
|
+
def proxmox_vm_type_and_node_id(host, form_object, params)
|
|
24
|
+
compute_attributes = form_object.compute_attributes || {}
|
|
25
|
+
host_compute_attrs = host.respond_to?(:compute_attributes) ? (host.compute_attributes || {}) : {}
|
|
26
|
+
host_vm_type = extract_attr(host_compute_attrs, :type)
|
|
27
|
+
|
|
28
|
+
profile_attrs = profile_compute_attributes(host)
|
|
29
|
+
profile_vm_type = extract_attr(profile_attrs, :type)
|
|
30
|
+
|
|
31
|
+
vm_type = [
|
|
32
|
+
params.dig(:host, :compute_attributes, :type).presence,
|
|
33
|
+
params.dig(:compute_attribute, :vm_attrs, :type).presence,
|
|
34
|
+
host_vm_type,
|
|
35
|
+
profile_vm_type,
|
|
36
|
+
'qemu',
|
|
37
|
+
].find(&:present?)
|
|
38
|
+
|
|
39
|
+
compute_attributes = proxmox_default_interface_compute_attributes(host, vm_type) unless proxmox_valid_interface_compute_attributes?(compute_attributes, vm_type)
|
|
40
|
+
|
|
41
|
+
compute_node_id = extract_attr(compute_attributes, :node_id)
|
|
42
|
+
object_node_id = form_object.respond_to?(:node_id) ? form_object.node_id : nil
|
|
43
|
+
host_node_id = extract_attr(host_compute_attrs, :node_id)
|
|
44
|
+
profile_node_id = extract_attr(profile_attrs, :node_id)
|
|
45
|
+
|
|
46
|
+
node_id = [
|
|
47
|
+
params.dig(:host, :compute_attributes, :node_id).presence,
|
|
48
|
+
params.dig(:compute_attribute, :vm_attrs, :node_id).presence,
|
|
49
|
+
object_node_id,
|
|
50
|
+
compute_node_id,
|
|
51
|
+
host_node_id,
|
|
52
|
+
profile_node_id,
|
|
53
|
+
].find(&:present?)
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
compute_attributes: compute_attributes,
|
|
57
|
+
vm_type: vm_type,
|
|
58
|
+
node_id: node_id,
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
21
62
|
def password_proxmox_f(f, attr, options = {})
|
|
22
63
|
unset_button = options.delete(:unset)
|
|
23
64
|
value = f.object[attr] if options.delete(:keep_value)
|
|
@@ -79,4 +120,32 @@ module ProxmoxFormHelper
|
|
|
79
120
|
hide += '$("[data-association=' + type + '_volumes]").show();' unless ['hard_disk', 'mp'].include?(type)
|
|
80
121
|
f.hidden_field(opts[:method] || :_destroy) + link_to_function(name, 'remove_child_node(this);' + hide, opts)
|
|
81
122
|
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
def proxmox_default_interface_compute_attributes(host, vm_type)
|
|
127
|
+
host.compute_resource.interface_typed_defaults(vm_type).fetch(:compute_attributes).deep_dup
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def proxmox_valid_interface_compute_attributes?(compute_attributes, vm_type)
|
|
131
|
+
return false unless compute_attributes.respond_to?(:keys)
|
|
132
|
+
|
|
133
|
+
valid_keys = interface_compute_attributes_typed_keys(vm_type)
|
|
134
|
+
compute_attributes.keys.map(&:to_s).all? { |key| valid_keys.include?(key) }
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def extract_attr(attrs, key)
|
|
138
|
+
return unless attrs.respond_to?(:[])
|
|
139
|
+
|
|
140
|
+
attrs[key.to_s] || attrs[key.to_sym]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def profile_compute_attributes(host)
|
|
144
|
+
inherited_profile_id = host.respond_to?(:hostgroup) ? host.hostgroup&.inherited_compute_profile_id : nil
|
|
145
|
+
profile_id = host.compute_profile_id || inherited_profile_id
|
|
146
|
+
|
|
147
|
+
return {} if profile_id.blank?
|
|
148
|
+
|
|
149
|
+
host.compute_resource.compute_profile_attributes_for(profile_id) || {}
|
|
150
|
+
end
|
|
82
151
|
end
|
|
@@ -49,7 +49,7 @@ module ProxmoxVMAttrsHelper
|
|
|
49
49
|
|
|
50
50
|
def cpu_flags_attrs(param_scope, config)
|
|
51
51
|
flag_attrs = ActiveSupport::HashWithIndifferentAccess.new
|
|
52
|
-
Fog::Proxmox::CpuHelper.flags.
|
|
52
|
+
Fog::Proxmox::CpuHelper.flags.each_key do |key|
|
|
53
53
|
flag_attrs.merge!({ key => { :name => "#{param_scope}[config_attributes][#{key}]", :value => config.public_send(key) } })
|
|
54
54
|
end
|
|
55
55
|
flag_attrs
|
|
@@ -73,7 +73,7 @@ module ProxmoxVMAttrsHelper
|
|
|
73
73
|
keys = ['id', 'volid', 'storage', 'size', 'storage_type']
|
|
74
74
|
type = 'rootfs'
|
|
75
75
|
elsif vol.hard_disk?
|
|
76
|
-
keys = ['id', 'volid', 'storage_type', 'storage', 'controller', 'device', 'cache', 'size', '_delete']
|
|
76
|
+
keys = ['id', 'volid', 'storage_type', 'storage', 'controller', 'device', 'cache', 'size', '_delete', 'backup']
|
|
77
77
|
type = 'hard_disk'
|
|
78
78
|
elsif vol.cdrom?
|
|
79
79
|
keys = ['id', 'storage_type', 'cdrom', 'storage', 'volid']
|
|
@@ -82,7 +82,7 @@ module ProxmoxVMAttrsHelper
|
|
|
82
82
|
keys = ['id', 'volid', 'storage_type', 'storage', 'controller', 'device']
|
|
83
83
|
type = 'cloud_init'
|
|
84
84
|
elsif vol.mount_point?
|
|
85
|
-
keys = ['id', 'volid', 'storage_type', 'storage', 'device', 'mp', 'size']
|
|
85
|
+
keys = ['id', 'volid', 'storage_type', 'storage', 'device', 'mp', 'size', 'backup']
|
|
86
86
|
type = 'mount_point'
|
|
87
87
|
end
|
|
88
88
|
vol_attrs << { :name => type, :value => vol_keys(param_scope, keys, vol, id) }
|
|
@@ -107,6 +107,14 @@ module ProxmoxVMAttrsHelper
|
|
|
107
107
|
camel_key = key.to_s.include?('_') ? snake_to_camel(key.to_s).to_sym : key
|
|
108
108
|
attrs[camel_key] = { :name => "#{param_scope}[interfaces_attributes][#{id}][#{key}]", :value => value }
|
|
109
109
|
end
|
|
110
|
+
if interface.respond_to?(:dhcp)
|
|
111
|
+
attrs[:dhcp] = { :name => "#{param_scope}[interfaces_attributes][#{id}][dhcp]",
|
|
112
|
+
:value => interface.dhcp ? '1' : '0' }
|
|
113
|
+
end
|
|
114
|
+
if interface.respond_to?(:dhcp6)
|
|
115
|
+
attrs[:dhcp6] = { :name => "#{param_scope}[interfaces_attributes][#{id}][dhcp6]",
|
|
116
|
+
:value => interface.dhcp6 ? '1' : '0' }
|
|
117
|
+
end
|
|
110
118
|
networks_attrs << { :name => 'interface', :value => attrs }
|
|
111
119
|
end
|
|
112
120
|
networks_attrs
|
|
@@ -60,10 +60,27 @@ module ProxmoxVMInterfacesHelper
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def compute_dhcps(interface_attributes_h)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
interface_attributes_h
|
|
63
|
+
return if interface_attributes_h.nil?
|
|
64
|
+
|
|
65
|
+
sync_dhcp_for_ip(interface_attributes_h, 'ip', 'dhcp')
|
|
66
|
+
sync_dhcp_for_ip(interface_attributes_h, 'ip6', 'dhcp6')
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def sync_dhcp_for_ip(attrs, ip_key, dhcp_key)
|
|
70
|
+
dhcp_value = attrs[dhcp_key] || attrs[dhcp_key.to_sym]
|
|
71
|
+
if dhcp_value.nil?
|
|
72
|
+
ip_value = attrs[ip_key] || attrs[ip_key.to_sym]
|
|
73
|
+
attrs[dhcp_key.to_sym] = (ip_value == 'dhcp') ? '1' : '0'
|
|
74
|
+
attrs[ip_key.to_sym] = '' if attrs[dhcp_key.to_sym] == '1'
|
|
75
|
+
return
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
ip_value = attrs[ip_key] || attrs[ip_key.to_sym]
|
|
79
|
+
if dhcp_value.to_s == '1'
|
|
80
|
+
attrs[ip_key.to_sym] = 'dhcp' if ip_value.to_s.empty?
|
|
81
|
+
elsif ip_value.to_s == 'dhcp'
|
|
82
|
+
attrs[ip_key.to_sym] = ''
|
|
83
|
+
end
|
|
67
84
|
end
|
|
68
85
|
|
|
69
86
|
def add_or_delete_typed_interface(interface_attributes, interfaces_to_delete, interfaces_to_add, type)
|
|
@@ -51,13 +51,35 @@ module ProxmoxVMVolumesHelper
|
|
|
51
51
|
def parse_hard_disk_volume(args)
|
|
52
52
|
logger.debug(format(_('parse_hard_disk_volume(): args=%<args>s'), args: args))
|
|
53
53
|
disk = {}
|
|
54
|
+
rootfs_volume = rootfs_volume?(args)
|
|
55
|
+
set_disk_attributes(disk, args)
|
|
56
|
+
if rootfs_volume
|
|
57
|
+
args.delete('backup')
|
|
58
|
+
elsif args['backup'].nil?
|
|
59
|
+
args['backup'] = '1'
|
|
60
|
+
end
|
|
61
|
+
if args.key?('options')
|
|
62
|
+
options = args['options']
|
|
63
|
+
if rootfs_volume && options.respond_to?(:delete)
|
|
64
|
+
options = options.dup
|
|
65
|
+
options.delete('backup')
|
|
66
|
+
end
|
|
67
|
+
disk[:options] = options
|
|
68
|
+
else
|
|
69
|
+
add_disk_options(disk, args)
|
|
70
|
+
end
|
|
71
|
+
disk.key?(:storage) ? disk : {}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def rootfs_volume?(args)
|
|
75
|
+
args['storage_type'] == 'rootfs' || args['id'] == 'rootfs'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def set_disk_attributes(disk, args)
|
|
54
79
|
disk[:id] = args['id'] if args.key?('id')
|
|
55
80
|
disk[:volid] = args['volid'] if args.key?('volid') && !args['volid'].empty?
|
|
56
81
|
disk[:storage] = args['storage'].to_s if args.key?('storage') && !args['storage'].empty?
|
|
57
82
|
disk[:size] = args['size'].to_i if args.key?('size') && !args['size'].empty?
|
|
58
|
-
add_disk_options(disk, args) unless args.key?('options')
|
|
59
|
-
disk[:options] = args['options'] if args.key?('options')
|
|
60
|
-
disk.key?(:storage) ? disk : {}
|
|
61
83
|
end
|
|
62
84
|
|
|
63
85
|
def volume_type?(args, type)
|
|
@@ -71,6 +93,7 @@ module ProxmoxVMVolumesHelper
|
|
|
71
93
|
end
|
|
72
94
|
|
|
73
95
|
def parse_typed_volume(args, type)
|
|
96
|
+
return if Foreman::Cast.to_bool(args['_delete'])
|
|
74
97
|
logger.debug("parse_typed_volume(#{type}): args=#{args}")
|
|
75
98
|
disk = parse_hard_disk_volume(args) if volume_type?(args,
|
|
76
99
|
'hard_disk') || volume_type?(args, 'mp') || volume_type?(args, 'rootfs')
|
|
@@ -94,6 +117,9 @@ module ProxmoxVMVolumesHelper
|
|
|
94
117
|
|
|
95
118
|
def remove_volume_keys(args)
|
|
96
119
|
if args.key?('volumes_attributes')
|
|
120
|
+
args['volumes_attributes'].delete_if do |_index, volume_attributes|
|
|
121
|
+
Foreman::Cast.to_bool(volume_attributes['_delete'])
|
|
122
|
+
end
|
|
97
123
|
args['volumes_attributes'].each_value do |volume_attributes|
|
|
98
124
|
ForemanFogProxmox::HashCollection.remove_keys(volume_attributes, ['_delete'])
|
|
99
125
|
end
|
|
@@ -21,12 +21,18 @@ module FogExtensions
|
|
|
21
21
|
module Proxmox
|
|
22
22
|
module Server
|
|
23
23
|
extend ActiveSupport::Concern
|
|
24
|
-
attr_accessor :image_id, :templated, :ostemplate_storage, :ostemplate_file, :password, :start_after_create
|
|
24
|
+
attr_accessor :image_id, :templated, :ostemplate_storage, :ostemplate_file, :password, :start_after_create, :compute_resource_id
|
|
25
25
|
|
|
26
26
|
def unique_cluster_identity(compute_resource)
|
|
27
27
|
compute_resource.id.to_s + '_' + identity.to_s
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def foreman_uuid
|
|
31
|
+
return identity.to_s if compute_resource_id.nil?
|
|
32
|
+
|
|
33
|
+
compute_resource_id.to_s + '_' + identity.to_s
|
|
34
|
+
end
|
|
35
|
+
|
|
30
36
|
def start
|
|
31
37
|
action('start')
|
|
32
38
|
end
|
|
@@ -49,12 +49,11 @@ module HostExt
|
|
|
49
49
|
|
|
50
50
|
def add_interface_to_compute_attributes(index, interface_attributes, compute_attributes)
|
|
51
51
|
compute_attributes[index] = {}
|
|
52
|
-
compute_attributes[index].store('id', interface_attributes['identifier'])
|
|
53
52
|
compute_attributes[index].store('_delete', interface_attributes['_destroy'])
|
|
54
53
|
compute_attributes[index].store('macaddr', interface_attributes['mac'])
|
|
55
54
|
compute_attributes[index].store('ip', cidr_ip(interface_attributes))
|
|
56
55
|
compute_attributes[index].store('ip6', cidr_ip(interface_attributes, 6))
|
|
57
|
-
compute_attributes[index].merge
|
|
56
|
+
compute_attributes[index].merge(interface_attributes['compute_attributes'])
|
|
58
57
|
end
|
|
59
58
|
end
|
|
60
59
|
end
|
|
@@ -45,6 +45,7 @@ module ForemanFogProxmox
|
|
|
45
45
|
|
|
46
46
|
def provided_attributes
|
|
47
47
|
super.merge(
|
|
48
|
+
:uuid => :foreman_uuid,
|
|
48
49
|
:mac => :mac
|
|
49
50
|
)
|
|
50
51
|
end
|
|
@@ -62,10 +63,11 @@ module ForemanFogProxmox
|
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def associated_host(vm)
|
|
65
|
-
associate_by('mac', vm
|
|
66
|
+
associate_by('mac', vm&.mac)
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def associate_by(name, attributes)
|
|
70
|
+
return nil if attributes.blank?
|
|
69
71
|
Host.authorized(:view_hosts,
|
|
70
72
|
Host).joins(:primary_interface).where(:nics => { :primary => true }).where("nics.#{name}".downcase => attributes.downcase).readonly(false).first
|
|
71
73
|
end
|
|
@@ -19,8 +19,13 @@
|
|
|
19
19
|
|
|
20
20
|
module ForemanFogProxmox
|
|
21
21
|
module ProxmoxComputeAttributes
|
|
22
|
+
FOREMAN_INTERFACE_ATTRIBUTES = [:id, :mac, :ip, :ip6].freeze
|
|
23
|
+
PROXMOX_MAC_ATTRIBUTES = [:macaddr, :hwaddr].freeze
|
|
24
|
+
PROXMOX_INTERFACE_METADATA = [:identifier, :compute_attributes].freeze
|
|
25
|
+
|
|
22
26
|
def host_compute_attrs(host)
|
|
23
|
-
|
|
27
|
+
config = host.compute_attributes['config_attributes'] || {}
|
|
28
|
+
ostype = config['ostype']
|
|
24
29
|
type = host.compute_attributes['type']
|
|
25
30
|
case type
|
|
26
31
|
when 'lxc'
|
|
@@ -41,19 +46,35 @@ module ForemanFogProxmox
|
|
|
41
46
|
end
|
|
42
47
|
|
|
43
48
|
def interface_compute_attributes(interface_attributes)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
attrs = interface_attributes.with_indifferent_access
|
|
50
|
+
provider_attrs = attrs[:compute_attributes].present? ? attrs[:compute_attributes].with_indifferent_access : ActiveSupport::HashWithIndifferentAccess.new
|
|
51
|
+
|
|
52
|
+
vm_attrs = FOREMAN_INTERFACE_ATTRIBUTES.index_with do |key|
|
|
53
|
+
attrs[key] || provider_attrs.delete(key)
|
|
54
|
+
end.compact
|
|
55
|
+
vm_attrs[:mac] ||= attrs[:macaddr] || attrs[:hwaddr] || provider_attrs.delete(:macaddr) || provider_attrs.delete(:hwaddr)
|
|
56
|
+
|
|
57
|
+
attrs.except(*FOREMAN_INTERFACE_ATTRIBUTES, *PROXMOX_MAC_ATTRIBUTES, *PROXMOX_INTERFACE_METADATA).each do |key, value|
|
|
58
|
+
provider_attrs[key] = value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
provider_attrs[:dhcp] = (vm_attrs[:ip] == 'dhcp') ? '1' : '0'
|
|
62
|
+
provider_attrs[:dhcp6] = (vm_attrs[:ip6] == 'dhcp') ? '1' : '0'
|
|
63
|
+
vm_attrs[:compute_attributes] = provider_attrs
|
|
47
64
|
vm_attrs
|
|
48
65
|
end
|
|
49
66
|
|
|
67
|
+
def volume_compute_attributes(volume_attributes)
|
|
68
|
+
volume_attributes.merge(_delete: '0')
|
|
69
|
+
end
|
|
70
|
+
|
|
50
71
|
def vm_compute_attributes(vm)
|
|
51
72
|
vm_attrs = {}
|
|
52
73
|
vm_attrs = vm_attrs.merge(vmid: vm.identity, node_id: vm.node_id, type: vm.type)
|
|
53
74
|
if vm.respond_to?(:config)
|
|
54
75
|
if vm.config.respond_to?(:disks)
|
|
55
76
|
vm_attrs[:volumes_attributes] = Hash[vm.config.disks.each_with_index.map do |disk, idx|
|
|
56
|
-
[idx.to_s, disk.attributes]
|
|
77
|
+
[idx.to_s, volume_compute_attributes(disk.attributes)]
|
|
57
78
|
end ]
|
|
58
79
|
end
|
|
59
80
|
if vm.config.respond_to?(:interfaces)
|
|
@@ -20,16 +20,20 @@
|
|
|
20
20
|
module ForemanFogProxmox
|
|
21
21
|
module ProxmoxOperatingSystems
|
|
22
22
|
def compute_os_types(host)
|
|
23
|
-
os_linux_types_mapping(host)
|
|
23
|
+
[os_linux_types_mapping(host), os_windows_types_mapping(host), os_other_types_mapping(host)].find(&:any?) || []
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def available_operating_systems
|
|
27
|
-
operating_systems =
|
|
27
|
+
operating_systems = available_other_operating_systems
|
|
28
28
|
operating_systems += available_linux_operating_systems
|
|
29
29
|
operating_systems += available_windows_operating_systems
|
|
30
30
|
operating_systems
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
def available_other_operating_systems
|
|
34
|
+
['other', 'solaris']
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
def available_linux_operating_systems
|
|
34
38
|
['l24', 'l26', 'debian', 'ubuntu', 'centos', 'fedora', 'opensuse', 'archlinux', 'gentoo', 'alpine']
|
|
35
39
|
end
|
|
@@ -50,5 +54,12 @@ module ForemanFogProxmox
|
|
|
50
54
|
def os_windows_types_mapping(host)
|
|
51
55
|
['Windows'].include?(host.operatingsystem.type) ? available_windows_operating_systems : []
|
|
52
56
|
end
|
|
57
|
+
|
|
58
|
+
def os_other_types_mapping(host)
|
|
59
|
+
{
|
|
60
|
+
'Freebsd' => ['other'],
|
|
61
|
+
'Solaris' => ['solaris'],
|
|
62
|
+
}.fetch(host.operatingsystem.type, [])
|
|
63
|
+
end
|
|
53
64
|
end
|
|
54
65
|
end
|
|
@@ -31,18 +31,18 @@ module ForemanFogProxmox
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def cloudinit_defaults
|
|
34
|
-
{ storage_type: 'cloud_init', id: 'ide0', storage: storages.first
|
|
34
|
+
{ storage_type: 'cloud_init', id: 'ide0', storage: storages.first&.identity.to_s, media: 'cdrom' }
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def hard_disk_typed_defaults(vm_type)
|
|
38
38
|
options = {}
|
|
39
|
-
volume_attributes_h = { storage: storages.first
|
|
39
|
+
volume_attributes_h = { storage: storages.first&.identity.to_s, size: '8' }
|
|
40
40
|
case vm_type
|
|
41
41
|
when 'qemu'
|
|
42
42
|
controller = 'virtio'
|
|
43
43
|
device = 0
|
|
44
44
|
id = "#{controller}#{device}"
|
|
45
|
-
options = { cache: 'none' }
|
|
45
|
+
options = { cache: 'none', backup: '1' }
|
|
46
46
|
volume_attributes_h = volume_attributes_h.merge(controller: controller, device: device)
|
|
47
47
|
when 'lxc'
|
|
48
48
|
id = 'rootfs'
|
|
@@ -69,18 +69,18 @@ module ForemanFogProxmox
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
def interface_defaults(id = 'net0')
|
|
72
|
-
{ id: id, compute_attributes: { model: 'virtio', name: 'eth0', bridge: bridges.first
|
|
72
|
+
{ id: id, compute_attributes: { model: 'virtio', name: 'eth0', bridge: bridges.first&.identity.to_s } }
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def interface_typed_defaults(type)
|
|
76
76
|
interface_attributes_h = { id: 'net0', compute_attributes: {} }
|
|
77
77
|
if type == 'qemu'
|
|
78
78
|
interface_attributes_h[:compute_attributes] =
|
|
79
|
-
{ model: 'virtio', bridge: bridges.first
|
|
79
|
+
{ model: 'virtio', bridge: bridges.first&.identity.to_s }
|
|
80
80
|
end
|
|
81
81
|
if type == 'lxc'
|
|
82
82
|
interface_attributes_h[:compute_attributes] =
|
|
83
|
-
{ name: 'eth0', bridge: bridges.first
|
|
83
|
+
{ name: 'eth0', bridge: bridges.first&.identity.to_s, dhcp: 1, dhcp6: 1 }
|
|
84
84
|
end
|
|
85
85
|
interface_attributes_h
|
|
86
86
|
end
|
|
@@ -32,7 +32,7 @@ module ForemanFogProxmox
|
|
|
32
32
|
node ||= default_node
|
|
33
33
|
storages = node.storages.list_by_content_type type
|
|
34
34
|
logger.debug("storages(): node_id #{node_id} type #{type}")
|
|
35
|
-
storages.sort_by(&:storage)
|
|
35
|
+
storages.reject { |s| s.enabled.to_i.zero? || s.active.to_i.zero? }.sort_by(&:storage)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def bridges(node_id = default_node_id)
|
|
@@ -46,9 +46,10 @@ module ForemanFogProxmox
|
|
|
46
46
|
def vms(opts = {})
|
|
47
47
|
vms = []
|
|
48
48
|
nodes.each { |node| vms += node.servers.all + node.containers.all }
|
|
49
|
+
vms.each { |vm| attach_compute_resource_id(vm) }
|
|
49
50
|
if opts.key?(:eager_loading) && opts[:eager_loading]
|
|
50
51
|
vms_eager = []
|
|
51
|
-
vms.each { |vm| vms_eager << vm.collection.get(vm.identity) }
|
|
52
|
+
vms.each { |vm| vms_eager << attach_compute_resource_id(vm.collection.get(vm.identity)) }
|
|
52
53
|
vms = vms_eager
|
|
53
54
|
end
|
|
54
55
|
ForemanFogProxmox::Vms.new(vms)
|
|
@@ -71,12 +72,21 @@ module ForemanFogProxmox
|
|
|
71
72
|
def find_vm_in_servers_by_vmid(servers, vmid)
|
|
72
73
|
vm = servers.get(vmid) unless ForemanFogProxmox::Value.empty?(vmid)
|
|
73
74
|
pool_owner(vm) if vm
|
|
74
|
-
vm
|
|
75
|
+
attach_compute_resource_id(vm)
|
|
75
76
|
rescue Fog::Errors::NotFound
|
|
76
77
|
nil
|
|
77
78
|
rescue StandardError => e
|
|
78
79
|
Foreman::Logging.exception(format(_('Failed retrieving proxmox server vm by vmid=%<vmid>s'), vmid: vmid), e)
|
|
79
80
|
raise(ActiveRecord::RecordNotFound, e)
|
|
80
81
|
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def attach_compute_resource_id(virtual_machine)
|
|
86
|
+
return virtual_machine if virtual_machine.nil?
|
|
87
|
+
|
|
88
|
+
virtual_machine.compute_resource_id = id if virtual_machine.respond_to?(:compute_resource_id=)
|
|
89
|
+
virtual_machine
|
|
90
|
+
end
|
|
81
91
|
end
|
|
82
92
|
end
|
|
@@ -35,8 +35,12 @@ module ForemanFogProxmox
|
|
|
35
35
|
|
|
36
36
|
def volume_options(vm, id, volume_attributes)
|
|
37
37
|
options = {}
|
|
38
|
+
backup = volume_attributes['backup'].to_s
|
|
39
|
+
cache = volume_attributes['cache'].to_s
|
|
40
|
+
backup = '1' if backup.empty? && (!vm.container? || id != 'rootfs')
|
|
38
41
|
options.store(:mp, volume_attributes['mp']) if vm.container? && id != 'rootfs'
|
|
39
|
-
options.store(:cache,
|
|
42
|
+
options.store(:cache, cache) unless vm.container? || cache.empty?
|
|
43
|
+
options.store(:backup, backup) unless backup.empty? || (vm.container? && id == 'rootfs')
|
|
40
44
|
options
|
|
41
45
|
end
|
|
42
46
|
|
|
@@ -87,14 +91,12 @@ module ForemanFogProxmox
|
|
|
87
91
|
raise ::Foreman::Exception,
|
|
88
92
|
format(_('Unable to shrink %<id>s size. Proxmox allows only increasing size.'), id: id)
|
|
89
93
|
end
|
|
90
|
-
diff_size = volume_attributes['size'].to_i - disk.size.to_i if volume_attributes['size'] && disk.size
|
|
91
|
-
raise ::Foreman::Exception, format(_('Unable to shrink %<id>s size. Proxmox allows only increasing size.'), id: id) unless diff_size >= 0
|
|
92
94
|
|
|
93
|
-
new_storage = volume_attributes['storage']
|
|
95
|
+
new_storage = volume_attributes['storage'].presence || disk.storage
|
|
94
96
|
|
|
95
97
|
if diff_size > 0
|
|
96
98
|
extend_volume(vm, id, diff_size)
|
|
97
|
-
elsif disk.storage != new_storage
|
|
99
|
+
elsif new_storage.present? && disk.storage != new_storage
|
|
98
100
|
move_volume(id, vm, new_storage)
|
|
99
101
|
else
|
|
100
102
|
update_options(disk, vm, volume_attributes)
|
|
@@ -102,6 +104,13 @@ module ForemanFogProxmox
|
|
|
102
104
|
end
|
|
103
105
|
end
|
|
104
106
|
|
|
107
|
+
def normalize_existing_volume_attributes(disk, volume_attributes)
|
|
108
|
+
return volume_attributes unless disk.hard_disk?
|
|
109
|
+
return volume_attributes if volume_attributes['storage'].present?
|
|
110
|
+
|
|
111
|
+
volume_attributes.merge('storage' => disk.storage)
|
|
112
|
+
end
|
|
113
|
+
|
|
105
114
|
def volume_exists?(vm, volume_attributes)
|
|
106
115
|
disk = vm.config.disks.get(volume_attributes['id'])
|
|
107
116
|
return false unless disk
|
|
@@ -154,7 +163,8 @@ module ForemanFogProxmox
|
|
|
154
163
|
delete_volume(vm, id, volume_attributes)
|
|
155
164
|
else
|
|
156
165
|
disk = vm.config.disks.get(id)
|
|
157
|
-
|
|
166
|
+
normalized_volume_attributes = normalize_existing_volume_attributes(disk, volume_attributes)
|
|
167
|
+
update_volume(vm, disk, normalized_volume_attributes) if update_volume_required?(disk.attributes, normalized_volume_attributes)
|
|
158
168
|
end
|
|
159
169
|
else
|
|
160
170
|
add_volume(vm, id, volume_attributes)
|
|
@@ -15,13 +15,12 @@ GNU General Public License for more details.
|
|
|
15
15
|
You should have received a copy of the GNU General Public License
|
|
16
16
|
along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>. %>
|
|
17
17
|
<% if @host.compute_resource.class == ForemanFogProxmox::Proxmox %>
|
|
18
|
-
<%
|
|
19
|
-
<%
|
|
20
|
-
<%
|
|
18
|
+
<% vm_type_and_node_id = proxmox_vm_type_and_node_id(@host, f.object, params) %>
|
|
19
|
+
<% compute_attributes = vm_type_and_node_id[:compute_attributes] %>
|
|
20
|
+
<% vm_type = vm_type_and_node_id[:vm_type] %>
|
|
21
|
+
<% node_id = vm_type_and_node_id[:node_id] %>
|
|
21
22
|
|
|
22
|
-
<%= f.fields_for 'compute_attributes', OpenStruct.new(
|
|
23
|
-
<% vm_type = compute_attributes.respond_to?('type') ? compute_attributes.type : 'qemu' %>
|
|
24
|
-
<% logger.debug("_add_vm_type_to_nic_provider_specific_form.html vm_type=#{vm_type}") %>
|
|
23
|
+
<%= f.fields_for 'compute_attributes', OpenStruct.new(compute_attributes) do |f| %>
|
|
25
24
|
<%= render provider_partial(@host.compute_resource, 'network'), :f => f, :vm_type => vm_type, :node_id => node_id, :disabled => f.object.persisted?, :compute_resource => @host.compute_resource, :new_host => new_vm, :new_vm => new_vm %>
|
|
26
25
|
<% end %>
|
|
27
26
|
<% else %>
|