opennebula 6.0.3 → 6.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ae4c2d6ffef598e821e3b6bcc4a429f766caadbf
4
- data.tar.gz: 2e65f273fb1f2d383d799fa4fd31e6d2fb66cb41
2
+ SHA256:
3
+ metadata.gz: 630fc82258e06265dd9308385f987452c2c9e97774f9c844567eb0512c699996
4
+ data.tar.gz: 4b19ee5faf356fc61ba4e8883dc7bb37137d54d34c251c6f0cbbfab5a8b0b27b
5
5
  SHA512:
6
- metadata.gz: ce66ed43b8db71bcb0f8572a7e3a48de18b3e7c4819006d93333709e892718cd83c724a723c81870538b404ed3d80bc33786b1b1cc0bbd8a882412992c56bd17
7
- data.tar.gz: e3694d73c467089a0ec6720c2ac22034bfcb49f273d14b607915d9aa1ba23abf6c5045a436ec08f47d7f87e5c394981c0e95d8b1614833f87c3666f64b731291
6
+ metadata.gz: ea3eba7d99bfc70cb7b94a2c8c2548b130d50ec3cf73d3344e0ed12a05b2e83780eec32e4790cfeef00bde6a38164468a0cfe91bb62cd1325c20aac7f9cca235
7
+ data.tar.gz: eeb5c702a03ef47f5ad8e37f95b94259e49019a78d5b58f8ce560d3b2afd50cb8828a7512afe14b1f3e25e262ab3b3974f9174e3109a20a98d89140a90fbca96
@@ -51,7 +51,7 @@ end
51
51
  module CloudClient
52
52
 
53
53
  # OpenNebula version
54
- VERSION = '6.0.3'
54
+ VERSION = '6.2.1'
55
55
 
56
56
  # #########################################################################
57
57
  # Default location for the authentication file
data/lib/datacenter.rb CHANGED
@@ -131,7 +131,10 @@ module VCenterDriver
131
131
 
132
132
  # Setting host import name and
133
133
  # replace spaces and weird characters
134
- cluster_name = (ccr['name']).to_s.tr(' ', '_')
134
+ cluster_name = ccr['name'].to_s.tr(' ', '_')
135
+ cluster_name = VCenterDriver::VcImporter.sanitize(
136
+ cluster_name
137
+ )
135
138
  cluster_name =
136
139
  VCenterDriver::VIHelper
137
140
  .one_name(
@@ -159,11 +162,28 @@ module VCenterDriver
159
162
  host_objects
160
163
  end
161
164
 
162
- def get_unimported_datastores(dpool, vcenter_instance_name, hpool)
165
+ # rubocop:disable Style/GlobalVars
166
+ def get_unimported_datastores(dpool, vcenter_instance_name, hpool, args)
163
167
  import_id = 0
164
168
  ds_objects = {}
165
169
  vcenter_uuid = vcenter_instance_uuid
166
170
 
171
+ # Selected host in OpenNebula
172
+ if $conf.nil?
173
+ one_client = OpenNebula::Client.new
174
+ else
175
+ one_client = OpenNebula::Client.new(
176
+ nil,
177
+ $conf[:one_xmlrpc]
178
+ )
179
+ end
180
+ one_host = OpenNebula::Host.new_with_id(args[:host], one_client)
181
+
182
+ rc = one_host.info
183
+ raise rc.message if OpenNebula.is_error? rc
184
+
185
+ cluster_id = one_host['CLUSTER_ID'].to_i
186
+
167
187
  # Get datacenters
168
188
  fetch! if @items.empty?
169
189
 
@@ -185,7 +205,10 @@ module VCenterDriver
185
205
  'summary.freeSpace'
186
206
  )
187
207
 
188
- ds_name = name.to_s
208
+ ds_name = VCenterDriver::VcImporter.sanitize(
209
+ name.to_s
210
+ )
211
+
189
212
  ds_total_mb = ((capacity.to_i / 1024) / 1024)
190
213
  ds_free_mb = ((free_space.to_i / 1024) / 1024)
191
214
  ds_ref = ds['_ref']
@@ -363,8 +386,15 @@ module VCenterDriver
363
386
  end
364
387
  end
365
388
 
