foreman_ovirt 2.0.2 → 2.0.4
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/Rakefile +2 -17
- data/app/assets/javascripts/foreman_ovirt/ovirt.js +37 -8
- data/app/controllers/concerns/foreman_ovirt/api_compute_resources_controller_extension.rb +42 -0
- data/app/controllers/concerns/foreman_ovirt/compute_resources_vms_controller.rb +3 -1
- data/app/controllers/concerns/foreman_ovirt/parameters_extension.rb +5 -5
- data/app/controllers/foreman_ovirt/concerns/compute_resources_controller_extensions.rb +12 -3
- data/app/helpers/ovirt_compute_resource_helper.rb +18 -4
- data/app/models/concerns/fog_extensions/ovirt/server.rb +13 -4
- data/app/models/concerns/fog_extensions/ovirt/template.rb +3 -1
- data/app/models/concerns/fog_extensions/ovirt/volume.rb +3 -1
- data/app/models/foreman_ovirt/ovirt.rb +167 -142
- data/app/views/api/v2/compute_resources/ovirt.json.rabl +2 -0
- data/config/routes.rb +8 -5
- data/db/migrate/20250810212811_update_legacy_ovirt_compute_resource_type.rb +5 -3
- data/lib/foreman_ovirt/engine.rb +8 -5
- data/lib/foreman_ovirt/version.rb +3 -1
- data/lib/foreman_ovirt.rb +2 -0
- data/lib/tasks/foreman_ovirt_tasks.rake +37 -22
- data/locale/gemspec.rb +3 -1
- data/package.json +1 -0
- data/test/controllers/api/v2/compute_resources_controller_test.rb +186 -0
- data/test/controllers/hosts_controller_test.rb +46 -0
- data/test/factories/foreman_ovirt_factories.rb +27 -2
- data/test/fixtures/ovirt_operating_systems.xml +243 -0
- data/test/graphql/types/provider_enum_test.rb +12 -0
- data/test/integration/compute_profile_js_test.rb +49 -0
- data/test/models/compute_resources/compute_resource_test_helpers.rb +143 -0
- data/test/models/compute_resources/ovirt_test.rb +687 -0
- data/test/models/ovirt_volume_test.rb +104 -0
- data/test/test_plugin_helper.rb +2 -0
- data/test/unit/compute_resource_host_importer_test.rb +48 -0
- data/test/unit/ovirt_connection_test.rb +123 -0
- data/webpack/components/__tests__/ovirt.test.js +17 -0
- data/webpack/components/extensions/HostDetails/DetailsTabCards/OvirtCard.js +40 -38
- data/webpack/global_index.js +0 -2
- data/webpack/global_test_setup.js +3 -3
- data/webpack/index.js +0 -1
- metadata +26 -8
- data/test/unit/foreman_ovirt_test.rb +0 -11
|
@@ -1,21 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'foreman/exception'
|
|
2
4
|
require 'uri'
|
|
3
5
|
|
|
4
6
|
module ForemanOvirt
|
|
5
7
|
class Ovirt < ComputeResource
|
|
6
|
-
ALLOWED_DISPLAY_TYPES = %w
|
|
8
|
+
ALLOWED_DISPLAY_TYPES = %w[vnc spice].freeze
|
|
7
9
|
|
|
8
|
-
validates :url, :
|
|
9
|
-
:
|
|
10
|
-
validates :display_type, :
|
|
11
|
-
validates :keyboard_layout, :
|
|
12
|
-
validates :user, :password, :
|
|
10
|
+
validates :url, format: { with: URI::DEFAULT_PARSER.make_regexp }, presence: true,
|
|
11
|
+
url_schema: %w[http https]
|
|
12
|
+
validates :display_type, inclusion: { in: ALLOWED_DISPLAY_TYPES }
|
|
13
|
+
validates :keyboard_layout, inclusion: { in: ALLOWED_KEYBOARD_LAYOUTS }
|
|
14
|
+
validates :user, :password, presence: true
|
|
13
15
|
after_validation :connect, :update_available_operating_systems unless Rails.env.test?
|
|
14
16
|
before_save :validate_quota
|
|
15
17
|
|
|
16
18
|
alias_attribute :datacenter, :uuid
|
|
17
19
|
|
|
18
|
-
delegate :clusters, :quotas, :templates, :instance_types, :
|
|
20
|
+
delegate :clusters, :quotas, :templates, :instance_types, to: :client
|
|
19
21
|
|
|
20
22
|
def self.available?
|
|
21
23
|
Fog::Compute.providers.include?(:ovirt)
|
|
@@ -31,12 +33,12 @@ module ForemanOvirt
|
|
|
31
33
|
|
|
32
34
|
def host_compute_attrs(host)
|
|
33
35
|
super.tap do |attrs|
|
|
34
|
-
attrs[:os] = { :
|
|
36
|
+
attrs[:os] = { type: determine_os_type(host) } if supports_operating_systems?
|
|
35
37
|
end
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
def capabilities
|
|
39
|
-
[
|
|
41
|
+
%i[build image new_volume]
|
|
40
42
|
end
|
|
41
43
|
|
|
42
44
|
def find_vm_by_uuid(uuid)
|
|
@@ -44,7 +46,7 @@ module ForemanOvirt
|
|
|
44
46
|
return unless vm
|
|
45
47
|
|
|
46
48
|
vm.define_singleton_method(:vm_template) do
|
|
47
|
-
|
|
49
|
+
template
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
vm
|
|
@@ -67,14 +69,14 @@ module ForemanOvirt
|
|
|
67
69
|
false
|
|
68
70
|
end
|
|
69
71
|
rescue Foreman::FingerprintException
|
|
70
|
-
logger.info
|
|
72
|
+
logger.info 'Unable to verify OS capabilities, SSL certificate verification failed'
|
|
71
73
|
false
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
def determine_os_type(host)
|
|
75
77
|
return nil unless host
|
|
76
78
|
return host.params['ovirt_ostype'] if host.params['ovirt_ostype']
|
|
77
|
-
ret =
|
|
79
|
+
ret = 'other_linux'
|
|
78
80
|
return ret unless host.operatingsystem
|
|
79
81
|
os_name = os_name_mapping(host)
|
|
80
82
|
arch_name = arch_name_mapping(host)
|
|
@@ -98,7 +100,7 @@ module ForemanOvirt
|
|
|
98
100
|
end
|
|
99
101
|
|
|
100
102
|
unless match_found
|
|
101
|
-
logger.debug {
|
|
103
|
+
logger.debug { 'No oVirt OS type found, returning other OS' }
|
|
102
104
|
return available.first[:name]
|
|
103
105
|
end
|
|
104
106
|
|
|
@@ -107,15 +109,12 @@ module ForemanOvirt
|
|
|
107
109
|
end
|
|
108
110
|
|
|
109
111
|
def available_operating_systems
|
|
110
|
-
if attrs.key?(:available_operating_systems)
|
|
111
|
-
|
|
112
|
-
else
|
|
113
|
-
raise Foreman::Exception.new("Listing operating systems is not supported by the current version")
|
|
114
|
-
end
|
|
112
|
+
return attrs[:available_operating_systems] if attrs.key?(:available_operating_systems)
|
|
113
|
+
raise Foreman::Exception, 'Listing operating systems is not supported by the current version'
|
|
115
114
|
end
|
|
116
115
|
|
|
117
116
|
def provided_attributes
|
|
118
|
-
super.merge({:
|
|
117
|
+
super.merge({ mac: :mac })
|
|
119
118
|
end
|
|
120
119
|
|
|
121
120
|
def ovirt_quota=(ovirt_quota_id)
|
|
@@ -132,8 +131,8 @@ module ForemanOvirt
|
|
|
132
131
|
|
|
133
132
|
def image_exists?(image)
|
|
134
133
|
client.templates.get(image).present?
|
|
135
|
-
rescue => e
|
|
136
|
-
Foreman::Logging.exception(
|
|
134
|
+
rescue StandardError => e
|
|
135
|
+
Foreman::Logging.exception('Error while checking if image exists', e)
|
|
137
136
|
false
|
|
138
137
|
end
|
|
139
138
|
|
|
@@ -156,7 +155,7 @@ module ForemanOvirt
|
|
|
156
155
|
def test_https_required
|
|
157
156
|
RestClient.post url, {} if URI(url).scheme == 'http'
|
|
158
157
|
true
|
|
159
|
-
rescue => e
|
|
158
|
+
rescue StandardError => e
|
|
160
159
|
case e.message
|
|
161
160
|
when /406/
|
|
162
161
|
true
|
|
@@ -176,16 +175,16 @@ module ForemanOvirt
|
|
|
176
175
|
|
|
177
176
|
update_public_key options
|
|
178
177
|
datacenters && test_https_required
|
|
179
|
-
rescue => e
|
|
178
|
+
rescue StandardError => e
|
|
180
179
|
case e.message
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
180
|
+
when /404/
|
|
181
|
+
errors.add(:url, e.message)
|
|
182
|
+
when /302/
|
|
183
|
+
errors.add(:url, _('HTTPS URL is required for API access'))
|
|
184
|
+
when /401/
|
|
185
|
+
errors.add(:user, e.message)
|
|
186
|
+
else
|
|
187
|
+
errors.add(:base, e.message)
|
|
189
188
|
end
|
|
190
189
|
end
|
|
191
190
|
|
|
@@ -203,7 +202,7 @@ module ForemanOvirt
|
|
|
203
202
|
@datacenter_uuid = datacenter
|
|
204
203
|
else
|
|
205
204
|
@datacenter_uuid = datacenters.select { |dc| dc[0] == datacenter }
|
|
206
|
-
raise ::Foreman::Exception
|
|
205
|
+
raise ::Foreman::Exception, N_('Datacenter was not found') if @datacenter_uuid.empty?
|
|
207
206
|
@datacenter_uuid = @datacenter_uuid.first[1]
|
|
208
207
|
end
|
|
209
208
|
@datacenter_uuid
|
|
@@ -232,36 +231,37 @@ module ForemanOvirt
|
|
|
232
231
|
end
|
|
233
232
|
|
|
234
233
|
def available_networks(cluster_id = nil)
|
|
235
|
-
raise ::Foreman::Exception
|
|
236
|
-
networks({:cluster_id
|
|
234
|
+
raise ::Foreman::Exception, N_('Cluster ID is required to list available networks') if cluster_id.nil?
|
|
235
|
+
networks({ cluster_id: cluster_id })
|
|
237
236
|
end
|
|
238
237
|
|
|
239
|
-
def available_storage_domains(
|
|
238
|
+
def available_storage_domains(_cluster_id = nil)
|
|
240
239
|
storage_domains
|
|
241
240
|
end
|
|
242
241
|
|
|
243
242
|
def storage_domains(opts = {})
|
|
244
|
-
client.storage_domains({:
|
|
243
|
+
client.storage_domains({ role: %w[data volume] }.merge(opts))
|
|
245
244
|
end
|
|
246
245
|
|
|
247
246
|
def start_vm(uuid)
|
|
248
247
|
vm = find_vm_by_uuid(uuid)
|
|
249
|
-
if
|
|
250
|
-
vm.start_with_cloudinit(:
|
|
248
|
+
if %r{cloud-config|^#!/}.match?(vm.comment.to_s)
|
|
249
|
+
vm.start_with_cloudinit(blocking: true, user_data: vm.comment, use_custom_script: true)
|
|
251
250
|
vm.comment = ''
|
|
252
251
|
vm.save
|
|
253
252
|
else
|
|
254
|
-
vm.start(:
|
|
253
|
+
vm.start(blocking: true)
|
|
255
254
|
end
|
|
256
255
|
end
|
|
257
256
|
|
|
258
257
|
def start_with_cloudinit(uuid, user_data = nil)
|
|
259
|
-
find_vm_by_uuid(uuid).start_with_cloudinit(:
|
|
258
|
+
find_vm_by_uuid(uuid).start_with_cloudinit(blocking: true, user_data: user_data, use_custom_script: true)
|
|
260
259
|
end
|
|
261
260
|
|
|
262
261
|
def sanitize_inherited_vm_attributes(args, template, instance_type)
|
|
263
262
|
# Override memory an cores values if template and/or instance type is/are provided.
|
|
264
|
-
# Take template values if blank values for VM attributes,
|
|
263
|
+
# Take template values if blank values for VM attributes,
|
|
264
|
+
# because oVirt will fail if empty values are present in VM definition
|
|
265
265
|
# Instance type values always take precedence on templates or vm provided values
|
|
266
266
|
if template
|
|
267
267
|
template_cores = template.cores.to_i if template.cores.present?
|
|
@@ -269,14 +269,13 @@ module ForemanOvirt
|
|
|
269
269
|
args[:cores] = template_cores if template_cores && args[:cores].blank?
|
|
270
270
|
args[:memory] = template_memory if template_memory && args[:memory].blank?
|
|
271
271
|
end
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
end
|
|
272
|
+
return unless instance_type
|
|
273
|
+
instance_type_cores = instance_type.cores.to_i if instance_type.cores.present?
|
|
274
|
+
instance_type_sockets = instance_type.sockets.to_i if instance_type.sockets.present?
|
|
275
|
+
instance_type_memory = instance_type.memory.to_i if instance_type.memory.present?
|
|
276
|
+
args[:cores] = instance_type_cores if instance_type_cores
|
|
277
|
+
args[:sockets] = instance_type_sockets if instance_type_sockets
|
|
278
|
+
args[:memory] = instance_type_memory if instance_type_memory
|
|
280
279
|
end
|
|
281
280
|
|
|
282
281
|
def create_vm(args = {})
|
|
@@ -292,12 +291,12 @@ module ForemanOvirt
|
|
|
292
291
|
sanitize_inherited_vm_attributes(args, template, instance_type)
|
|
293
292
|
preallocate_and_clone_disks(args, template) if args[:volumes_attributes].present? && template.present?
|
|
294
293
|
|
|
295
|
-
vm = super({ :
|
|
294
|
+
vm = super({ first_boot_dev: 'network', quota: ovirt_quota }.merge(args))
|
|
296
295
|
|
|
297
296
|
begin
|
|
298
297
|
create_interfaces(vm, args[:interfaces_attributes], args[:cluster]) unless args[:interfaces_attributes].empty?
|
|
299
298
|
create_volumes(vm, args[:volumes_attributes]) unless args[:volumes_attributes].empty?
|
|
300
|
-
rescue => e
|
|
299
|
+
rescue StandardError => e
|
|
301
300
|
destroy_vm vm.id
|
|
302
301
|
raise e
|
|
303
302
|
end
|
|
@@ -306,40 +305,45 @@ module ForemanOvirt
|
|
|
306
305
|
|
|
307
306
|
def get_ovirt_id(argument_list, argument_key, argument_value)
|
|
308
307
|
return argument_value if argument_value.blank?
|
|
309
|
-
if argument_list.none?
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
308
|
+
if argument_list.none? do |a|
|
|
309
|
+
a.name == argument_value || a.id == argument_value
|
|
310
|
+
end
|
|
311
|
+
raise Foreman::Exception,
|
|
312
|
+
"The #{argument_key} #{argument_value} is not valid, enter a correct id or name"
|
|
313
313
|
end
|
|
314
|
+
argument_list.detect { |a| a.name == argument_value }.try(:id) || argument_value
|
|
314
315
|
end
|
|
315
316
|
|
|
316
317
|
def preallocate_and_clone_disks(args, template)
|
|
317
318
|
volumes_to_change = args[:volumes_attributes].values.select { |x| x[:id].present? }
|
|
318
|
-
return
|
|
319
|
+
return if volumes_to_change.blank?
|
|
319
320
|
|
|
320
321
|
template_disks = template.volumes
|
|
321
322
|
|
|
322
323
|
disks = volumes_to_change.map do |volume|
|
|
323
324
|
if volume[:preallocate] == '1'
|
|
324
|
-
{:
|
|
325
|
+
{ id: volume[:id], sparse: 'false', format: 'raw', storage_domain: volume[:storage_domain] }
|
|
325
326
|
else
|
|
326
|
-
template_volume = template_disks.detect { |v| v.id == volume[
|
|
327
|
-
|
|
327
|
+
template_volume = template_disks.detect { |v| v.id == volume['id'] }
|
|
328
|
+
if template_volume.storage_domain != volume['storage_domain']
|
|
329
|
+
{ id: volume['id'],
|
|
330
|
+
storage_domain: volume['storage_domain'] }
|
|
331
|
+
end
|
|
328
332
|
end
|
|
329
333
|
end.compact
|
|
330
334
|
|
|
331
|
-
args.merge!(:
|
|
335
|
+
args.merge!(clone: true, disks: disks) if disks.present?
|
|
332
336
|
end
|
|
333
337
|
|
|
334
338
|
def vm_instance_defaults
|
|
335
339
|
super.merge(
|
|
336
|
-
:
|
|
337
|
-
:
|
|
338
|
-
:
|
|
339
|
-
:
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
340
|
+
memory: 1024.megabytes,
|
|
341
|
+
cores: '1',
|
|
342
|
+
sockets: '1',
|
|
343
|
+
display: { type: display_type,
|
|
344
|
+
keyboard_layout: keyboard_layout,
|
|
345
|
+
port: -1,
|
|
346
|
+
monitors: 1 }
|
|
343
347
|
)
|
|
344
348
|
end
|
|
345
349
|
|
|
@@ -347,7 +351,7 @@ module ForemanOvirt
|
|
|
347
351
|
vm = super
|
|
348
352
|
|
|
349
353
|
vm.define_singleton_method(:vm_template) do
|
|
350
|
-
|
|
354
|
+
template
|
|
351
355
|
end
|
|
352
356
|
|
|
353
357
|
vm.define_singleton_method(:vm_template=) do |value|
|
|
@@ -367,7 +371,9 @@ module ForemanOvirt
|
|
|
367
371
|
|
|
368
372
|
def new_volume(attr = {})
|
|
369
373
|
set_preallocated_attributes!(attr, attr[:preallocate])
|
|
370
|
-
raise ::Foreman::Exception
|
|
374
|
+
raise ::Foreman::Exception, N_('VM volume attributes are not set properly') unless attr.all? do |_key, value|
|
|
375
|
+
value.is_a? String
|
|
376
|
+
end
|
|
371
377
|
Fog::Ovirt::Compute::Volume.new(attr)
|
|
372
378
|
end
|
|
373
379
|
|
|
@@ -394,29 +400,30 @@ module ForemanOvirt
|
|
|
394
400
|
def parse_vms_list_params(params)
|
|
395
401
|
max = (params['length'] || 10).to_i
|
|
396
402
|
{
|
|
397
|
-
:
|
|
398
|
-
:
|
|
399
|
-
:
|
|
400
|
-
:
|
|
403
|
+
search: params['search']['value'] || '',
|
|
404
|
+
max: max,
|
|
405
|
+
page: (params['start'].to_i / max) + 1,
|
|
406
|
+
without_details: true,
|
|
401
407
|
}
|
|
402
408
|
end
|
|
403
409
|
|
|
404
410
|
def console(uuid)
|
|
405
411
|
vm = find_vm_by_uuid(uuid)
|
|
406
|
-
raise
|
|
412
|
+
raise 'VM is not running!' if vm.status == 'down'
|
|
407
413
|
opts = if vm.display[:secure_port]
|
|
408
|
-
{ :
|
|
414
|
+
{ host_port: vm.display[:secure_port], ssl_target: true }
|
|
409
415
|
else
|
|
410
|
-
{ :
|
|
416
|
+
{ host_port: vm.display[:port] }
|
|
411
417
|
end
|
|
412
|
-
WsProxy.start(opts.merge(:
|
|
418
|
+
WsProxy.start(opts.merge(host: vm.display[:address], password: vm.ticket)).merge(name: vm.name,
|
|
419
|
+
type: vm.display[:type])
|
|
413
420
|
end
|
|
414
421
|
|
|
415
422
|
def update_required?(old_attrs, new_attrs)
|
|
416
423
|
return true if super(old_attrs, new_attrs)
|
|
417
424
|
|
|
418
425
|
new_attrs[:interfaces_attributes]&.each do |key, interface|
|
|
419
|
-
return true if (interface[:id].blank? || interface[:_delete] == '1') && key != 'new_interfaces'
|
|
426
|
+
return true if (interface[:id].blank? || interface[:_delete] == '1') && key != 'new_interfaces'
|
|
420
427
|
end
|
|
421
428
|
|
|
422
429
|
new_attrs[:volumes_attributes]&.each do |key, volume|
|
|
@@ -427,11 +434,11 @@ module ForemanOvirt
|
|
|
427
434
|
end
|
|
428
435
|
|
|
429
436
|
def associated_host(vm)
|
|
430
|
-
associate_by(
|
|
437
|
+
associate_by('mac', vm.interfaces.map(&:mac))
|
|
431
438
|
end
|
|
432
439
|
|
|
433
440
|
def self.provider_friendly_name
|
|
434
|
-
|
|
441
|
+
'oVirt'
|
|
435
442
|
end
|
|
436
443
|
|
|
437
444
|
def display_type
|
|
@@ -459,31 +466,33 @@ module ForemanOvirt
|
|
|
459
466
|
end
|
|
460
467
|
|
|
461
468
|
def normalize_vm_attrs(vm_attrs)
|
|
462
|
-
normalized = slice_vm_attributes(vm_attrs, [
|
|
469
|
+
normalized = slice_vm_attributes(vm_attrs, %w[cores interfaces_attributes memory])
|
|
463
470
|
normalized['cluster_id'] = get_ovirt_id(clusters, 'cluster', vm_attrs['cluster'])
|
|
464
471
|
normalized['cluster_name'] = clusters.detect { |c| c.id == normalized['cluster_id'] }.try(:name)
|
|
465
472
|
|
|
466
473
|
normalized['template_id'] = get_ovirt_id(templates, 'template', vm_attrs['template'])
|
|
467
474
|
normalized['template_name'] = templates.detect { |t| t.id == normalized['template_id'] }.try(:name)
|
|
468
475
|
|
|
469
|
-
cluster_networks = networks(:
|
|
476
|
+
cluster_networks = networks(cluster_id: normalized['cluster_id'])
|
|
470
477
|
|
|
471
478
|
interface_attrs = vm_attrs['interfaces_attributes'] || {}
|
|
472
479
|
normalized['interfaces_attributes'] = interface_attrs.inject({}) do |interfaces, (key, nic)|
|
|
473
480
|
interfaces.update(key => { 'name' => nic['name'],
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
481
|
+
'network_id' => nic['network'],
|
|
482
|
+
'network_name' => cluster_networks.detect do |n|
|
|
483
|
+
n.id == nic['network']
|
|
484
|
+
end.try(:name) })
|
|
477
485
|
end
|
|
478
486
|
|
|
479
487
|
volume_attrs = vm_attrs['volumes_attributes'] || {}
|
|
480
488
|
normalized['volumes_attributes'] = volume_attrs.inject({}) do |volumes, (key, vol)|
|
|
481
489
|
volumes.update(key => { 'size' => memory_gb_to_bytes(vol['size_gb']).to_s,
|
|
482
490
|
'storage_domain_id' => vol['storage_domain'],
|
|
483
|
-
'storage_domain_name' => storage_domains.detect
|
|
491
|
+
'storage_domain_name' => storage_domains.detect do |d|
|
|
492
|
+
d.id == vol['storage_domain']
|
|
493
|
+
end.try(:name),
|
|
484
494
|
'preallocate' => to_bool(vol['preallocate']),
|
|
485
|
-
'bootable' => to_bool(vol['bootable'])
|
|
486
|
-
})
|
|
495
|
+
'bootable' => to_bool(vol['bootable']) })
|
|
487
496
|
end
|
|
488
497
|
|
|
489
498
|
normalized
|
|
@@ -491,19 +500,19 @@ module ForemanOvirt
|
|
|
491
500
|
|
|
492
501
|
def nictypes
|
|
493
502
|
[
|
|
494
|
-
OpenStruct.new({:
|
|
495
|
-
OpenStruct.new({:
|
|
496
|
-
OpenStruct.new({:
|
|
497
|
-
OpenStruct.new({:
|
|
503
|
+
OpenStruct.new({ id: 'virtio', name: 'VirtIO' }),
|
|
504
|
+
OpenStruct.new({ id: 'rtl8139', name: 'rtl8139' }),
|
|
505
|
+
OpenStruct.new({ id: 'e1000', name: 'e1000' }),
|
|
506
|
+
OpenStruct.new({ id: 'pci_passthrough', name: 'PCI Passthrough' }),
|
|
498
507
|
]
|
|
499
508
|
end
|
|
500
509
|
|
|
501
510
|
def validate_quota
|
|
502
|
-
if attrs[:ovirt_quota_id].nil?
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
511
|
+
attrs[:ovirt_quota_id] = if attrs[:ovirt_quota_id].nil?
|
|
512
|
+
client.quotas.first.id
|
|
513
|
+
else
|
|
514
|
+
get_ovirt_id(client.quotas, 'quota', attrs[:ovirt_quota_id])
|
|
515
|
+
end
|
|
507
516
|
end
|
|
508
517
|
|
|
509
518
|
protected
|
|
@@ -511,7 +520,7 @@ module ForemanOvirt
|
|
|
511
520
|
def bootstrap(args)
|
|
512
521
|
client.servers.bootstrap vm_instance_defaults.merge(args.to_h)
|
|
513
522
|
rescue Fog::Errors::Error => e
|
|
514
|
-
Foreman::Logging.exception(
|
|
523
|
+
Foreman::Logging.exception('Failed to bootstrap vm', e)
|
|
515
524
|
errors.add(:base, e.to_s)
|
|
516
525
|
false
|
|
517
526
|
end
|
|
@@ -519,23 +528,25 @@ module ForemanOvirt
|
|
|
519
528
|
def client
|
|
520
529
|
return @client if @client
|
|
521
530
|
client = ::Fog::Compute.new(
|
|
522
|
-
:
|
|
523
|
-
:
|
|
524
|
-
:
|
|
525
|
-
:
|
|
526
|
-
:
|
|
527
|
-
:
|
|
528
|
-
:
|
|
529
|
-
:
|
|
531
|
+
provider: 'ovirt',
|
|
532
|
+
ovirt_username: user,
|
|
533
|
+
ovirt_password: password,
|
|
534
|
+
ovirt_url: url,
|
|
535
|
+
ovirt_datacenter: uuid,
|
|
536
|
+
ovirt_ca_cert_store: ca_cert_store(public_key),
|
|
537
|
+
public_key: public_key,
|
|
538
|
+
api_version: 'v4'
|
|
530
539
|
)
|
|
531
540
|
client.datacenters
|
|
532
541
|
@client = client
|
|
533
|
-
rescue => e
|
|
542
|
+
rescue StandardError => e
|
|
534
543
|
if e.message =~ /SSL_connect.*certificate verify failed/ ||
|
|
535
|
-
|
|
536
|
-
|
|
544
|
+
e.message =~ /Peer certificate cannot be authenticated with given CA certificates/ ||
|
|
545
|
+
e.message =~ /SSL peer certificate or SSH remote key was not OK/
|
|
537
546
|
raise Foreman::FingerprintException.new(
|
|
538
|
-
N_(
|
|
547
|
+
N_('The remote system presented a public key signed by an unidentified certificate authority. ' \
|
|
548
|
+
'If you are sure the remote system is authentic, go to the compute resource edit page, ' \
|
|
549
|
+
"press the 'Test Connection' or 'Load Datacenters' button and submit"),
|
|
539
550
|
ca_cert
|
|
540
551
|
)
|
|
541
552
|
else
|
|
@@ -561,8 +572,8 @@ module ForemanOvirt
|
|
|
561
572
|
store.add_cert(OpenSSL::X509::Certificate.new(cert))
|
|
562
573
|
end
|
|
563
574
|
store
|
|
564
|
-
rescue => e
|
|
565
|
-
raise _(
|
|
575
|
+
rescue StandardError => e
|
|
576
|
+
raise _(format('Failed to create X509 certificate, error: %s', e.message))
|
|
566
577
|
end
|
|
567
578
|
|
|
568
579
|
def fetch_unverified(path, query = '')
|
|
@@ -577,13 +588,14 @@ module ForemanOvirt
|
|
|
577
588
|
# response might be 404 or some other normal code,
|
|
578
589
|
# that would not trigger any exception so we rather check what kind of response we got
|
|
579
590
|
response.is_a?(Net::HTTPSuccess) ? response.body : nil
|
|
580
|
-
rescue => e
|
|
591
|
+
rescue StandardError => e
|
|
581
592
|
Foreman::Logging.exception("Unable to fetch CA certificate on path #{path}: #{e}", e)
|
|
582
593
|
nil
|
|
583
594
|
end
|
|
584
595
|
|
|
585
596
|
def ca_cert
|
|
586
|
-
fetch_unverified(
|
|
597
|
+
fetch_unverified('/ovirt-engine/services/pki-resource',
|
|
598
|
+
'resource=ca-certificate&format=X509-PEM-CA') || fetch_unverified('/ca.crt')
|
|
587
599
|
end
|
|
588
600
|
|
|
589
601
|
private
|
|
@@ -593,17 +605,14 @@ module ForemanOvirt
|
|
|
593
605
|
ovirt_operating_systems = client.operating_systems if client.respond_to?(:operating_systems)
|
|
594
606
|
|
|
595
607
|
attrs[:available_operating_systems] = ovirt_operating_systems.map do |os|
|
|
596
|
-
{ :
|
|
608
|
+
{ id: os.id, name: os.name, href: os.href }
|
|
597
609
|
end
|
|
598
610
|
rescue Foreman::FingerprintException
|
|
599
|
-
logger.info
|
|
611
|
+
logger.info 'Unable to verify OS capabilities, SSL certificate verification failed'
|
|
600
612
|
true
|
|
601
613
|
rescue Fog::Ovirt::Errors::OvirtEngineError => e
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
else
|
|
605
|
-
raise e
|
|
606
|
-
end
|
|
614
|
+
raise e unless /404/.match?(e.message)
|
|
615
|
+
attrs[:available_operating_systems] ||= :unsupported
|
|
607
616
|
end
|
|
608
617
|
|
|
609
618
|
def os_name_mapping(host)
|
|
@@ -617,7 +626,7 @@ module ForemanOvirt
|
|
|
617
626
|
|
|
618
627
|
def default_iface_name(interfaces)
|
|
619
628
|
nic_name_num = 1
|
|
620
|
-
name_blacklist = interfaces.map { |i| i[:name] }.reject
|
|
629
|
+
name_blacklist = interfaces.map { |i| i[:name] }.reject(&:blank?)
|
|
621
630
|
nic_name_num += 1 while name_blacklist.include?("nic#{nic_name_num}")
|
|
622
631
|
"nic#{nic_name_num}"
|
|
623
632
|
end
|
|
@@ -626,19 +635,30 @@ module ForemanOvirt
|
|
|
626
635
|
# first remove all existing interfaces
|
|
627
636
|
vm.interfaces&.each do |interface|
|
|
628
637
|
# The blocking true is a work-around for ovirt bug, it should be removed.
|
|
629
|
-
vm.destroy_interface(:
|
|
638
|
+
vm.destroy_interface(id: interface.id, blocking: true)
|
|
630
639
|
end
|
|
631
640
|
# add interfaces
|
|
632
|
-
cluster_networks = networks(:
|
|
641
|
+
cluster_networks = networks(cluster_id: cluster_id)
|
|
633
642
|
profiles = vnic_profiles
|
|
634
643
|
interfaces = nested_attributes_for :interfaces, attrs
|
|
635
644
|
interfaces.map do |interface|
|
|
636
645
|
interface[:name] = default_iface_name(interfaces) if interface[:name].empty?
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
646
|
+
if interface[:network].nil? && interface[:vnic_profile].nil?
|
|
647
|
+
raise Foreman::Exception,
|
|
648
|
+
'Interface network or vnic profile are missing.'
|
|
649
|
+
end
|
|
650
|
+
if interface[:network].present?
|
|
651
|
+
interface[:network] =
|
|
652
|
+
get_ovirt_id(cluster_networks, 'network', interface[:network])
|
|
653
|
+
end
|
|
654
|
+
if interface[:vnic_profile].present?
|
|
655
|
+
interface[:vnic_profile] =
|
|
656
|
+
get_ovirt_id(profiles, 'vnic profile', interface[:vnic_profile])
|
|
657
|
+
end
|
|
658
|
+
if interface[:network].present? && interface[:vnic_profile].present? && profiles.none? do |profile|
|
|
659
|
+
profile.network.id == interface[:network]
|
|
660
|
+
end
|
|
661
|
+
raise Foreman::Exception, 'Vnic Profile have a different network'
|
|
642
662
|
end
|
|
643
663
|
vm.add_interface(interface)
|
|
644
664
|
end
|
|
@@ -649,15 +669,14 @@ module ForemanOvirt
|
|
|
649
669
|
# add volumes
|
|
650
670
|
volumes = nested_attributes_for :volumes, attrs
|
|
651
671
|
volumes.map do |vol|
|
|
652
|
-
if vol[:id].
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
end
|
|
672
|
+
next if vol[:id].present?
|
|
673
|
+
set_preallocated_attributes!(vol, vol[:preallocate])
|
|
674
|
+
vol[:wipe_after_delete] = to_fog_ovirt_boolean(vol[:wipe_after_delete])
|
|
675
|
+
vol[:storage_domain] = get_ovirt_id(storage_domains, 'storage domain', vol[:storage_domain])
|
|
676
|
+
# The blocking true is a work-around for ovirt bug fixed in ovirt version 5.1
|
|
677
|
+
# The BZ in ovirt cause to the destruction of a host in foreman to fail in case a volume is locked
|
|
678
|
+
# Here we are enforcing blocking behavior which will wait until the volume is added
|
|
679
|
+
vm.add_volume({ bootable: 'false', quota: ovirt_quota, blocking: api_version.to_f < 5.1 }.merge(vol))
|
|
661
680
|
end
|
|
662
681
|
vm.volumes.reload
|
|
663
682
|
end
|
|
@@ -685,7 +704,7 @@ module ForemanOvirt
|
|
|
685
704
|
def update_interfaces(vm, attrs)
|
|
686
705
|
interfaces = nested_attributes_for :interfaces, attrs
|
|
687
706
|
interfaces.each do |interface|
|
|
688
|
-
vm.destroy_interface(:
|
|
707
|
+
vm.destroy_interface(id: interface[:id]) if interface[:_delete] == '1' && interface[:id]
|
|
689
708
|
if interface[:id].blank?
|
|
690
709
|
interface[:name] = default_iface_name(interfaces) if interface[:name].empty?
|
|
691
710
|
vm.add_interface(interface)
|
|
@@ -696,8 +715,14 @@ module ForemanOvirt
|
|
|
696
715
|
def update_volumes(vm, attrs)
|
|
697
716
|
volumes = nested_attributes_for :volumes, attrs
|
|
698
717
|
volumes.each do |volume|
|
|
699
|
-
|
|
700
|
-
|
|
718
|
+
if volume[:_delete] == '1' && volume[:id].present?
|
|
719
|
+
vm.destroy_volume(id: volume[:id],
|
|
720
|
+
blocking: api_version.to_f < 3.1)
|
|
721
|
+
end
|
|
722
|
+
if volume[:id].blank?
|
|
723
|
+
vm.add_volume({ bootable: 'false', quota: ovirt_quota,
|
|
724
|
+
blocking: api_version.to_f < 3.1 }.merge(volume))
|
|
725
|
+
end
|
|
701
726
|
end
|
|
702
727
|
end
|
|
703
728
|
|
|
@@ -730,7 +755,7 @@ module ForemanOvirt
|
|
|
730
755
|
|
|
731
756
|
def volume_to_attributes(volume, template_volumes)
|
|
732
757
|
{
|
|
733
|
-
size_gb: (volume.size.to_i / 1.gigabyte),
|
|
758
|
+
size_gb: (volume.size.to_i / 1.gigabyte).to_s,
|
|
734
759
|
storage_domain: volume.storage_domain,
|
|
735
760
|
preallocate: (volume.sparse == 'true') ? '0' : '1',
|
|
736
761
|
wipe_after_delete: volume.wipe_after_delete,
|