opennebula 6.8.0 → 6.8.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eedefbb85b95ea6fab4348f1a05bb71ef05532659c49a388cecf0ba3662afb75
4
- data.tar.gz: 10a3856b4e5794727d67687446ef420c8b0eb05b9f15ada412467d8e3da8b15a
3
+ metadata.gz: 5759fbb07bfb063ffa52b37dab6435776ed9d3fa2e14c686df1920d4012b7242
4
+ data.tar.gz: 602088834190d1305ad873f000bab5afe75858b87ab5c9891d2d869d518bf0bc
5
5
  SHA512:
6
- metadata.gz: ce540f42a07049fd4088692b31b3651dce29db28cee3bd199a3c67f17998aad1677a8aceb4d29a75deb93e9c5d7d985b9246cc7fa6c55721f9e3411e5779dd85
7
- data.tar.gz: c751b6ad361a43f7d87ef93734f881715b95c1b2c8c385b565c10ae7ce62b8d3d69db42d4ed2365cb4449d1ed1e2ea8a1958a38ab5705e4c755a6ef135e7249c
6
+ metadata.gz: 89b9a4ac5491c5b443d30692cd198bbe4176823df5b81fcc914cbb96be8d72d19b9ca6c4ae3e8c97f8754bd745273888cedfa094a71aae9c366cca75987ed152
7
+ data.tar.gz: 40f49cf1a941abc8f5e4f081393f10ec902229704c6ff24e033753b184007d5eaef8bf8d2c0dbeb255c30985b32e07508a36a1b0a2ab531c4437920dcfb436da
@@ -207,7 +207,7 @@ module DriverExecHelper
207
207
  config[name]=value
208
208
  end
209
209
  end
210
- rescue StandardException => e
210
+ rescue StandardError => e
211
211
  STDERR.puts "Error reading config: #{e.inspect}"
212
212
  STDERR.flush
213
213
  end
@@ -51,7 +51,7 @@ end
51
51
  module CloudClient
52
52
 
53
53
  # OpenNebula version
54
- VERSION = '6.8.0'
54
+ VERSION = '6.8.2'
55
55
 
56
56
  # #########################################################################
57
57
  # Default location for the authentication file
data/lib/models/role.rb CHANGED
@@ -468,8 +468,7 @@ module OpenNebula
468
468
  @body['last_vmname'] += 1
469
469
 
470
470
  Log.debug LOG_COMP,
471
- "Role #{name} : Trying to instantiate " \
472
- "template #{template_id}, with name #{vm_name}",
471
+ "Role #{name} : Instantiate template #{template_id}, name #{vm_name}",
473
472
  @service.id
474
473
 
475
474
  vm_id = template.instantiate(vm_name, on_hold?, extra_template)
@@ -481,33 +480,52 @@ module OpenNebula
481
480
  "#{template_id}; #{vm_id.message}"
482
481
 
483
482
  Log.error LOG_COMP, msg, @service.id
483
+
484
484
  @service.log_error(msg)
485
485
 