389
+ ds_objects.keys.each do |key|
390
+ unless ds_objects[key][:cluster].include? cluster_id
391
+ ds_objects.delete key
392
+ end
393
+ end
394
+
366
395
  { vcenter_instance_name => ds_objects }
367
396
  end
397
+ # rubocop:enable Style/GlobalVars
368
398
 
369
399
  def get_unimported_templates(vi_client, tpool)
370
400
  template_objects = {}
data/lib/datastore.rb CHANGED
@@ -558,8 +558,12 @@ module VCenterDriver
558
558
  raise 'Could not get file size or capacity' if size.nil?
559
559
 
560
560
  size
561
- rescue StandardError
562
- raise 'Could not find file.'
561
+ rescue StandardError => e
562
+ message = "Could not find file. Reason: \"#{e.message}\"."
563
+ if VCenterDriver::CONFIG[:debug_information]
564
+ message += ' ' + e.backtrace
565
+ end
566
+ raise message
563
567
  end
564
568
  end
565
569
 
@@ -877,7 +881,7 @@ module VCenterDriver
877
881
  @one_class = OpenNebula::Datastore
878
882
  end
879
883
 
880
- def get_list(_args = {})
884
+ def get_list(args = {})
881
885
  dc_folder = VCenterDriver::DatacenterFolder.new(@vi_client)
882
886
 
883
887
  # one pool creation
@@ -904,7 +908,8 @@ module VCenterDriver
904
908
  .get_unimported_datastores(
905
909
  dpool,
906
910
  @vi_client.vc_name,
907
- hpool
911
+ hpool,
912
+ args
908
913
  )
909
914
  @list = rs
910
915
  end
@@ -944,7 +949,11 @@ module VCenterDriver
944
949
  clusters = opts['selected_clusters'].each.map(&:to_i)
945
950
  end
946
951
 
947
- res = { :id => [], :name => selected[:simple_name] }
952
+ name = VCenterDriver::VcImporter.sanitize(
953
+ selected[:simple_name]
954
+ )
955
+
956
+ res = { :id => [], :name => name }
948
957
  @info[:rollback] = []
949
958
  pair.each do |ds|
950
959
  create(ds[:one]) do |one_object, id|
@@ -1007,7 +1016,9 @@ module VCenterDriver
1007
1016
  message = 'Error creating the OpenNebula resource'
1008
1017
  info = selected[:one]
1009
1018
  dsid = selected[:dsid].to_i
1010
- name = selected[:name]
1019
+ name = VCenterDriver::VcImporter.sanitize(
1020
+ selected[:name]
1021
+ )
1011
1022
 
1012
1023
  rc = resource.allocate(info, dsid, false)
1013
1024
  VCenterDriver::VIHelper.check_error(rc, message)
data/lib/models/role.rb CHANGED
@@ -571,11 +571,20 @@ module OpenNebula
571
571
  vm = OpenNebula::VirtualMachine.new_with_id(vm_id,
572
572
  @service.client)
573
573
 
574
- rc = vm.info
574
+ if do_offset
575
+ offset = (index / vms_per_period.to_i).floor
576
+ time_offset = offset * period.to_i
577
+ end
578
+
579
+ tmp_str = 'SCHED_ACTION = ['
580
+ tmp_str << "ACTION = #{action},"
581
+ tmp_str << "ARGS = \"#{args}\"," if args
582
+ tmp_str << "TIME = #{now + time_offset}]"
575
583
 
584
+ rc = vm.sched_action_add(tmp_str)
576
585
  if OpenNebula.is_error?(rc)
577
- msg = "Role #{name} : VM #{vm_id} monitorization failed;"\
578
- " #{rc.message}"
586
+ msg = "Role #{name} : VM #{vm_id} error scheduling "\
587
+ "action; #{rc.message}"
579
588
 
580
589
  error_msgs << msg
581
590
 
@@ -583,40 +592,7 @@ module OpenNebula
583
592
 
584
593
  @service.log_error(msg)
585
594
  else
