opennebula 6.10.3 → 6.99.85.pre
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/lib/cloud/CloudClient.rb +3 -3
- data/lib/models/role.rb +349 -823
- data/lib/models/service.rb +156 -80
- data/lib/models/vmrole.rb +703 -0
- data/lib/models/vrrole.rb +284 -0
- data/lib/models.rb +3 -1
- data/lib/opennebula/acl.rb +1 -1
- data/lib/opennebula/acl_pool.rb +1 -1
- data/lib/opennebula/backupjob.rb +1 -1
- data/lib/opennebula/backupjob_pool.rb +1 -1
- data/lib/opennebula/client.rb +1 -1
- data/lib/opennebula/cluster.rb +45 -2
- data/lib/opennebula/cluster_pool.rb +1 -1
- data/lib/opennebula/datastore.rb +1 -1
- data/lib/opennebula/datastore_pool.rb +1 -1
- data/lib/opennebula/document.rb +1 -1
- data/lib/opennebula/document_json.rb +1 -1
- data/lib/opennebula/document_pool.rb +1 -1
- data/lib/opennebula/document_pool_json.rb +1 -1
- data/lib/opennebula/error.rb +1 -1
- data/lib/opennebula/flow/grammar.rb +1 -1
- data/lib/opennebula/flow/service_pool.rb +1 -1
- data/lib/opennebula/flow/service_template.rb +353 -97
- data/lib/opennebula/flow/service_template_ext.rb +3 -3
- data/lib/opennebula/flow/service_template_pool.rb +1 -1
- data/lib/opennebula/flow/validator.rb +458 -410
- data/lib/opennebula/flow.rb +1 -1
- data/lib/opennebula/group.rb +1 -1
- data/lib/opennebula/group_pool.rb +1 -1
- data/lib/opennebula/hook.rb +1 -1
- data/lib/opennebula/hook_log.rb +1 -1
- data/lib/opennebula/hook_pool.rb +1 -1
- data/lib/opennebula/host.rb +1 -60
- data/lib/opennebula/host_pool.rb +1 -1
- data/lib/opennebula/image.rb +1 -1
- data/lib/opennebula/image_pool.rb +1 -1
- data/lib/opennebula/ldap_auth.rb +1 -1
- data/lib/opennebula/ldap_auth_spec.rb +1 -1
- data/lib/opennebula/lockable_ext.rb +1 -1
- data/lib/opennebula/marketplace.rb +1 -1
- data/lib/opennebula/marketplace_pool.rb +1 -1
- data/lib/opennebula/marketplaceapp.rb +1 -1
- data/lib/opennebula/marketplaceapp_ext.rb +14 -211
- data/lib/opennebula/marketplaceapp_pool.rb +1 -1
- data/lib/opennebula/oneflow_client.rb +11 -9
- data/lib/opennebula/pool.rb +1 -1
- data/lib/opennebula/pool_element.rb +1 -1
- data/lib/opennebula/security_group.rb +1 -1
- data/lib/opennebula/security_group_pool.rb +1 -1
- data/lib/opennebula/server_cipher_auth.rb +1 -1
- data/lib/opennebula/server_x509_auth.rb +1 -1
- data/lib/opennebula/ssh_auth.rb +1 -1
- data/lib/opennebula/system.rb +1 -1
- data/lib/opennebula/template.rb +1 -1
- data/lib/opennebula/template_ext.rb +1 -1
- data/lib/opennebula/template_pool.rb +1 -1
- data/lib/opennebula/user.rb +1 -1
- data/lib/opennebula/user_pool.rb +1 -1
- data/lib/opennebula/utils.rb +2 -2
- data/lib/opennebula/vdc.rb +1 -1
- data/lib/opennebula/vdc_pool.rb +1 -1
- data/lib/opennebula/virtual_machine.rb +3 -12
- data/lib/opennebula/virtual_machine_ext.rb +2 -31
- data/lib/opennebula/virtual_machine_pool.rb +1 -1
- data/lib/opennebula/virtual_network.rb +1 -1
- data/lib/opennebula/virtual_network_pool.rb +1 -1
- data/lib/opennebula/virtual_router.rb +1 -1
- data/lib/opennebula/virtual_router_pool.rb +1 -1
- data/lib/opennebula/vm_group.rb +1 -1
- data/lib/opennebula/vm_group_pool.rb +1 -1
- data/lib/opennebula/vntemplate.rb +1 -1
- data/lib/opennebula/vntemplate_pool.rb +1 -1
- data/lib/opennebula/wait_ext.rb +1 -1
- data/lib/opennebula/x509_auth.rb +1 -1
- data/lib/opennebula/xml_element.rb +2 -2
- data/lib/opennebula/xml_pool.rb +1 -1
- data/lib/opennebula/xml_utils.rb +1 -1
- data/lib/opennebula/zone.rb +1 -1
- data/lib/opennebula/zone_pool.rb +1 -1
- data/lib/opennebula.rb +2 -2
- metadata +6 -67
- data/lib/ActionManager.rb +0 -280
- data/lib/CommandManager.rb +0 -328
- data/lib/DriverExecHelper.rb +0 -213
- data/lib/HostSyncManager.rb +0 -111
- data/lib/OpenNebulaDriver.rb +0 -223
- data/lib/VirtualMachineDriver.rb +0 -404
- data/lib/datacenter.rb +0 -1319
- data/lib/datastore.rb +0 -1049
- data/lib/distributed_firewall.rb +0 -293
- data/lib/file_helper.rb +0 -374
- data/lib/host.rb +0 -1518
- data/lib/logical_port.rb +0 -50
- data/lib/logical_switch.rb +0 -77
- data/lib/memoize.rb +0 -74
- data/lib/network.rb +0 -705
- data/lib/nsx_client.rb +0 -157
- data/lib/nsx_component.rb +0 -28
- data/lib/nsx_constants.rb +0 -162
- data/lib/nsx_driver.rb +0 -91
- data/lib/nsx_error.rb +0 -77
- data/lib/nsx_rule.rb +0 -206
- data/lib/nsxt_client.rb +0 -189
- data/lib/nsxt_dfw.rb +0 -196
- data/lib/nsxt_logical_port.rb +0 -94
- data/lib/nsxt_rule.rb +0 -188
- data/lib/nsxt_tz.rb +0 -38
- data/lib/nsxv_client.rb +0 -189
- data/lib/nsxv_dfw.rb +0 -202
- data/lib/nsxv_logical_port.rb +0 -107
- data/lib/nsxv_rule.rb +0 -172
- data/lib/nsxv_tz.rb +0 -41
- data/lib/opaque_network.rb +0 -134
- data/lib/rest_client.rb +0 -191
- data/lib/scripts_common.rb +0 -176
- data/lib/transport_zone.rb +0 -43
- data/lib/vcenter_driver.rb +0 -152
- data/lib/vcenter_importer.rb +0 -626
- data/lib/vi_client.rb +0 -273
- data/lib/vi_helper.rb +0 -328
- data/lib/virtual_machine.rb +0 -3574
- data/lib/virtual_wire.rb +0 -158
- data/lib/vm_device.rb +0 -80
- data/lib/vm_disk.rb +0 -202
- data/lib/vm_folder.rb +0 -69
- data/lib/vm_helper.rb +0 -30
- data/lib/vm_monitor.rb +0 -305
- data/lib/vm_nic.rb +0 -70
- data/lib/vm_template.rb +0 -2112
- data/lib/vmm_importer.rb +0 -165
@@ -1,5 +1,5 @@
|
|
1
1
|
# -------------------------------------------------------------------------- #
|
2
|
-
# Copyright 2002-
|
2
|
+
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems #
|
3
3
|
# #
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
5
5
|
# not use this file except in compliance with the License. You may obtain #
|
@@ -21,7 +21,7 @@ module OpenNebula
|
|
21
21
|
# Service Template
|
22
22
|
class ServiceTemplate < DocumentJSON
|
23
23
|
|
24
|
-
|
24
|
+
VM_ROLE_SCHEMA = {
|
25
25
|
:type => :object,
|
26
26
|
:properties => {
|
27
27
|
'name' => {
|
@@ -29,25 +29,33 @@ module OpenNebula
|
|
29
29
|
:required => true,
|
30
30
|
:regex => /^\w+$/
|
31
31
|
},
|
32
|
+
'type' => {
|
33
|
+
:type => :string,
|
34
|
+
:enum => [
|
35
|
+
'vm'
|
36
|
+
],
|
37
|
+
:required => true
|
38
|
+
},
|
32
39
|
'cardinality' => {
|
33
40
|
:type => :integer,
|
34
41
|
:default => 0,
|
35
42
|
:minimum => 0
|
36
43
|
},
|
37
|
-
'
|
44
|
+
'template_id' => {
|
38
45
|
:type => :integer,
|
39
46
|
:required => true
|
40
47
|
},
|
41
|
-
'
|
42
|
-
:type => :
|
48
|
+
'template_contents' => {
|
49
|
+
:type => :object,
|
50
|
+
:properties => {},
|
43
51
|
:required => false
|
44
52
|
},
|
45
|
-
'
|
53
|
+
'user_inputs' => {
|
46
54
|
:type => :object,
|
47
55
|
:properties => {},
|
48
56
|
:required => false
|
49
57
|
},
|
50
|
-
'
|
58
|
+
'user_inputs_values' => {
|
51
59
|
:type => :object,
|
52
60
|
:properties => {},
|
53
61
|
:required => false
|
@@ -173,6 +181,58 @@ module OpenNebula
|
|
173
181
|
}
|
174
182
|
}
|
175
183
|
|
184
|
+
VR_ROLE_SCHEMA = {
|
185
|
+
:type => :object,
|
186
|
+
:properties => {
|
187
|
+
'name' => {
|
188
|
+
:type => :string,
|
189
|
+
:required => true,
|
190
|
+
:regex => /^\w+$/
|
191
|
+
},
|
192
|
+
'type' => {
|
193
|
+
:type => :string,
|
194
|
+
:enum => [
|
195
|
+
'vr'
|
196
|
+
],
|
197
|
+
:required => true
|
198
|
+
},
|
199
|
+
'template_id' => {
|
200
|
+
:type => :integer,
|
201
|
+
:required => true
|
202
|
+
},
|
203
|
+
'cardinality' => {
|
204
|
+
:type => :integer,
|
205
|
+
:default => 0,
|
206
|
+
:minimum => 0
|
207
|
+
},
|
208
|
+
'template_contents' => {
|
209
|
+
:type => :object,
|
210
|
+
:properties => {},
|
211
|
+
:required => false
|
212
|
+
},
|
213
|
+
'user_inputs' => {
|
214
|
+
:type => :object,
|
215
|
+
:properties => {},
|
216
|
+
:required => false
|
217
|
+
},
|
218
|
+
'user_inputs_values' => {
|
219
|
+
:type => :object,
|
220
|
+
:properties => {},
|
221
|
+
:required => false
|
222
|
+
},
|
223
|
+
'on_hold' => {
|
224
|
+
:type => :boolean,
|
225
|
+
:required => false
|
226
|
+
},
|
227
|
+
'parents' => {
|
228
|
+
:type => :array,
|
229
|
+
:items => {
|
230
|
+
:type => :string
|
231
|
+
}
|
232
|
+
}
|
233
|
+
}
|
234
|
+
}
|
235
|
+
|
176
236
|
SCHEMA = {
|
177
237
|
:type => :object,
|
178
238
|
:properties => {
|
@@ -201,15 +261,15 @@ module OpenNebula
|
|
201
261
|
},
|
202
262
|
'roles' => {
|
203
263
|
:type => :array,
|
204
|
-
:items =>
|
264
|
+
:items => [],
|
205
265
|
:required => true
|
206
266
|
},
|
207
|
-
'
|
267
|
+
'user_inputs' => {
|
208
268
|
:type => :object,
|
209
269
|
:properties => {},
|
210
270
|
:required => false
|
211
271
|
},
|
212
|
-
'
|
272
|
+
'user_inputs_values' => {
|
213
273
|
:type => :object,
|
214
274
|
:properties => {},
|
215
275
|
:required => false
|
@@ -260,6 +320,12 @@ module OpenNebula
|
|
260
320
|
def allocate(template_json)
|
261
321
|
template = JSON.parse(template_json)
|
262
322
|
|
323
|
+
# Compability mode v<7.0
|
324
|
+
rc = ServiceTemplate.convert_template(template) \
|
325
|
+
if ServiceTemplate.old_format?(template)
|
326
|
+
|
327
|
+
return rc if OpenNebula.is_error?(rc)
|
328
|
+
|
263
329
|
ServiceTemplate.validate(template)
|
264
330
|
|
265
331
|
template['registration_time'] = Integer(Time.now)
|
@@ -376,11 +442,11 @@ module OpenNebula
|
|
376
442
|
|
377
443
|
# iterate over roles to clone templates
|
378
444
|
rc = body['roles'].each do |role|
|
379
|
-
t_id = role['
|
445
|
+
t_id = role['template_id']
|
380
446
|
|
381
447
|
# if the template has already been cloned, just update the value
|
382
448
|
if cloned_templates.keys.include?(t_id)
|
383
|
-
role['
|
449
|
+
role['template_id'] = cloned_templates[t_id]
|
384
450
|
next
|
385
451
|
end
|
386
452
|
|
@@ -404,7 +470,7 @@ module OpenNebula
|
|
404
470
|
# add new ID to the hash
|
405
471
|
cloned_templates[t_id] = rc
|
406
472
|
|
407
|
-
role['
|
473
|
+
role['template_id'] = rc
|
408
474
|
end
|
409
475
|
|
410
476
|
# if any error, rollback and delete the left templates
|
@@ -477,6 +543,10 @@ module OpenNebula
|
|
477
543
|
|
478
544
|
validator.validate!(template, SCHEMA)
|
479
545
|
|
546
|
+
template['roles'].each do |role|
|
547
|
+
validate_role(role)
|
548
|
+
end
|
549
|
+
|
480
550
|
validate_values(template)
|
481
551
|
end
|
482
552
|
|
@@ -487,7 +557,16 @@ module OpenNebula
|
|
487
557
|
:allow_extra_properties => true
|
488
558
|
)
|
489
559
|
|
490
|
-
|
560
|
+
tmplt_type = template.fetch('type', 'vm')
|
561
|
+
|
562
|
+
case tmplt_type
|
563
|
+
when 'vm'
|
564
|
+
validator.validate!(template, VM_ROLE_SCHEMA)
|
565
|
+
when 'vr'
|
566
|
+
validator.validate!(template, VR_ROLE_SCHEMA)
|
567
|
+
else
|
568
|
+
raise Validator::ParseException, "Unsupported role type \"#{template['type']}\""
|
569
|
+
end
|
491
570
|
end
|
492
571
|
|
493
572
|
def instantiate(merge_template)
|
@@ -496,6 +575,8 @@ module OpenNebula
|
|
496
575
|
if merge_template.nil?
|
497
576
|
instantiate_template = JSON.parse(@body.to_json)
|
498
577
|
else
|
578
|
+
@body = handle_nested_values(@body, merge_template)
|
579
|
+
|
499
580
|
instantiate_template = JSON.parse(@body.to_json)
|
500
581
|
.deep_merge(merge_template)
|
501
582
|
end
|
@@ -518,11 +599,10 @@ module OpenNebula
|
|
518
599
|
end
|
519
600
|
|
520
601
|
def self.validate_values(template)
|
521
|
-
parser = ElasticityGrammarParser.new
|
522
|
-
|
523
602
|
roles = template['roles']
|
524
603
|
|
525
604
|
roles.each_with_index do |role, role_index|
|
605
|
+
# General verification (applies to all roles)
|
526
606
|
roles[role_index+1..-1].each do |other_role|
|
527
607
|
if role['name'] == other_role['name']
|
528
608
|
raise Validator::ParseException,
|
@@ -530,115 +610,291 @@ module OpenNebula
|
|
530
610
|
end
|
531
611
|
end
|
532
612
|
|
533
|
-
|
534
|
-
|
535
|
-
|
613
|
+
# Specific values verification per role type
|
614
|
+
case role['type']
|
615
|
+
when 'vm'
|
616
|
+
parser = ElasticityGrammarParser.new
|
617
|
+
validate_vmvalues(role, parser)
|
618
|
+
when 'vr'
|
619
|
+
validate_vrvalues(role)
|
620
|
+
else
|
536
621
|
raise Validator::ParseException,
|
537
|
-
"
|
538
|
-
"greater than or equal to 'min_vms'"
|
622
|
+
"Unsupported role type \"#{template['type']}\""
|
539
623
|
end
|
624
|
+
end
|
625
|
+
end
|
540
626
|
|
541
|
-
|
542
|
-
|
627
|
+
# Retreives all associated VM templates IDs
|
628
|
+
#
|
629
|
+
# @return [Array] VM templates IDs
|
630
|
+
def vm_template_ids
|
631
|
+
rc = info
|
543
632
|
|
544
|
-
|
545
|
-
|
546
|
-
|
633
|
+
return rc if OpenNebula.is_error?(rc)
|
634
|
+
|
635
|
+
ret = []
|
636
|
+
|
637
|
+
@body['roles'].each do |role|
|
638
|
+
t_id = Integer(role['template_id'])
|
639
|
+
ret << t_id unless ret.include?(t_id)
|
640
|
+
end
|
641
|
+
|
642
|
+
ret
|
643
|
+
end
|
644
|
+
|
645
|
+
def self.validate_vrvalues(vrrole)
|
646
|
+
nic_array = vrrole.dig('template_contents', 'NIC')
|
647
|
+
cardinality = vrrole['cardinality']
|
648
|
+
|
649
|
+
return if nic_array.nil? || !nic_array.is_a?(Array)
|
650
|
+
|
651
|
+
contains_floating_key = nic_array.any? do |nic|
|
652
|
+
nic.keys.any? do |key|
|
653
|
+
key.to_s.start_with?('FLOATING')
|
547
654
|
end
|
655
|
+
end
|
656
|
+
|
657
|
+
return unless cardinality > 1 && !contains_floating_key
|
658
|
+
|
659
|
+
raise(
|
660
|
+
Validator::ParseException,
|
661
|
+
"Role '#{vrrole['name']}' with 'cardinality' greather " \
|
662
|
+
'than one must define a floating IP'
|
663
|
+
)
|
664
|
+
end
|
665
|
+
|
666
|
+
def self.validate_vmvalues(vmrole, parser)
|
667
|
+
if !vmrole['min_vms'].nil? &&
|
668
|
+
vmrole['min_vms'].to_i > vmrole['cardinality'].to_i
|
669
|
+
|
670
|
+
raise Validator::ParseException,
|
671
|
+
"Role '#{vmrole['name']}' 'cardinality' must be " \
|
672
|
+
"greater than or equal to 'min_vms'"
|
673
|
+
end
|
674
|
+
|
675
|
+
if !vmrole['max_vms'].nil? &&
|
676
|
+
vmrole['max_vms'].to_i < vmrole['cardinality'].to_i
|
677
|
+
|
678
|
+
raise Validator::ParseException,
|
679
|
+
"Role '#{vmrole['name']}' 'cardinality' must be " \
|
680
|
+
"lower than or equal to 'max_vms'"
|
681
|
+
end
|
682
|
+
|
683
|
+
if ((vmrole['elasticity_policies'] &&
|
684
|
+
!vmrole['elasticity_policies'].empty?) ||
|
685
|
+
(vmrole['scheduled_policies'] &&
|
686
|
+
!vmrole['scheduled_policies'].empty?)) &&
|
687
|
+
(vmrole['min_vms'].nil? || vmrole['max_vms'].nil?)
|
688
|
+
raise Validator::ParseException,
|
689
|
+
"Role '#{vmrole['name']}' with " \
|
690
|
+
" 'elasticity_policies' or " \
|
691
|
+
"'scheduled_policies'must define both 'min_vms'" \
|
692
|
+
" and 'max_vms'"
|
693
|
+
end
|
694
|
+
|
695
|
+
if vmrole['elasticity_policies']
|
696
|
+
vmrole['elasticity_policies'].each_with_index do |policy, index|
|
697
|
+
exp = policy['expression']
|
698
|
+
|
699
|
+
if exp.empty?
|
700
|
+
raise Validator::ParseException,
|
701
|
+
"Role '#{vmrole['name']}', elasticity policy " \
|
702
|
+
"##{index} 'expression' cannot be empty"
|
703
|
+
end
|
704
|
+
|
705
|
+
treetop = parser.parse(exp)
|
706
|
+
next unless treetop.nil?
|
548
707
|
|
549
|
-
if ((role['elasticity_policies'] &&
|
550
|
-
!role['elasticity_policies'].empty?) ||
|
551
|
-
(role['scheduled_policies'] &&
|
552
|
-
!role['scheduled_policies'].empty?)) &&
|
553
|
-
(role['min_vms'].nil? || role['max_vms'].nil?)
|
554
708
|
raise Validator::ParseException,
|
555
|
-
"Role '#{
|
556
|
-
" '
|
557
|
-
"
|
558
|
-
" and 'max_vms'"
|
709
|
+
"Role '#{vmrole['name']}', elasticity policy " \
|
710
|
+
"##{index} 'expression' parse error: " \
|
711
|
+
"#{parser.failure_reason}"
|
559
712
|
end
|
713
|
+
end
|
560
714
|
|
561
|
-
|
562
|
-
role['elasticity_policies'].each_with_index do |policy, index|
|
563
|
-
exp = policy['expression']
|
715
|
+
return unless vmrole['scheduled_policies']
|
564
716
|
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
"##{index} 'expression' cannot be empty"
|
569
|
-
end
|
717
|
+
vmrole['scheduled_policies'].each_with_index do |policy, index|
|
718
|
+
start_time = policy['start_time']
|
719
|
+
recurrence = policy['recurrence']
|
570
720
|
|
571
|
-
|
572
|
-
|
721
|
+
if !start_time.nil?
|
722
|
+
if !policy['recurrence'].nil?
|
723
|
+
raise Validator::ParseException,
|
724
|
+
"Role '#{vmrole['name']}', scheduled policy "\
|
725
|
+
"##{index} must define "\
|
726
|
+
"'start_time' or 'recurrence', but not both"
|
727
|
+
end
|
728
|
+
|
729
|
+
begin
|
730
|
+
next if start_time.match(/^\d+$/)
|
573
731
|
|
732
|
+
Time.parse(start_time)
|
733
|
+
rescue ArgumentError
|
734
|
+
raise Validator::ParseException,
|
735
|
+
"Role '#{vmrole['name']}', scheduled policy " \
|
736
|
+
"##{index} 'start_time' is not a valid " \
|
737
|
+
'Time. Try with YYYY-MM-DD hh:mm:ss or ' \
|
738
|
+
'0YYY-MM-DDThh:mm:ssZ'
|
739
|
+
end
|
740
|
+
elsif !recurrence.nil?
|
741
|
+
begin
|
742
|
+
cron_parser = CronParser.new(recurrence)
|
743
|
+
cron_parser.next
|
744
|
+
rescue StandardError
|
574
745
|
raise Validator::ParseException,
|
575
|
-
"Role '#{
|
576
|
-
"##{index} '
|
577
|
-
|
746
|
+
"Role '#{vmrole['name']}', scheduled policy " \
|
747
|
+
"##{index} 'recurrence' is not a valid " \
|
748
|
+
'cron expression'
|
578
749
|
end
|
750
|
+
else
|
751
|
+
raise Validator::ParseException,
|
752
|
+
"Role '#{vmrole['name']}', scheduled policy #" \
|
753
|
+
"#{index} needs to define either " \
|
754
|
+
"'start_time' or 'recurrence'"
|
579
755
|
end
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
def handle_nested_values(template, extra_template)
|
760
|
+
roles = template['roles']
|
761
|
+
extra_roles = extra_template.fetch('roles', [])
|
580
762
|
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
begin
|
596
|
-
next if start_time.match(/^\d+$/)
|
597
|
-
|
598
|
-
Time.parse(start_time)
|
599
|
-
rescue ArgumentError
|
600
|
-
raise Validator::ParseException,
|
601
|
-
"Role '#{role['name']}', scheduled policy " \
|
602
|
-
"##{index} 'start_time' is not a valid " \
|
603
|
-
'Time. Try with YYYY-MM-DD hh:mm:ss or ' \
|
604
|
-
'0YYY-MM-DDThh:mm:ssZ'
|
605
|
-
end
|
606
|
-
elsif !recurrence.nil?
|
607
|
-
begin
|
608
|
-
cron_parser = CronParser.new(recurrence)
|
609
|
-
cron_parser.next
|
610
|
-
rescue StandardError
|
611
|
-
raise Validator::ParseException,
|
612
|
-
"Role '#{role['name']}', scheduled policy " \
|
613
|
-
"##{index} 'recurrence' is not a valid " \
|
614
|
-
'cron expression'
|
615
|
-
end
|
763
|
+
# Check if nics key already exist
|
764
|
+
template_nets = template['networks_values'] || []
|
765
|
+
extra_nets = extra_template['networks_values'] || []
|
766
|
+
|
767
|
+
unless extra_nets.empty?
|
768
|
+
extra_nets.each do |extra_net|
|
769
|
+
next unless extra_net.is_a?(Hash) && !extra_net.empty?
|
770
|
+
|
771
|
+
net_name = extra_net.keys.first
|
772
|
+
net_index = template_nets.index {|net| net.key?(net_name) }
|
773
|
+
|
774
|
+
if net_index
|
775
|
+
template_nets[net_index] = extra_net
|
616
776
|
else
|
617
|
-
|
618
|
-
"Role '#{role['name']}', scheduled policy #" \
|
619
|
-
"#{index} needs to define either " \
|
620
|
-
"'start_time' or 'recurrence'"
|
777
|
+
template_nets << extra_net
|
621
778
|
end
|
622
779
|
end
|
780
|
+
|
781
|
+
template['networks_values'] = template_nets
|
782
|
+
extra_template['networks_values'] = []
|
623
783
|
end
|
784
|
+
|
785
|
+
return template if extra_roles.empty?
|
786
|
+
|
787
|
+
roles.each_with_index do |role, index|
|
788
|
+
extra_role = extra_roles.find {|item| item['name'] == role['name'] }
|
789
|
+
next unless extra_role
|
790
|
+
|
791
|
+
roles[index] = role.deep_merge(extra_role)
|
792
|
+
end
|
793
|
+
|
794
|
+
extra_template.delete('roles')
|
795
|
+
|
796
|
+
template
|
624
797
|
end
|
625
798
|
|
626
|
-
|
799
|
+
def self.old_format?(body)
|
800
|
+
body.key?('roles') && body['roles'].all? do |role|
|
801
|
+
role.key?('vm_template') || role.key?('vm_template_contents')
|
802
|
+
end
|
803
|
+
end
|
804
|
+
|
805
|
+
# Compatibility function to translate a service template from the old format
|
806
|
+
# to the new one with vRouters with other data model changes
|
627
807
|
#
|
628
|
-
# @
|
629
|
-
def
|
630
|
-
|
808
|
+
# @param template [String] Hash body of the service template to translate
|
809
|
+
def self.convert_template(body)
|
810
|
+
body['roles'].each do |role|
|
811
|
+
# Mandatory
|
812
|
+
role['template_id'] = role['vm_template']
|
813
|
+
role['type'] = 'vm'
|
814
|
+
|
815
|
+
# Optional attributes
|
816
|
+
role['user_inputs'] = role['custom_attrs'] if role['custom_attrs']
|
817
|
+
body['user_inputs_values'] = role['custom_attrs_values'] \
|
818
|
+
if body['custom_attrs_values']
|
819
|
+
|
820
|
+
# Change name and type (string -> object)
|
821
|
+
role['template_contents'] = ServiceTemplate.upgrade_template_contents(
|
822
|
+
role['vm_template_contents']
|
823
|
+
) if role['vm_template_contents']
|
824
|
+
|
825
|
+
# Remove old attributes
|
826
|
+
role.delete('vm_template')
|
827
|
+
role.delete('vm_template_contents') if role['vm_template_contents']
|
828
|
+
role.delete('custom_attrs') if role['custom_attrs']
|
829
|
+
role.delete('custom_attrs_values') if role['custom_attrs_values']
|
830
|
+
end
|
631
831
|
|
632
|
-
|
832
|
+
body['user_inputs'] = body['custom_attrs'] if body['custom_attrs']
|
833
|
+
body['user_inputs_values'] = body['custom_attrs_values'] if body['custom_attrs_values']
|
633
834
|
|
634
|
-
|
835
|
+
body.delete('custom_attrs') if body['custom_attrs']
|
836
|
+
body.delete('custom_attrs_values') if body['custom_attrs_values']
|
837
|
+
rescue StandardError => e
|
838
|
+
return OpenNebula::Error.new(
|
839
|
+
'An old service template format (OpenNebula v6.x) was detected and could not be ' \
|
840
|
+
'automatically converted. Update it manually to the new format. Error: ' + e.message
|
841
|
+
)
|
842
|
+
end
|
635
843
|
|
636
|
-
|
637
|
-
|
638
|
-
|
844
|
+
# Converts a RAW string in the form KEY = VAL to a hash
|
845
|
+
#
|
846
|
+
# @param template [String] Raw string content in the form KEY = VAL,
|
847
|
+
# representing vm_template_contents
|
848
|
+
# @return [Hash, OpenNebula::Error] Hash representation of the raw content,
|
849
|
+
# or an OpenNebula Error if the conversion fails
|
850
|
+
def self.upgrade_template_contents(vm_template_contents)
|
851
|
+
return {} if vm_template_contents.nil? || vm_template_contents.empty?
|
852
|
+
|
853
|
+
result = {}
|
854
|
+
|
855
|
+
vm_template_contents.split(/\n(?![^\[]*\])/).each do |line|
|
856
|
+
next unless line.include?('=')
|
857
|
+
|
858
|
+
key, value = line.split('=', 2).map(&:strip)
|
859
|
+
value = value.tr('"', '')
|
860
|
+
|
861
|
+
# If the value is an array (e.g., NIC = [ ... ]),
|
862
|
+
# process the content inside the brackets
|
863
|
+
if value.start_with?('[') && value.end_with?(']')
|
864
|
+
# Split the elements inside the brackets by commas
|
865
|
+
array_elements = value[1..-2].split(/\s*,\s*/)
|
866
|
+
|
867
|
+
# Create a hash combining all key-value pairs in the array
|
868
|
+
array_result = {}
|
869
|
+
array_elements.each do |element|
|
870
|
+
sub_key, sub_value = element.split('=', 2).map(&:strip)
|
871
|
+
array_result[sub_key] = sub_value
|
872
|
+
end
|
873
|
+
|
874
|
+
value = [array_result]
|
875
|
+
else
|
876
|
+
value = [value]
|
877
|
+
end
|
878
|
+
|
879
|
+
# If the key already exists in the result hash, add the new value
|
880
|
+
if result[key]
|
881
|
+
if result[key].is_a?(Array)
|
882
|
+
result[key] << value.first
|
883
|
+
else
|
884
|
+
result[key] = [result[key], value.first]
|
885
|
+
end
|
886
|
+
else
|
887
|
+
result[key] = value.first
|
888
|
+
end
|
639
889
|
end
|
640
890
|
|
641
|
-
|
891
|
+
result.each do |key, val|
|
892
|
+
if val.is_a?(Hash)
|
893
|
+
result[key] = [val]
|
894
|
+
end
|
895
|
+
end
|
896
|
+
|
897
|
+
result
|
642
898
|
end
|
643
899
|
|
644
900
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# -------------------------------------------------------------------------- #
|
2
|
-
# Copyright 2002-
|
2
|
+
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems #
|
3
3
|
# #
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
5
5
|
# not use this file except in compliance with the License. You may obtain #
|
@@ -51,7 +51,7 @@ module OpenNebula::ServiceTemplateExt
|
|
51
51
|
@body['roles'].each do |role|
|
52
52
|
# Find role template into templates to get the name to use
|
53
53
|
t = templates.find do |_, v|
|
54
|
-
v[:template]['ID'].to_i == role['
|
54
|
+
v[:template]['ID'].to_i == role['template_id']
|
55
55
|
end
|
56
56
|
|
57
57
|
next if t.nil? || t[1].nil? || t[1][:name].nil?
|
@@ -62,7 +62,7 @@ module OpenNebula::ServiceTemplateExt
|
|
62
62
|
ROLE = [ NAME="#{role['name']}", APP="#{app_name}"]
|
63
63
|
EOT
|
64
64
|
|
65
|
-
role.delete('
|
65
|
+
role.delete('template_id')
|
66
66
|
end
|
67
67
|
|
68
68
|
xml = MarketPlaceApp.build_xml
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# -------------------------------------------------------------------------- #
|
2
|
-
# Copyright 2002-
|
2
|
+
# Copyright 2002-2025, OpenNebula Project, OpenNebula Systems #
|
3
3
|
# #
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
5
5
|
# not use this file except in compliance with the License. You may obtain #
|