486
- return [false, 'Error trying to instantiate the VM ' \
487
- "Template #{template_id} in Role " \
486
+ return [false, "Error instantiating VM Template #{template_id} in Role " \
488
487
  "#{name}: #{vm_id.message}"]
489
488
  end
490
489
 
491
- Log.debug LOG_COMP, "Role #{name} : Instantiate success," \
492
- " VM ID #{vm_id}", @service.id
493
- node = {
494
- 'deploy_id' => vm_id
495
- }
490
+ Log.debug LOG_COMP,
491
+ "Role #{name} : Instantiate success, VM ID #{vm_id}",
492
+ @service.id
496
493
 
497
- vm = OpenNebula::VirtualMachine.new_with_id(vm_id,
498
- @service.client)
499
- rc = vm.info
494
+ node = { 'deploy_id' => vm_id }
495
+ vm = OpenNebula::VirtualMachine.new_with_id(vm_id, @service.client)
500
496
 
501
- if OpenNebula.is_error?(rc)
497
+ tries = 0
498
+ loop do
499
+ break if tries == 3
500
+
501
+ tries += 1
502
+
503
+ rc = vm.info
504
+
505
+ break unless OpenNebula.is_error?(rc)
506
+
507
+ sleep(tries * 0.5)
508
+ end
509
+
510
+ if tries == 3
502
511
  node['vm_info'] = nil
503
- else
504
- hash_vm = vm.to_hash['VM']
505
- vm_info = {}
506
- vm_info['VM'] = hash_vm.select {|v| VM_INFO.include?(v) }
507
512
 
508
- node['vm_info'] = vm_info
513
+ msg = "Role #{name} : Cannot get info for VM #{vm_id}"
514
+
515
+ Log.error LOG_COMP, msg, @service.id
516
+
517
+ @service.log_error(msg)
518
+
519
+ return [false,
520
+ "Error getting VM #{vm_id} info in Role #{name}: #{vm_id.message}"]
509
521
  end
510
522
 
523
+ hash_vm = vm.to_hash['VM']
524
+ vm_info = {}
525
+ vm_info['VM'] = hash_vm.select {|v| VM_INFO.include?(v) }
526
+
527
+ node['vm_info'] = vm_info
528
+
511
529
  @body['nodes'] << node
512
530
  end
513
531
 
@@ -637,8 +655,8 @@ module OpenNebula
637
655
  return OpenNebula::Error.new("Role #{name} is in DONE state")
638
656
  end
639
657
 
640
- do_offset = (!period.nil? && period.to_i > 0 &&
641
- !vms_per_period.nil? && vms_per_period.to_i > 0)
658
+ do_offset = !period.nil? && period.to_i > 0 &&
659
+ !vms_per_period.nil? && vms_per_period.to_i > 0
642
660
 
643
661
  nodes.each_with_index do |node, index|
644
662
  vm_id = node['deploy_id']
@@ -38,16 +38,16 @@ module OpenNebula
38
38
  #######################################################################
39
39
 
40
40
  DOCUMENT_METHODS = {
41
- :allocate => "document.allocate",
42
- :delete => "document.delete",
43
- :info => "document.info",
44
- :update => "document.update",
45
- :chown => "document.chown",
46
- :chmod => "document.chmod",
47
- :clone => "document.clone",
48
- :rename => "document.rename",
49
- :lock => "document.lock",
50
- :unlock => "document.unlock"
41
+ :allocate => 'document.allocate',
42
+ :delete => 'document.delete',
43
+ :info => 'document.info',
44
+ :update => 'document.update',
45
+ :chown => 'document.chown',
46
+ :chmod => 'document.chmod',
47
+ :clone => 'document.clone',
48
+ :rename => 'document.rename',
49
+ :lock => 'document.lock',
50
+ :unlock => 'document.unlock'
51
51
  }
52
52
 
53
53
  # Creates a Document Object description with just its identifier
@@ -55,14 +55,14 @@ module OpenNebula
55
55
  # @param [Integer] pe_id the id of the object
56
56
  #
57
57
  # @return [Nokogiri::XML::Node, REXML::Element] the empty xml
58
- def Document.build_xml(pe_id=nil)
58
+ def self.build_xml(pe_id = nil)
59
59
  if pe_id
60
60
  obj_xml = "<DOCUMENT><ID>#{pe_id}</ID></DOCUMENT>"
61
61
  else
62
- obj_xml = "<DOCUMENT></DOCUMENT>"
62
+ obj_xml = '<DOCUMENT></DOCUMENT>'
63
63
  end
64
64
 
65
- XMLElement.build_xml(obj_xml,'DOCUMENT')
65
+ XMLElement.build_xml(obj_xml, 'DOCUMENT')
66
66
  end
67
67
 
68
68
  # Class constructor
@@ -78,7 +78,7 @@ module OpenNebula
78
78
  def initialize(xml, client)
79
79
  LockableExt.make_lockable(self, DOCUMENT_METHODS)
80
80
 
81
- super(xml,client)
81
+ super(xml, client)
82
82
  end
83
83
 
84
84
  #######################################################################
@@ -99,7 +99,7 @@ module OpenNebula
99
99
  return rc
100
100
  end
101
101
 
102
- alias_method :info!, :info
102
+ alias info! info
103
103
 
104
104
  # Allocates a new Document in OpenNebula
105
105
  #
@@ -111,14 +111,14 @@ module OpenNebula
111
111
  super(DOCUMENT_METHODS[:allocate], description, document_type)
112
112
  end
113
113
 
114
- alias_method :allocate_xml, :allocate
114
+ alias allocate_xml allocate
115
115
 
116
116
  # Deletes the Document
117
117
  #
118
118
  # @return [nil, OpenNebula::Error] nil in case of success, Error
119
119
  # otherwise
120
- def delete()
121
- rc = check_type()
120
+ def delete
121
+ rc = check_type
122
122
  return rc if OpenNebula.is_error?(rc)
123
123
 
124
124
  return call(DOCUMENT_METHODS[:delete], @pe_id)
@@ -132,8 +132,8 @@ module OpenNebula
132
132
  #
133
133
  # @return [nil, OpenNebula::Error] nil in case of success, Error
134
134
  # otherwise
135
- def update(new_template, append=false)
136
- rc = check_type()
135
+ def update(new_template, append = false)
136
+ rc = check_type
137
137
  return rc if OpenNebula.is_error?(rc)
138
138
 
139
139
  super(DOCUMENT_METHODS[:update], new_template, append ? 1 : 0)
@@ -147,8 +147,8 @@ module OpenNebula
147
147
  #
148
148
  # @return [nil, OpenNebula::Error] nil in case of success, Error
149
149
  # otherwise
150
- def update_raw(template_raw, append=false)
151
- rc = check_type()
150
+ def update_raw(template_raw, append = false)
151
+ rc = check_type
152
152
  return rc if OpenNebula.is_error?(rc)
153
153
 
154
154
  return call(DOCUMENT_METHODS[:update], @pe_id, template_raw, append ? 1 : 0)
@@ -162,7 +162,7 @@ module OpenNebula
162
162
  # @return [nil, OpenNebula::Error] nil in case of success, Error
163
163
  # otherwise
164
164
  def chown(uid, gid)
165
- rc = check_type()
165
+ rc = check_type
166
166
  return rc if OpenNebula.is_error?(rc)
167
167
 
168
168
  super(DOCUMENT_METHODS[:chown], uid, gid)
@@ -175,7 +175,7 @@ module OpenNebula
175
175
  # @return [nil, OpenNebula::Error] nil in case of success, Error
176
176
  # otherwise
177
177
  def chmod_octet(octet)
178
- rc = check_type()
178
+ rc = check_type
179
179
  return rc if OpenNebula.is_error?(rc)
180
180
 
181
181
  super(DOCUMENT_METHODS[:chmod], octet)
@@ -187,8 +187,8 @@ module OpenNebula
187
187
  # @return [nil, OpenNebula::Error] nil in case of success, Error
188
188
  # otherwise
189
189
  def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
190
- other_m, other_a)
191
- rc = check_type()
190
+ other_m, other_a)
191
+ rc = check_type
192
192
  return rc if OpenNebula.is_error?(rc)