586
- ids = vm.retrieve_elements('USER_TEMPLATE/SCHED_ACTION/ID')
587
-
588
- id = 0
589
- if !ids.nil? && !ids.empty?
590
- ids.map! {|e| e.to_i }
591
- id = ids.max + 1
592
- end
593
-
594
- tmp_str = vm.user_template_str
595
-
596
- if do_offset
597
- offset = (index / vms_per_period.to_i).floor
598
- time_offset = offset * period.to_i
599
- end
600
-
601
- tmp_str << "\nSCHED_ACTION = ["
602
- tmp_str << "ID = #{id},"
603
- tmp_str << "ACTION = #{action},"
604
- tmp_str << "ARGS = \"#{args}\"," if args
605
- tmp_str << "TIME = #{now + time_offset}]"
606
-
607
- rc = vm.update(tmp_str)
608
- if OpenNebula.is_error?(rc)
609
- msg = "Role #{name} : VM #{vm_id} error scheduling "\
610
- "action; #{rc.message}"
611
-
612
- error_msgs << msg
613
-
614
- Log.error LOG_COMP, msg, @service.id
615
-
616
- @service.log_error(msg)
617
- else
618
- vms_id << vm.id
619
- end
595
+ vms_id << vm.id
620
596
  end
621
597
  end
622
598
 
@@ -522,31 +522,40 @@ module OpenNebula
522
522
 
523
523
  # Check that changes values are correct
524
524
  #
525
- # @param template_json [String] New template
525
+ # @param template_json [String] New template
526
+ # @param append [Boolean] True to append template to the current
526
527
  #
527
528
  # @return [Boolean, String] True, nil if everything is correct
528
529
  # False, attr if attr was changed
529
- def check_new_template(template_json)
530
+ def check_new_template(template_json, append)
530
531
  template = JSON.parse(template_json)
531
532
 
532
- if template['roles'].size != @roles.size
533
- return [false, 'service/roles size']
534
- end
533
+ if append
534
+ IMMUTABLE_ATTRS.each do |attr|
535
+ next if template[attr].nil?
535
536
 
536
- IMMUTABLE_ATTRS.each do |attr|
537
- next if template[attr] == @body[attr]
537
+ return [false, "service/#{attr}"]
538
+ end
539
+ else
540
+ if template['roles'].size != @roles.size
541
+ return [false, 'service/roles size']
542
+ end
538
543
 
539
- return [false, "service/#{attr}"]
540
- end
544
+ IMMUTABLE_ATTRS.each do |attr|
545
+ next if template[attr] == @body[attr]
541
546
 
542
- template['roles'].each do |role|
543
- # Role name can't be changed, if it is changed some problems
544
- # may appear, as name is used to reference roles
545
- return [false, 'name'] unless @roles[role['name']]
547
+ return [false, "service/#{attr}"]
548
+ end
546
549
 
547
- rc = @roles[role['name']].check_new_template(role)
550
+ template['roles'].each do |role|
551
+ # Role name can't be changed, if it is changed some problems
552
+ # may appear, as name is used to reference roles
553
+ return [false, 'name'] unless @roles[role['name']]
548
554
 
549
- return rc unless rc[0]
555
+ rc = @roles[role['name']].check_new_template(role)
556
+
557
+ return rc unless rc[0]
558
+ end
550
559
  end
551
560
 
552
561
  [true, nil]
@@ -307,10 +307,18 @@ module OpenNebula
307
307
 
308
308
  template = JSON.parse(template_json)
309
309
 
310
- IMMUTABLE_ATTRS.each do |attr|
311
- next if template[attr] == @body[attr]
310
+ if append
311
+ IMMUTABLE_ATTRS.each do |attr|
312
+ unless template[attr].nil?
313
+ return [false, "service_template/#{attr}"]
314
+ end
315
+ end
316
+ else
317
+ IMMUTABLE_ATTRS.each do |attr|
318
+ next if template[attr] == @body[attr]
312
319
 
313
- return [false, "service_template/#{attr}"]
320
+ return [false, "service_template/#{attr}"]
321
+ end
314
322
  end
315
323
 
316
324
  template = @body.merge(template) if append
@@ -15,7 +15,9 @@
15
15
  # ---------------------------------------------------------------------------- #
16
16
 
17
17
  require 'rubygems'
18
- require 'opennebula'
18
+ require 'opennebula/xml_utils'
19
+ require 'opennebula/client'
20
+ require 'opennebula/group_pool'
19
21
  require 'net/ldap'
