foreman_fog_proxmox 0.25.1 → 1.0.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_network_interface_modal.js +11 -0
- data/app/assets/stylesheets/foreman_fog_proxmox/network_interface_modal.css +17 -0
- data/app/controllers/foreman_fog_proxmox/compute_resources_controller.rb +31 -23
- data/app/helpers/proxmox_vm_attrs_helper.rb +1 -0
- data/app/helpers/proxmox_vm_cloudinit_helper.rb +63 -48
- data/app/helpers/proxmox_vm_config_helper.rb +1 -1
- data/app/models/concerns/fog_extensions/proxmox/server.rb +1 -1
- data/app/models/foreman_fog_proxmox/proxmox_images.rb +1 -1
- data/app/models/foreman_fog_proxmox/proxmox_vm_commands.rb +2 -2
- data/app/models/foreman_fog_proxmox/proxmox_vm_new.rb +14 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_react_component_to_host_form.html.erb +5 -0
- data/app/views/compute_resources_vms/form/proxmox/_add_vm_type_to_nic_provider_specific_form.html.erb +5 -4
- data/lib/foreman_fog_proxmox/engine.rb +8 -2
- data/lib/foreman_fog_proxmox/version.rb +1 -1
- data/test/functional/compute_resources_controller_test.rb +41 -0
- data/test/unit/foreman_fog_proxmox/proxmox_images_test.rb +13 -0
- data/test/unit/foreman_fog_proxmox/proxmox_vm_commands_server_create_test.rb +123 -10
- data/test/unit/foreman_fog_proxmox/proxmox_vm_new_test.rb +40 -0
- data/webpack/components/GeneralTabContent.js +99 -61
- data/webpack/components/ProxmoxVmType.js +20 -0
- data/webpack/components/__tests__/GeneralTabContent.test.js +207 -0
- data/webpack/components/__tests__/ProxmoxVmType.test.js +36 -1
- data/webpack/components/hooks/useInheritedImageSelection.js +42 -0
- metadata +6 -3
- data/app/controllers/concerns/foreman_fog_proxmox/controller/parameters/compute_resource.rb +0 -41
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9dcd1a0e6c90d8847b0e31986425ab3354e4659676994ea6ab84ec9648b0d17d
|
|
4
|
+
data.tar.gz: 8dc424df461ebfe7f7cf07f11e7fecebf56fa75c3bdb4c52b51ef2fdcda01fa5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a99138711e3912f07dfe3c875106745d543db41e466fbf50460a3fd9abab1476e1da72620f2233d4455984698c64763b849c87f317131d6021b458f1150ea2f5
|
|
7
|
+
data.tar.gz: 852428fd8ed987daca7f45d0908a8b9d71ecbacb9affe3bd65fdc9ecff12b7be80859ea3071d59bd00d8182d5bd75eac1510f922e9c3977be6fd638a879e8187
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
$(document)
|
|
2
|
+
.on('show.bs.modal', '#interfaceModal', function () {
|
|
3
|
+
var modal = $(this);
|
|
4
|
+
modal.toggleClass(
|
|
5
|
+
'proxmox-interface-modal',
|
|
6
|
+
modal.find('.proxmox-interface-form').length > 0
|
|
7
|
+
);
|
|
8
|
+
})
|
|
9
|
+
.on('hidden.bs.modal', '#interfaceModal', function () {
|
|
10
|
+
$(this).removeClass('proxmox-interface-modal');
|
|
11
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#interfaceModal.proxmox-interface-modal {
|
|
2
|
+
overflow-y: hidden;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
#interfaceModal.proxmox-interface-modal .modal-content {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: column;
|
|
8
|
+
max-height: 90vh;
|
|
9
|
+
overflow: hidden;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#interfaceModal.proxmox-interface-modal .modal-body {
|
|
13
|
+
flex: 1 1 auto;
|
|
14
|
+
min-height: 0;
|
|
15
|
+
overflow-y: auto;
|
|
16
|
+
overflow-x: hidden;
|
|
17
|
+
}
|
|
@@ -95,20 +95,21 @@ module ForemanFogProxmox
|
|
|
95
95
|
# GET foreman_fog_proxmox/metadata/:compute_resource_id
|
|
96
96
|
def metadata
|
|
97
97
|
cr = ComputeResource.find(params[:compute_resource_id])
|
|
98
|
+
nodes = Array(cr.nodes)
|
|
98
99
|
|
|
99
100
|
render json: {
|
|
100
|
-
nodes: extract_nodes(
|
|
101
|
+
nodes: extract_nodes(nodes),
|
|
101
102
|
pools: extract_pools(cr),
|
|
102
|
-
storages: extract_storages(cr),
|
|
103
|
-
bridges: extract_bridges(cr),
|
|
103
|
+
storages: extract_storages(cr, nodes),
|
|
104
|
+
bridges: extract_bridges(cr, nodes),
|
|
104
105
|
images: extract_images(cr),
|
|
105
106
|
}
|
|
106
107
|
end
|
|
107
108
|
|
|
108
109
|
private
|
|
109
110
|
|
|
110
|
-
def extract_nodes(
|
|
111
|
-
|
|
111
|
+
def extract_nodes(nodes)
|
|
112
|
+
nodes.map { |n| { node: n.node } }
|
|
112
113
|
end
|
|
113
114
|
|
|
114
115
|
def extract_pools(compute_resource)
|
|
@@ -118,27 +119,34 @@ module ForemanFogProxmox
|
|
|
118
119
|
end
|
|
119
120
|
end
|
|
120
121
|
|
|
121
|
-
def extract_storages(compute_resource)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
storage:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
122
|
+
def extract_storages(compute_resource, nodes)
|
|
123
|
+
nodes.flat_map do |node|
|
|
124
|
+
node_id = node.node
|
|
125
|
+
Array(compute_resource.storages(node_id)).map do |storage|
|
|
126
|
+
h = storage.respond_to?(:as_json) ? storage.as_json : storage
|
|
127
|
+
{
|
|
128
|
+
storage: (h[:storage] || h['storage']),
|
|
129
|
+
node_id: node_id,
|
|
130
|
+
content: (h[:content] || h['content']),
|
|
131
|
+
avail: (h[:avail] || h['avail']),
|
|
132
|
+
used: (h[:used] || h['used']),
|
|
133
|
+
total: (h[:total] || h['total']),
|
|
134
|
+
shared: (h[:shared] || h['shared']),
|
|
135
|
+
}
|
|
136
|
+
end
|
|
132
137
|
end
|
|
133
138
|
end
|
|
134
139
|
|
|
135
|
-
def extract_bridges(compute_resource)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
def extract_bridges(compute_resource, nodes)
|
|
141
|
+
nodes.flat_map do |node|
|
|
142
|
+
node_id = node.node
|
|
143
|
+
Array(compute_resource.bridges(node_id)).map do |bridge|
|
|
144
|
+
h = bridge.respond_to?(:as_json) ? bridge.as_json : bridge
|
|
145
|
+
{
|
|
146
|
+
node_id: node_id,
|
|
147
|
+
iface: (h[:iface] || h['iface']),
|
|
148
|
+
}
|
|
149
|
+
end
|
|
142
150
|
end
|
|
143
151
|
end
|
|
144
152
|
|
|
@@ -130,6 +130,7 @@ module ProxmoxVMAttrsHelper
|
|
|
130
130
|
hostname: vms.config.hostname,
|
|
131
131
|
ostemplate_storage: vms.ostemplate_storage,
|
|
132
132
|
ostemplate_file: vms.ostemplate_file,
|
|
133
|
+
iso_upload_storage: vms.iso_upload_storage,
|
|
133
134
|
start_after_create: vms.start_after_create,
|
|
134
135
|
templated: vms.templated,
|
|
135
136
|
is_secure_boot: vms.config.secure_boot?,
|
|
@@ -21,6 +21,9 @@ require 'fog/proxmox/helpers/disk_helper'
|
|
|
21
21
|
require 'fog/proxmox/helpers/nic_helper'
|
|
22
22
|
require 'foreman_fog_proxmox/value'
|
|
23
23
|
require 'foreman_fog_proxmox/hash_collection'
|
|
24
|
+
require 'fileutils'
|
|
25
|
+
require 'open3'
|
|
26
|
+
require 'tmpdir'
|
|
24
27
|
|
|
25
28
|
# Convert a foreman form server hash into a fog-proxmox server attributes hash
|
|
26
29
|
module ProxmoxVMCloudinitHelper
|
|
@@ -42,54 +45,59 @@ module ProxmoxVMCloudinitHelper
|
|
|
42
45
|
cloudinit_h
|
|
43
46
|
end
|
|
44
47
|
|
|
45
|
-
def create_cloudinit_iso(vm_name, configs
|
|
46
|
-
|
|
48
|
+
def create_cloudinit_iso(vm_name, configs)
|
|
49
|
+
wd = create_temp_directory
|
|
50
|
+
iso = File.join(wd, "#{vm_name.tr('.', '_')}_cloudinit.iso")
|
|
47
51
|
files = []
|
|
48
|
-
wd = create_temp_directory(ssh)
|
|
49
52
|
|
|
50
53
|
configs.each do |config|
|
|
51
|
-
config_file =
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
raise ::Foreman::Exception, "Failed to create file #{config[0]}: #{config_file.first.stdout}"
|
|
55
|
-
end
|
|
56
|
-
files.append(File.join(wd, config[0]))
|
|
54
|
+
config_file = File.join(wd, config[0])
|
|
55
|
+
File.write(config_file, config[1])
|
|
56
|
+
files.append(config_file)
|
|
57
57
|
end
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
logger.debug("Generating cloud-init ISO at #{iso}")
|
|
59
|
+
stdout, stderr, status = Open3.capture3(*generate_iso_command(iso, files))
|
|
60
|
+
raise Foreman::Exception, N_("ISO build failed: #{stderr.presence || stdout}") unless status.success?
|
|
61
|
+
|
|
62
|
+
yield iso
|
|
63
|
+
ensure
|
|
64
|
+
delete_temp_dir(wd) if wd && Dir.exist?(wd)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def generate_iso_command(iso_file, config_files)
|
|
68
|
-
arguments = ["genisoimage",
|
|
69
|
-
|
|
70
|
-
logger.debug("iso image generation args: #{
|
|
71
|
-
|
|
68
|
+
arguments = ["genisoimage", '-output', iso_file, '-volid', 'cidata', '-joliet', '-rock']
|
|
69
|
+
arguments.concat(config_files)
|
|
70
|
+
logger.debug("iso image generation args: #{arguments.join(' ')}")
|
|
71
|
+
arguments
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def create_temp_directory
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
def create_temp_directory
|
|
75
|
+
Dir.mktmpdir
|
|
76
|
+
rescue StandardError => e
|
|
77
|
+
raise ::Foreman::Exception, "Could not create working directory to store cloudinit config data: #{e}."
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def delete_temp_dir(
|
|
81
|
-
|
|
82
|
-
rescue
|
|
80
|
+
def delete_temp_dir(working_dir)
|
|
81
|
+
FileUtils.remove_entry(working_dir)
|
|
82
|
+
rescue StandardError => e
|
|
83
83
|
logger.warn("Could not delete directory for config files: #{e}. Please delete it manually at #{working_dir}")
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
def
|
|
86
|
+
def cloudinit_clone_args(args, vm_instance)
|
|
87
|
+
return args unless args[:user_data]
|
|
88
|
+
|
|
89
|
+
actual_node = vm_instance.node_id
|
|
90
|
+
logger.info("Cloud-init ISO storage will be validated for cloned VM node #{actual_node} instead of selected node #{args[:node_id]}") if args[:node_id] != actual_node
|
|
91
|
+
|
|
92
|
+
parse_cloudinit_config(args, vm_node: actual_node)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def parse_cloudinit_config(args, vm_node: args[:node_id])
|
|
87
96
|
filenames = ["meta-data"]
|
|
88
97
|
config_data = ["instance-id: #{args[:name]}"]
|
|
89
98
|
user_data = args.delete(:user_data)
|
|
90
99
|
return args if user_data == ''
|
|
91
100
|
check_template_format(user_data)
|
|
92
|
-
ssh = vm_ssh
|
|
93
101
|
|
|
94
102
|
if user_data.include?('#network-config') && user_data.include?('#cloud-config')
|
|
95
103
|
config_data.concat(user_data.split('#network-config'))
|
|
@@ -105,32 +113,39 @@ module ProxmoxVMCloudinitHelper
|
|
|
105
113
|
return args if config_data.length == 1
|
|
106
114
|
configs = filenames.zip(config_data).to_h
|
|
107
115
|
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
create_cloudinit_iso(args[:name], configs) do |iso|
|
|
117
|
+
storage = upload_iso(args[:node_id], args[:iso_upload_storage], iso, vm_node: vm_node)
|
|
118
|
+
args.merge!(attach_cloudinit_iso(vm_node, storage, iso))
|
|
119
|
+
end
|
|
110
120
|
end
|
|
111
121
|
|
|
112
|
-
def
|
|
113
|
-
|
|
114
|
-
storages(node, 'iso').each do |storage|
|
|
115
|
-
volume = storage.volumes.detect { |v| v.volid.include? File.basename(iso) }
|
|
116
|
-
break if volume
|
|
117
|
-
end
|
|
122
|
+
def upload_iso(node, storage_id, iso, vm_node: node)
|
|
123
|
+
raise ::Foreman::Exception, _('ISO upload storage must be selected') if storage_id.blank?
|
|
118
124
|
|
|
119
|
-
|
|
125
|
+
iso_storages = storages(node, 'iso')
|
|
126
|
+
storage = iso_storages.find { |s| s.identity == storage_id }
|
|
127
|
+
raise ::Foreman::Exception, "Could not find selected ISO upload storage #{storage_id} for node #{node}" unless storage
|
|
120
128
|
|
|
121
|
-
|
|
122
|
-
|
|
129
|
+
if node != vm_node
|
|
130
|
+
vm_storage = storages(vm_node, 'iso').find { |s| s.identity == storage_id }
|
|
131
|
+
raise ::Foreman::Exception, "Selected ISO upload storage #{storage_id} is not accessible from cloned VM node #{vm_node}" unless vm_storage
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
storage = vm_storage
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
storage.upload_iso(iso)
|
|
137
|
+
storage.identity
|
|
126
138
|
end
|
|
127
139
|
|
|
128
|
-
def
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
140
|
+
def attach_cloudinit_iso(node, storage_id, iso)
|
|
141
|
+
storage = client.nodes.get(node).storages.get(storage_id)
|
|
142
|
+
volume = storage&.volumes&.all&.detect do |v|
|
|
143
|
+
File.basename(v.volid) == File.basename(iso)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
raise ::Foreman::Exception, "Could not find generated cloud-init ISO #{File.basename(iso)} on storage #{storage_id} for node #{node}" unless volume
|
|
147
|
+
|
|
148
|
+
{ ide2: "#{volume.volid},media=cdrom" }
|
|
134
149
|
end
|
|
135
150
|
|
|
136
151
|
def check_template_format(user_data)
|
|
@@ -41,7 +41,7 @@ module ProxmoxVMConfigHelper
|
|
|
41
41
|
|
|
42
42
|
def general_a(type)
|
|
43
43
|
general_a = ['node_id', 'type', 'config_attributes', 'efidisk_attributes', 'volumes_attributes', 'interfaces_attributes', 'image_id']
|
|
44
|
-
general_a += ['firmware_type', 'provision_method', 'container_volumes', 'server_volumes', 'start_after_create']
|
|
44
|
+
general_a += ['firmware_type', 'provision_method', 'container_volumes', 'server_volumes', 'start_after_create', 'iso_upload_storage']
|
|
45
45
|
general_a += ['name'] if type == 'lxc'
|
|
46
46
|
general_a
|
|
47
47
|
end
|
|
@@ -21,7 +21,7 @@ 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, :compute_resource_id
|
|
24
|
+
attr_accessor :image_id, :templated, :ostemplate_storage, :ostemplate_file, :iso_upload_storage, :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
|
|
@@ -41,7 +41,7 @@ module ForemanFogProxmox
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def available_images
|
|
44
|
-
templates.collect { |template| OpenStruct.new(id: template_uuid(template), name: template_name(template)) }
|
|
44
|
+
templates.collect { |template| OpenStruct.new(id: template_uuid(template), name: template_name(template)) }.uniq
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def templates
|
|
@@ -42,7 +42,8 @@ module ForemanFogProxmox
|
|
|
42
42
|
image = find_vm_by_uuid(image_id)
|
|
43
43
|
validate_image_template_disk_slots!(image, args) if type == 'qemu'
|
|
44
44
|
vm = clone_from_image(image, vmid)
|
|
45
|
-
|
|
45
|
+
cloudinit_args = cloudinit_clone_args(args, vm)
|
|
46
|
+
vm.update(compute_clone_attributes(cloudinit_args, vm.container?, type, image: image))
|
|
46
47
|
update_pool(vm, args[:pool]) if args[:pool]
|
|
47
48
|
else
|
|
48
49
|
logger.warn("create vm: args=#{args}")
|
|
@@ -71,7 +72,6 @@ module ForemanFogProxmox
|
|
|
71
72
|
end
|
|
72
73
|
|
|
73
74
|
def compute_clone_attributes(args, container, type, image: nil)
|
|
74
|
-
args = parse_cloudinit_config(args) if args[:user_data]
|
|
75
75
|
args[:config_attributes].merge!(update_boot_order(image)) if image && args[:config_attributes]
|
|
76
76
|
parsed_args = parse_typed_vm(args, type)
|
|
77
77
|
if container
|
|
@@ -195,6 +195,17 @@ module ForemanFogProxmox
|
|
|
195
195
|
vm_h[:is_secure_boot] = secure_boot if type == 'qemu' && secure_boot
|
|
196
196
|
end
|
|
197
197
|
|
|
198
|
+
def add_image_attribute(vm_h, options)
|
|
199
|
+
image_id = options['image_id']
|
|
200
|
+
vm_h[:image_id] = image_id if image_id.present?
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def add_iso_upload_storage_attribute(vm_h, options, type)
|
|
204
|
+
iso_upload_storage = options['iso_upload_storage']
|
|
205
|
+
vm_h[:iso_upload_storage] = iso_upload_storage if type == 'qemu' && iso_upload_storage.present?
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# rubocop:disable Metrics/AbcSize
|
|
198
209
|
def new_typed_vm(new_attr, type)
|
|
199
210
|
convert_config_attributes(new_attr) if new_attr.key?(:config_attributes)
|
|
200
211
|
node_id = new_attr['node_id']
|
|
@@ -210,11 +221,14 @@ module ForemanFogProxmox
|
|
|
210
221
|
logger.debug("new_typed_vm(#{type}): options=#{options}")
|
|
211
222
|
vm_h = parse_typed_vm(options, type).deep_symbolize_keys
|
|
212
223
|
add_secure_boot_attribute(vm_h, options, type)
|
|
224
|
+
add_image_attribute(vm_h, options)
|
|
225
|
+
add_iso_upload_storage_attribute(vm_h, options, type)
|
|
213
226
|
logger.debug("new_typed_vm(#{type}): vm_h=#{vm_h}")
|
|
214
227
|
vm_h = vm_h.merge(vm_typed_instance_defaults(type)) if vm_h.empty?
|
|
215
228
|
logger.debug(format(_('new_typed_vm(%<type>s) with vm_typed_instance_defaults: vm_h=%<vm_h>s'), type: type, vm_h: vm_h))
|
|
216
229
|
node.send(vm_collection(type)).new(vm_h)
|
|
217
230
|
end
|
|
231
|
+
# rubocop:enable Metrics/AbcSize
|
|
218
232
|
end
|
|
219
233
|
end
|
|
220
234
|
|
data/app/views/compute_resources_vms/form/proxmox/_add_react_component_to_host_form.html.erb
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
<% content_for(:stylesheets) do %>
|
|
2
|
+
<%= stylesheet_link_tag 'foreman_fog_proxmox/network_interface_modal' %>
|
|
3
|
+
<% end %>
|
|
4
|
+
|
|
1
5
|
<% content_for(:javascripts) do %>
|
|
6
|
+
<%= javascript_include_tag 'foreman_fog_proxmox/proxmox_network_interface_modal' %>
|
|
2
7
|
<%= webpacked_plugins_js_for :foreman_fog_proxmox %>
|
|
3
8
|
<% end %>
|
|
4
9
|
<%= react_component('ProxmoxVmType', { registerComp: true }) unless @host.managed %>
|
|
@@ -20,12 +20,13 @@ along with ForemanFogProxmox. If not, see <http://www.gnu.org/licenses/>. %>
|
|
|
20
20
|
<% vm_type = vm_type_and_node_id[:vm_type] %>
|
|
21
21
|
<% node_id = vm_type_and_node_id[:node_id] %>
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
<div class="proxmox-interface-form">
|
|
24
|
+
<%= f.fields_for 'compute_attributes', OpenStruct.new(compute_attributes) do |f| %>
|
|
25
|
+
<%= 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
|
+
<% end %>
|
|
27
|
+
</div>
|
|
26
28
|
<% else %>
|
|
27
29
|
<%= f.fields_for 'compute_attributes', OpenStruct.new(f.object.compute_attributes) do |f| %>
|
|
28
30
|
<%= render provider_partial(@host.compute_resource, 'network'), :f => f, :disabled => f.object.persisted?, :compute_resource => @host.compute_resource, :new_host => new_vm, :new_vm => new_vm %>
|
|
29
31
|
<% end %>
|
|
30
32
|
<% end %>
|
|
31
|
-
|
|
@@ -40,7 +40,14 @@ module ForemanFogProxmox
|
|
|
40
40
|
register_global_js_file 'global'
|
|
41
41
|
# Register Proxmox VE compute resource in foreman
|
|
42
42
|
compute_resource ForemanFogProxmox::Proxmox
|
|
43
|
-
parameter_filter
|
|
43
|
+
parameter_filter ComputeResource,
|
|
44
|
+
:uuid,
|
|
45
|
+
:ssl_verify_peer,
|
|
46
|
+
:ssl_certs,
|
|
47
|
+
:disable_proxy,
|
|
48
|
+
:auth_method,
|
|
49
|
+
:token_id,
|
|
50
|
+
:token
|
|
44
51
|
# add dashboard widget
|
|
45
52
|
widget 'foreman_fog_proxmox_widget', name: N_('Foreman Fog Proxmox widget'), sizex: 8, sizey: 1
|
|
46
53
|
|
|
@@ -111,7 +118,6 @@ module ForemanFogProxmox
|
|
|
111
118
|
Fog::Proxmox::Compute::Interface.include FogExtensions::Proxmox::Interface
|
|
112
119
|
Fog::Proxmox::Compute::Disk.include FogExtensions::Proxmox::Disk
|
|
113
120
|
Fog::Proxmox::Compute::Node.include FogExtensions::Proxmox::Node
|
|
114
|
-
::ComputeResourcesController.include ForemanFogProxmox::Controller::Parameters::ComputeResource
|
|
115
121
|
::ComputeResourcesVmsController.include ForemanFogProxmox::ComputeResourcesVmsController
|
|
116
122
|
::HostsController.include ForemanFogProxmox::HostsController
|
|
117
123
|
::Host::Managed.include Orchestration::Proxmox::Compute
|
|
@@ -79,6 +79,18 @@ module ForemanFogProxmox
|
|
|
79
79
|
assert_instance_of Array, json_response
|
|
80
80
|
end
|
|
81
81
|
test 'should get metadata' do
|
|
82
|
+
node_a = stub(node: 'node-a')
|
|
83
|
+
node_b = stub(node: 'node-b')
|
|
84
|
+
node_a_storages = [{ storage: 'shared-iso', content: 'iso', avail: 100, used: 20, total: 120, shared: 1 }]
|
|
85
|
+
node_b_storages = [{ storage: 'local', content: 'iso', avail: 200, used: 30, total: 230, shared: 0 }]
|
|
86
|
+
node_a_bridges = [{ iface: 'vmbr0' }]
|
|
87
|
+
node_b_bridges = [{ iface: 'vmbr1' }]
|
|
88
|
+
@compute_resource.stubs(:nodes).returns([node_a, node_b])
|
|
89
|
+
@compute_resource.expects(:storages).with('node-a').returns(node_a_storages)
|
|
90
|
+
@compute_resource.expects(:storages).with('node-b').returns(node_b_storages)
|
|
91
|
+
@compute_resource.expects(:bridges).with('node-a').returns(node_a_bridges)
|
|
92
|
+
@compute_resource.expects(:bridges).with('node-b').returns(node_b_bridges)
|
|
93
|
+
|
|
82
94
|
get :metadata, params: { :compute_resource_id => @compute_resource.id }, session: set_session_user
|
|
83
95
|
assert_response :success
|
|
84
96
|
show_response = @response.body
|
|
@@ -93,6 +105,35 @@ module ForemanFogProxmox
|
|
|
93
105
|
assert_instance_of Array, json_response['pools']
|
|
94
106
|
assert_instance_of Array, json_response['storages']
|
|
95
107
|
assert_instance_of Array, json_response['bridges']
|
|
108
|
+
assert_equal ['node-a', 'node-b'], (json_response['storages'].map { |storage| storage['node_id'] })
|
|
109
|
+
assert_equal [1, 0], (json_response['storages'].map { |storage| storage['shared'] })
|
|
110
|
+
assert_equal ['node-a', 'node-b'], (json_response['bridges'].map { |bridge| bridge['node_id'] })
|
|
111
|
+
assert_equal ['vmbr0', 'vmbr1'], (json_response['bridges'].map { |bridge| bridge['iface'] })
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
test 'metadata includes shared storage for every node where it is available' do
|
|
115
|
+
node_a = stub(node: 'node-a')
|
|
116
|
+
node_b = stub(node: 'node-b')
|
|
117
|
+
shared_storage = {
|
|
118
|
+
storage: 'shared-iso',
|
|
119
|
+
content: 'iso',
|
|
120
|
+
avail: 100,
|
|
121
|
+
used: 20,
|
|
122
|
+
total: 120,
|
|
123
|
+
shared: 1,
|
|
124
|
+
}
|
|
125
|
+
@compute_resource.stubs(:nodes).returns([node_a, node_b])
|
|
126
|
+
@compute_resource.expects(:storages).with('node-a').returns([shared_storage])
|
|
127
|
+
@compute_resource.expects(:storages).with('node-b').returns([shared_storage])
|
|
128
|
+
|
|
129
|
+
get :metadata, params: { :compute_resource_id => @compute_resource.id }, session: set_session_user
|
|
130
|
+
assert_response :success
|
|
131
|
+
json_response = JSON.parse(@response.body)
|
|
132
|
+
|
|
133
|
+
assert_equal [
|
|
134
|
+
['shared-iso', 'node-a'],
|
|
135
|
+
['shared-iso', 'node-b'],
|
|
136
|
+
], (json_response['storages'].map { |storage| [storage['storage'], storage['node_id']] })
|
|
96
137
|
end
|
|
97
138
|
end
|
|
98
139
|
end
|
|
@@ -43,5 +43,18 @@ module ForemanFogProxmox
|
|
|
43
43
|
@cr.clone_from_image(@image, @vmid)
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
|
+
|
|
47
|
+
describe 'available_images' do
|
|
48
|
+
it 'removes duplicates' do
|
|
49
|
+
@cr = FactoryBot.build_stubbed(:proxmox_cr)
|
|
50
|
+
clone = mock('vm')
|
|
51
|
+
clone.stubs(:name).returns('vm-1')
|
|
52
|
+
@cr.stubs(:find_vm_by_uuid).returns(clone)
|
|
53
|
+
template = mock('template')
|
|
54
|
+
template.stubs(:vmid).returns(100).at_least(2)
|
|
55
|
+
@cr.stubs(:templates).returns([template, template])
|
|
56
|
+
assert_equal 1, @cr.available_images.length
|
|
57
|
+
end
|
|
58
|
+
end
|
|
46
59
|
end
|
|
47
60
|
end
|