193
193
 
194
194
  super(DOCUMENT_METHODS[:chmod], owner_u, owner_m, owner_a, group_u,
@@ -202,10 +202,10 @@ module OpenNebula
202
202
  # @return [Integer, OpenNebula::Error] The new Document ID in case
203
203
  # of success, Error otherwise
204
204
  def clone(name)
205
- rc = check_type()
205
+ rc = check_type
206
206
  return rc if OpenNebula.is_error?(rc)
207
207
 
208
- return Error.new('ID not defined') if !@pe_id
208
+ return Error.new('ID not defined') unless @pe_id
209
209
 
210
210
  rc = @client.call(DOCUMENT_METHODS[:clone], @pe_id, name)
211
211
 
@@ -241,7 +241,7 @@ module OpenNebula
241
241
  # Returns true if the GROUP_U permission bit is set
242
242
  # @return [true, false] true if the GROUP_U permission bit is set
243
243
  def public?
244
- if self['PERMISSIONS/GROUP_U'] == "1" || self['PERMISSIONS/OTHER_U'] == "1"
244
+ if self['PERMISSIONS/GROUP_U'] == '1' || self['PERMISSIONS/OTHER_U'] == '1'
245
245
  true
246
246
  else
247
247
  false
@@ -252,7 +252,7 @@ module OpenNebula
252
252
  self.class::DOCUMENT_TYPE
253
253
  end
254
254
 
255
- private
255
+ private
256
256
 
257
257
  def set_publish(published)
258
258
  group_u = published ? 1 : 0
@@ -260,7 +260,7 @@ module OpenNebula
260
260
  chmod(-1, -1, -1, group_u, -1, -1, -1, -1, -1)
261
261
  end
262
262
 
263
- def check_type()
263
+ def check_type
264
264
  type = self['TYPE']
265
265
 
266
266
  if type.nil? && @pe_id
@@ -276,10 +276,13 @@ module OpenNebula
276
276
 
277
277
  if !type.nil? && type.to_i != document_type
278
278
  return OpenNebula::Error.new(
279
- "[DocumentInfo] Error getting document [#{@pe_id}].")
279
+ "[DocumentInfo] Error getting document [#{@pe_id}]."
280
+ )
280
281
  end