20
22
  require 'yaml'
21
23
 
@@ -161,7 +163,8 @@ class OpenNebula::LdapAuth
161
163
  end
162
164
 
163
165
  def is_in_group?(user, group)
164
- username = user.first.force_encoding(Encoding::UTF_8)
166
+ username = Net::LDAP::Filter.escape(
167
+ user.first.force_encoding(Encoding::UTF_8))
165
168
  result=@ldap.search(
166
169
  :base => group,
167
170
  :attributes => [@options[:group_field]],
@@ -273,6 +276,7 @@ def get_server_order(opts, user)
273
276
  user = m[1] if m[1]
274
277
 
275
278
  order << to_array(server)
279
+ break
276
280
  end
277
281
  end
278
282
 
@@ -461,7 +461,7 @@ module OpenNebula::MarketPlaceAppExt
461
461
  def export_recursive(xpath, options)
462
462
  # Get marketplace apps pool to find roles apps
463
463
  pool = OpenNebula::MarketPlaceAppPool.new(@client)
464
- rc = pool.info
464
+ rc = pool.info_all
465
465
 
466
466
  return rc if OpenNebula.is_error?(rc)
467
467
 
@@ -261,6 +261,8 @@ module OpenNebula
261
261
  size = OpenNebula.pool_page_size if (!size || size == 0)
262
262
  rc = @client.call(method, @user_id, current, -size, state)
263
263
 
264
+ return rc if OpenNebula.is_error?(rc)
265
+
264
266
  initialize_xml(rc, @pool_name)
265
267
  else
266
268
  rc = info
@@ -276,11 +278,11 @@ module OpenNebula
276
278
  page = OpenNebula::XMLElement.new
277
279
 
278
280
  loop do
279
- page.initialize_xml(get_page(size,
280
- current,
281
- extended,
282
- state),
283
- @pool_name)
281
+ rc = get_page(size, current, extended, state)
282
+
283
+ break rc if OpenNebula.is_error?(rc)
284
+
285
+ page.initialize_xml(rc, @pool_name)
284
286
 
285
287
  break if page["//#{element}"].nil?
286
288
 
@@ -41,8 +41,10 @@ class OpenNebula::ServerCipherAuth
41
41
  if !srv_passwd.empty?
42
42
  # truncate token to 32-bytes for Ruby >= 2.4
43
43
  @key = Digest::SHA256.hexdigest(@srv_passwd)[0..31]
44
- else
44
+ @iv = @key[0..15]
45
+ else
45
46
  @key = ""
47
+ @iv = ""
46
48
  end
47
49
 
48
50
  @cipher = OpenSSL::Cipher.new(CIPHER)
@@ -112,6 +114,7 @@ class OpenNebula::ServerCipherAuth
112
114
  begin
113
115
  # truncate token to 32-bytes for Ruby >= 2.4
114
116
  @key = srv_pass[0..31]
117
+ @iv = srv_pass[0..15]
115
118
 
116
119
  token_array = decrypt(signed_text).split(':')
117
120
 
@@ -133,7 +136,7 @@ class OpenNebula::ServerCipherAuth
133
136
  def encrypt(data)
134
137
  @cipher.encrypt
135
138
  @cipher.key = @key
136
-
139
+ @cipher.iv = @iv
137
140
  rc = @cipher.update(data)
138
141
  rc << @cipher.final
139
142
 
@@ -143,7 +146,7 @@ class OpenNebula::ServerCipherAuth
143
146
  def decrypt(data)
144
147
  @cipher.decrypt
145
148
  @cipher.key = @key
146
-
149
+ @cipher.iv = @iv
147
150
  rc = @cipher.update(Base64::decode64(data))
148
151
  rc << @cipher.final
149
152
 
@@ -89,8 +89,8 @@ module OpenNebula
89
89
  #######################################################################
90
90
 
91
91
  # Retrieves the information of the given User.
92
- def info()
93
- super(USER_METHODS[:info], 'USER')
92
+ def info(decrypt = false)
93
+ super(USER_METHODS[:info], 'USER', decrypt)
94
94
  end
95
95
 
96
96
  alias_method :info!, :info
@@ -50,8 +50,11 @@ module OpenNebula
50
50
  :disksnapshotrename => "vm.disksnapshotrename",
51
51
  :diskresize => "vm.diskresize",
52
52
  :updateconf => "vm.updateconf",
53
- :lock => "vm.lock",
54
- :unlock => "vm.unlock"
53
+ :lock => "vm.lock",
54
+ :unlock => "vm.unlock",
55
+ :schedadd => "vm.schedadd",
56
+ :scheddelete => "vm.scheddelete",
57
+ :schedupdate => "vm.schedupdate"
55
58
  }
56
59
 
57
60
  VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED
@@ -260,7 +263,7 @@ module OpenNebula
260
263
  # +id+ the id of the vm
261
264
  #
262
265
  # Example:
263
- # vnet = VirtualMachine.new(VirtualMachine.build_xml(3),rpc_client)
266
+ # vm = VirtualMachine.new(VirtualMachine.build_xml(3),rpc_client)
264
267
  #
265
268
  def VirtualMachine.build_xml(pe_id=nil)
266
269
  if pe_id
@@ -710,18 +713,49 @@ module OpenNebula
710
713
  end
711
714
  end
712
715
 
713
- # Changes the attributes of a VM in power off, failure and undeploy
714
- # states
715
- # @param new_conf, string describing the new attributes. Each attribute
716
+ # Changes the attributes of a VM in power off, failure and undeploy
717
+ # states
718
+ #
719
+ # @param new_conf, string describing the new attributes. Each attribute
716
720
  # will replace the existing ones or delete it if empty. Attributes that
717
721
  # can be updated are: INPUT/{TYPE, BUS}; RAW/{TYPE, DATA, DATA_VMX},
718
722
  # OS/{BOOT, BOOTLOADER, ARCH, MACHINE, KERNEL, INITRD},
719
723
  # FEATURES/{ACPI, APIC, PAE, LOCALTIME, HYPERV, GUEST_AGENT},
720
724
  # and GRAPHICS/{TYPE, LISTEN, PASSWD, KEYMAP}
725
+ # @param append, append template, do not delete empty attributes
726
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
727
+ # otherwise
728
+ def updateconf(new_conf, append = false)
729
+ return call(VM_METHODS[:updateconf], @pe_id, new_conf, append ? 1 : 0)
730
+ end
731
+
732
+ # Add sched actions
733
+ #
734
+ # @param sched_template [String] Template with SCHED_ACTIONs
735
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
736
+ # otherwise
737
+ def sched_action_add(sched_template)
738
+ return call(VM_METHODS[:schedadd], @pe_id, sched_template)
739
+ end
740
+
741
+ # Delete sched action
742
+ #
743
+ # @param sched_id [Int] id of the SCHED_ACTION
744
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
745
+ # otherwise
746
+ def sched_action_delete(sched_id)
747
+ return call(VM_METHODS[:scheddelete], @pe_id, sched_id.to_i)
748
+ end
749
+
750
+ # Update sched_action
751
+ #
752
+ # @param sched_id [Int] id of the SCHED_ACTION
753
+ # @param sched_template [String] Template containing a SCHED_ACTION
721
754
  # @return [nil, OpenNebula::Error] nil in case of success, Error
722
755
  # otherwise
723
- def updateconf(new_conf)
724
- return call(VM_METHODS[:updateconf], @pe_id, new_conf)
756
+ def sched_action_update(sched_id, sched_template)
757
+ return call(VM_METHODS[:schedupdate], @pe_id, sched_id.to_i,
758
+ sched_template)
725
759
  end
726
760
 
727
761
  ########################################################################
@@ -94,6 +94,35 @@ module OpenNebula::VirtualMachineExt
94
94
  raise rc.message if OpenNebula.is_error?(rc)
95
95
  end
96
96
 