281
282
 
282
- return nil
283
+ return
283
284
  end
285
+
284
286
  end
287
+
285
288
  end
@@ -41,7 +41,7 @@ module OpenNebula
41
41
  #######################################################################
42
42
 
43
43
  DOCUMENT_POOL_METHODS = {
44
- :info => "documentpool.info"
44
+ :info => 'documentpool.info'
45
45
  }
46
46
 
47
47
  #######################################################################
@@ -55,10 +55,10 @@ module OpenNebula
55
55
  # http://docs.opennebula.io/stable/integration/system_interfaces/api.html
56
56
  #
57
57
  # @return [DocumentPool] the new object
58
- def initialize(client, user_id=-1)
59
- super('DOCUMENT_POOL','DOCUMENT',client)
58
+ def initialize(client, user_id = -1)
59
+ super('DOCUMENT_POOL', 'DOCUMENT', client)
60
60
 
61
- @user_id = user_id
61
+ @user_id = user_id
62
62
  end
63
63
 
64
64
  #######################################################################
@@ -99,4 +99,5 @@ module OpenNebula
99
99
  self.class::DOCUMENT_TYPE
100
100
  end
101
101
  end
102
+
102
103
  end
@@ -450,9 +450,7 @@ module OpenNebula::MarketPlaceAppExt
450
450
  ds = OpenNebula::Datastore.new_with_id(dsid, @client)
451
451
  rc = ds.info
452
452
 
453
- is_vcenter =
454
- !OpenNebula.is_error?(rc) &&
455
- (ds['TEMPLATE/DRIVER'] == 'vcenter')
453
+ is_vcenter = !OpenNebula.is_error?(rc) && ds['TEMPLATE/DRIVER'] == 'vcenter'
456
454
 
457
455
  if is_vcenter
458
456
  if options[:template].nil?
@@ -592,7 +590,7 @@ module OpenNebula::MarketPlaceAppExt
592
590
  pool = OpenNebula::MarketPlaceAppPool.new(@client)
593
591
  rc = pool.info_all
594
592
 
595
- return rc if OpenNebula.is_error?(rc)
593
+ return [rc, [], []] if OpenNebula.is_error?(rc)
596
594
 
597
595
  # Apps that have been already exported
598
596
  #
@@ -676,9 +674,7 @@ module OpenNebula::MarketPlaceAppExt
676
674
  end
677
675
 
678
676
  if OpenNebula.is_error?(rc)
679
- rc_rbck = rollback_export(exported, xpath != '//DISK')
680
-
681
- return rc_rbck if OpenNebula.is_error?(rc_rbck)
677
+ rollback_export(exported, xpath != '//DISK')
682
678
  end
683
679
 
684
680
  [rc, images, templates]
@@ -461,6 +461,10 @@ module Service
461
461
 
462
462
  req['User-Agent'] = @user_agent
463
463
 
464
+ if !@uri.path.nil?
465
+ req.instance_variable_set(:@path, @uri.path + req.path)
466
+ end
467
+
464
468
  CloudClient.http_start(@uri, @timeout) do |http|
465
469
  http.request(req)
466
470
  end
@@ -61,7 +61,9 @@ module OpenNebula
61
61
  :detachsg => 'vm.detachsg',
62
62
  :backup => 'vm.backup',
63
63
  :updatenic => 'vm.updatenic',
64
- :backupcancel => 'vm.backupcancel'
64
+ :backupcancel => 'vm.backupcancel',
65
+ :attachpci => 'vm.attachpci',
66
+ :detachpci => 'vm.detachpci'
65
67
  }
66
68
 
67
69
  VM_STATE=['INIT', 'PENDING', 'HOLD', 'ACTIVE', 'STOPPED', 'SUSPENDED', 'DONE', 'FAILED',
@@ -228,8 +230,68 @@ module OpenNebula
228
230
  'BACKUP_POWEROFF' => 'back'
229
231
  }
230
232
 
231
- HISTORY_ACTION=['none', 'migrate', 'live-migrate', 'shutdown', 'shutdown-hard', 'undeploy',
232
- 'undeploy-hard', 'hold', 'release', 'stop', 'suspend', 'resume', 'boot', 'delete', 'delete-recreate', 'reboot', 'reboot-hard', 'resched', 'unresched', 'poweroff', 'poweroff-hard', 'disk-attach', 'disk-detach', 'nic-attach', 'nic-detach', 'disk-snapshot-create', 'disk-snapshot-delete', 'terminate', 'terminate-hard', 'disk-resize', 'deploy', 'chown', 'chmod', 'updateconf', 'rename', 'resize', 'update', 'snapshot-resize', 'snapshot-delete', 'snapshot-revert', 'disk-saveas', 'disk-snapshot-revert', 'recover', 'retry', 'monitor', 'disk-snapshot-rename', 'alias-attach', 'alias-detach', 'poweroff-migrate', 'poweroff-hard-migrate', 'backup', 'nic-update']
233
+ HISTORY_ACTION=[
234
+ 'none',
235
+ 'migrate',
236
+ 'live-migrate',
237
+ 'shutdown',
238
+ 'shutdown-hard',
239
+ 'undeploy',
240
+ 'undeploy-hard',
241
+ 'hold',
242
+ 'release',
243
+ 'stop',
244
+ 'suspend',
245
+ 'resume',
246
+ 'boot',
247
+ 'delete',
248
+ 'delete-recreate',
249
+ 'reboot',
250
+ 'reboot-hard',
251
+ 'resched',
252
+ 'unresched',
253
+ 'poweroff',
254
+ 'poweroff-hard',
255
+ 'disk-attach',
256
+ 'disk-detach',
257
+ 'nic-attach',
258
+ 'nic-detach',
259
+ 'disk-snapshot-create',
260
+ 'disk-snapshot-delete',
261
+ 'terminate',
262
+ 'terminate-hard',
263
+ 'disk-resize',
264
+ 'deploy',
265
+ 'chown',
266
+ 'chmod',
267
+ 'updateconf',
268
+ 'rename',
269
+ 'resize',
270
+ 'update',
271
+ 'snapshot-resize',
272
+ 'snapshot-delete',
273
+ 'snapshot-revert',
274
+ 'disk-saveas',
275
+ 'disk-snapshot-revert',
276
+ 'recover',
277
+ 'retry',
278
+ 'monitor',
279
+ 'disk-snapshot-rename',
280
+ 'alias-attach',
281
+ 'alias-detach',
282
+ 'poweroff-migrate',
283
+ 'poweroff-hard-migrate',
284
+ 'backup',
285
+ 'nic-update',
286
+ 'backup-cancel',
287
+ 'sched-add',
288
+ 'sched-update',
289
+ 'sched-delete',
290
+ 'sg-attach',
291
+ 'sg-detach',
292
+ 'pci-attach',
293
+ 'pci-detach'
294
+ ]
233
295
 