97
+ # --------------------------------------------------------------
98
+ # Ask if source VM is linked clone
99
+ # --------------------------------------------------------------
100
+ use_linked_clones = self['USER_TEMPLATE/VCENTER_LINKED_CLONES']
101
+
102
+ if use_linked_clones && use_linked_clones.downcase == 'yes'
103
+ # Delay the require until it is strictly needed
104
+ # This way we can avoid the vcenter driver dependency
105
+ # in no vCenter deployments
106
+ require 'vcenter_driver'
107
+
108
+ deploy_id = self['DEPLOY_ID']
109
+ vm_id = self['ID']
110
+ host_id = self['HISTORY_RECORDS/HISTORY[last()]/HID']
111
+ vi_client = VCenterDriver::VIClient.new_from_host(host_id)
112
+
113
+ vm = VCenterDriver::VirtualMachine.new(
114
+ vi_client,
115
+ deploy_id,
116
+ vm_id
117
+ )
118
+
119
+ error, vm_template_ref = vm.save_as_linked_clones(name)
120
+
121
+ raise error unless error.nil?
122
+
123
+ return vm_template_ref
124
+ end
125
+
97
126
  # --------------------------------------------------------------
98
127
  # Clone the source template
99
128
  # --------------------------------------------------------------
@@ -271,7 +300,7 @@ module OpenNebula::VirtualMachineExt
271
300
 
272
301
  raise rc.message if OpenNebula.is_error?(rc)
273
302
 
274
- binfo.merge!(backup_info) do |key, old_val, new_val|
303
+ binfo.merge!(backup_info) do |_key, old_val, new_val|
275
304
  new_val.nil? ? old_val : new_val
276
305
  end
277
306
 
@@ -472,7 +501,7 @@ module OpenNebula::VirtualMachineExt
472
501
  end
473
502
 
474
503
  binfo[:apps].each do |id|
475
- logger.info "Deleting applicance #{id}" if logger
504
+ logger.info "Deleting appliance #{id}" if logger
476
505
 
477
506
  papp = OpenNebula::MarketPlaceApp.new_with_id(id, @client)
478
507
 
@@ -450,6 +450,10 @@ module OpenNebula
450
450
  private
451
451
 
452
452
  def build_accounting(filter_flag, options, &block)
453
+
454
+ options[:start_time] = -1 if options[:start_time].nil?
455
+ options[:end_time] = -1 if options[:end_time].nil?
456
+
453
457
  xml_str = @client.call(VM_POOL_METHODS[:accounting],
454
458
  filter_flag,
455
459
  options[:start_time],
@@ -31,7 +31,15 @@ module OpenNebula
31
31
  :delete => "zone.delete",
32
32
  :addserver => "zone.addserver",
33
33
  :delserver => "zone.delserver",
34
- :resetserver => "zone.resetserver"
34
+ :resetserver => "zone.resetserver",
35
+ :enable => "zone.enable"
36
+ }
37
+
38
+ ZONE_STATES=%w{ENABLED DISABLED}
39
+
40
+ SHORT_ZONE_STATES={
41
+ "ENABLED" => "on",
42
+ "DISABLED" => "off"
35
43
  }
36
44
 
37
45
  # Creates a Zone description with just its identifier
@@ -179,6 +187,37 @@ module OpenNebula
179
187
  return call(ZONE_METHODS[:resetserver], @pe_id, server_id)
180
188
  end
181
189
 
190
+ # Enable zone
191
+ #
192
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
193
+ # otherwise
194
+ def enable()
195
+ return call(ZONE_METHODS[:enable], @pe_id, true)
196
+ end
197
+
198
+ # Disable zone, only readonly commands can be executed in disabled
199
+ # state
200
+ #
201
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
202
+ # otherwise
203
+ def disable()
204
+ return call(ZONE_METHODS[:enable], @pe_id, false)
205
+ end
206
+
207
+ #######################################################################
208
+ # Helpers to get Zone information
209
+ #######################################################################
210
+
211
+ # Returns the state of the Zone (numeric value)
212
+ def state
213
+ self['STATE'].to_i
214
+ end
215
+
216
+ # Returns the state of the Zone (string value)
217
+ def state_str
218
+ ZONE_STATES[state]
219
+ end
220
+
182
221
  private
183
222
 
184
223
  # These methods adds elements to the given node of the zone
data/lib/opennebula.rb CHANGED
@@ -77,5 +77,5 @@ require 'opennebula/flow'
77
77
  module OpenNebula
78
78
 
79
79
  # OpenNebula version
80
- VERSION = '6.0.3'
80
+ VERSION = '6.2.1'
81
81
  end