234
296
  EXTERNAL_IP_ATTRS = [
235
297
  'GUEST_IP',
@@ -755,7 +817,7 @@ module OpenNebula
755
817
  # will replace the existing ones or delete it if empty. Attributes that
756
818
  # can be updated are: INPUT/{TYPE, BUS}; RAW/{TYPE, DATA, DATA_VMX},
757
819
  # OS/{BOOT, BOOTLOADER, ARCH, MACHINE, KERNEL, INITRD},
758
- # FEATURES/{ACPI, APIC, PAE, LOCALTIME, HYPERV, GUEST_AGENT},
820
+ # FEATURES/{ACPI, APIC, PAE, LOCALTIME, HYPERV, GUEST_AGENT, VIRTIO_SCSI_QUEUES, VIRTIO_BLK_QUEUES, IOTHREADS},
759
821
  # GRAPHICS/{TYPE, LISTEN, PASSWD, KEYMAP},
760
822
  # and VIDEO/{TYPE, IOMMU, ATS, VRAM, RESOLUTION}
761
823
  # @param append, append template, do not delete empty attributes
@@ -811,6 +873,24 @@ module OpenNebula
811
873
  @client.call(VM_METHODS[:backupcancel], @pe_id)
812
874
  end
813
875
 
876
+ # Attaches a PCI to a VM
877
+ #
878
+ # @param pci [String] Template containing a PCI element
879
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
880
+ # otherwise
881
+ def pci_attach(pci)
882
+ call(VM_METHODS[:attachpci], @pe_id, pci)
883
+ end
884
+
885
+ # Detaches a PCI from a VM
886
+ #
887
+ # @param pci_id [Integer] Id of the PCI to be detached
888
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
889
+ # otherwise
890
+ def pci_detach(pci_id)
891
+ call(VM_METHODS[:detachpci], @pe_id, pci_id)
892
+ end
893
+
814
894
  ########################################################################
815
895
  # Helpers to get VirtualMachine information
816
896
  ########################################################################
data/lib/opennebula.rb CHANGED
@@ -79,5 +79,5 @@ require 'opennebula/backupjob_pool'
79
79
  module OpenNebula
80
80
 
81
81
  # OpenNebula version
82
- VERSION = '6.8.0'
82
+ VERSION = '6.8.2'
83
83
  end
@@ -2028,7 +2028,7 @@ end
2028
2028
  :unitNumber => unumber
2029
2029
  }
2030
2030
  if @vi_client.vim.serviceContent.about.apiVersion.to_f >= 7.0
2031
- card_spec[:key] = Time.now.utc.strftime('%m%d%M%S%L').to_i
2031
+ card_spec[:key] = -100 - card_num.to_i
2032
2032
  end
2033
2033
 
2034
2034
  if (limit || rsrv) && (limit > 0)
@@ -2175,7 +2175,7 @@ end
2175
2175
  :addressType => 'generated'
2176
2176
  }
2177
2177
  if @vi_client.vim.serviceContent.about.apiVersion.to_f >= 7.0
2178
- card_spec[:key] = Time.now.utc.strftime('%m%d%M%S%L').to_i
2178
+ card_spec[:key] = -100 - card_num.to_i
2179
2179
  end
2180
2180
 
2181
2181
  if (limit || rsrv) && (limit > 0)
@@ -2720,7 +2720,7 @@ end
2720
2720
  img_name = VCenterDriver::FileHelper.unescape_path(img_name_escaped)
2721
2721
 
2722
2722
  vc_disks.each do |d|
2723
- key_matches = (unmanaged_key && d[:key] == unmanaged_key.to_i)
2723
+ key_matches = unmanaged_key && d[:key] == unmanaged_key.to_i
2724
2724
  path_matches = (d[:path_wo_ds] == img_name)
2725
2725
 
2726
2726
  if key_matches || path_matches
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opennebula
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.8.0
4
+ version: 6.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenNebula
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-17 00:00:00.000000000 Z
11
+ date: 2024-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rbvmomi
42
+ name: rbvmomi2
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="