opennebula 4.0.1 → 4.1.80.beta

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.
data/NOTICE CHANGED
@@ -21,6 +21,9 @@ The following people have contributed to the development of the technology
21
21
  - Daniel Molina Aranda (dmolina@opennebula.org)
22
22
  - Hector Sanjuan Redondo (hsanjuan@opennebula.org)
23
23
 
24
+ The new features for service elasticity (oneFlow) introduced in OpenNebula 4.2
25
+ were funded by Blackberry in the context of the Fund a Feature Program.
26
+
24
27
  OpenNebula Project also acknowledges the contributions of C12G Labs developers.
25
28
 
26
29
  LICENSE
@@ -43,5 +46,6 @@ OpenNebula distribution includes third-party software under fully compatible
43
46
  open-source licenses. See the following directories and the NOTICE files
44
47
  they contain for more information:
45
48
 
49
+ - share/vendor
46
50
  - src/sunstone/public/vendor
47
51
  - src/oca/java/lib
@@ -54,5 +54,5 @@ require 'opennebula/system'
54
54
  module OpenNebula
55
55
 
56
56
  # OpenNebula version
57
- VERSION = '4.0.1'
57
+ VERSION = '4.1.80'
58
58
  end
@@ -162,11 +162,13 @@ module OpenNebula
162
162
  # Replaces the template contents
163
163
  #
164
164
  # @param new_template [String] New template contents
165
+ # @param append [true, false] True to append new attributes instead of
166
+ # replace the whole template
165
167
  #
166
168
  # @return [nil, OpenNebula::Error] nil in case of success, Error
167
169
  # otherwise
168
- def update(new_template)
169
- super(CLUSTER_METHODS[:update], new_template)
170
+ def update(new_template, append=false)
171
+ super(CLUSTER_METHODS[:update], new_template, append ? 1 : 0)
170
172
  end
171
173
 
172
174
  # ---------------------------------------------------------------------
@@ -106,11 +106,13 @@ module OpenNebula
106
106
  # Replaces the template contents
107
107
  #
108
108
  # @param new_template [String] New template contents
109
+ # @param append [true, false] True to append new attributes instead of
110
+ # replace the whole template
109
111
  #
110
112
  # @return [nil, OpenNebula::Error] nil in case of success, Error
111
113
  # otherwise
112
- def update(new_template)
113
- super(DATASTORE_METHODS[:update], new_template)
114
+ def update(new_template, append=false)
115
+ super(DATASTORE_METHODS[:update], new_template, append ? 1 : 0)
114
116
  end
115
117
 
116
118
  # Changes the owner/group
@@ -120,14 +120,16 @@ module OpenNebula
120
120
  # Replaces the template contents
121
121
  #
122
122
  # @param [String] new_template new template contents
123
+ # @param append [true, false] True to append new attributes instead of
124
+ # replace the whole template
123
125
  #
124
126
  # @return [nil, OpenNebula::Error] nil in case of success, Error
125
127
  # otherwise
126
- def update(new_template)
128
+ def update(new_template, append=false)
127
129
  rc = check_type()
128
130
  return rc if OpenNebula.is_error?(rc)
129
131
 
130
- super(DOCUMENT_METHODS[:update], new_template)
132
+ super(DOCUMENT_METHODS[:update], new_template, append ? 1 : 0)
131
133
  end
132
134
 
133
135
  # Changes the owner/group
@@ -56,15 +56,18 @@ module OpenNebula
56
56
  #
57
57
  # @params [String, nil] template_json string to be inserted in the
58
58
  # template. If nil @body will be used instead
59
+ # @param append [true, false] True to append new attributes instead of
60
+ # replace the whole template
61
+ #
59
62
  # @return [nil, OpenNebula::Error] nil in case of success, Error
60
63
  # otherwise
61
64
  #
62
- def update(template_json=nil)
65
+ def update(template_json=nil, append=false)
63
66
  template_json ||= @body.to_json
64
67
 
65
68
  text = build_template_xml(template_json)
66
69
 
67
- super(text)
70
+ super(text, append)
68
71
  end
69
72
 
70
73
  # Generates a json representing the object
@@ -133,9 +133,14 @@ module OpenNebula
133
133
 
134
134
  # Replaces the template contents
135
135
  #
136
- # +new_template+ New template contents
137
- def update(new_template)
138
- super(HOST_METHODS[:update], new_template)
136
+ # @param new_template [String] New template contents
137
+ # @param append [true, false] True to append new attributes instead of
138
+ # replace the whole template
139
+ #
140
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
141
+ # otherwise
142
+ def update(new_template, append=false)
143
+ super(HOST_METHODS[:update], new_template, append ? 1 : 0)
139
144
  end
140
145
 
141
146
  # Retrieves this Host's monitoring data from OpenNebula
@@ -114,10 +114,14 @@ module OpenNebula
114
114
 
115
115
  # Replaces the template contents
116
116
  #
117
- # +new_template+ New template contents. If no argument is provided
118
- # the object will be updated using the @xml variable
119
- def update(new_template=nil)
120
- super(IMAGE_METHODS[:update], new_template)
117
+ # @param new_template [String] New template contents
118
+ # @param append [true, false] True to append new attributes instead of
119
+ # replace the whole template
120
+ #
121
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
122
+ # otherwise
123
+ def update(new_template=nil, append=false)
124
+ super(IMAGE_METHODS[:update], new_template, append ? 1 : 0)
121
125
  end
122
126
 
123
127
  # Enables an Image
@@ -0,0 +1,387 @@
1
+ # -------------------------------------------------------------------------- #
2
+ # Copyright 2010-2013, C12G Labs S.L. #
3
+ # #
4
+ # Licensed under the Apache License, Version 2.0 (the "License"); you may #
5
+ # not use this file except in compliance with the License. You may obtain #
6
+ # a copy of the License at #
7
+ # #
8
+ # http://www.apache.org/licenses/LICENSE-2.0 #
9
+ # #
10
+ # Unless required by applicable law or agreed to in writing, software #
11
+ # distributed under the License is distributed on an "AS IS" BASIS, #
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
13
+ # See the License for the specific language governing permissions and #
14
+ # limitations under the License. #
15
+ #--------------------------------------------------------------------------- #
16
+
17
+ require 'uri'
18
+ require 'cloud/CloudClient'
19
+
20
+ include CloudCLI
21
+
22
+ module Role
23
+ # Actions that can be performed on the VMs of a given Role
24
+ SCHEDULE_ACTIONS = [
25
+ 'shutdown',
26
+ 'shutdown-hard',
27
+ 'undeploy',
28
+ 'undeploy-hard',
29
+ 'hold',
30
+ 'release',
31
+ 'stop',
32
+ 'suspend',
33
+ 'resume',
34
+ 'boot',
35
+ 'delete',
36
+ 'delete-recreate',
37
+ 'reboot',
38
+ 'reboot-hard',
39
+ 'poweroff',
40
+ 'poweroff-hard',
41
+ 'snapshot-create'
42
+ ]
43
+
44
+ STATE = {
45
+ 'PENDING' => 0,
46
+ 'DEPLOYING' => 1,
47
+ 'RUNNING' => 2,
48
+ 'UNDEPLOYING' => 3,
49
+ 'WARNING' => 4,
50
+ 'DONE' => 5,
51
+ 'FAILED_UNDEPLOYING' => 6,
52
+ 'FAILED_DEPLOYING' => 7,
53
+ 'SCALING' => 8,
54
+ 'FAILED_SCALING' => 9,
55
+ 'COOLDOWN' => 10
56
+ }
57
+
58
+ STATE_STR = [
59
+ 'PENDING',
60
+ 'DEPLOYING',
61
+ 'RUNNING',
62
+ 'UNDEPLOYING',
63
+ 'WARNING',
64
+ 'DONE',
65
+ 'FAILED_UNDEPLOYING',
66
+ 'FAILED_DEPLOYING',
67
+ 'SCALING',
68
+ 'FAILED_SCALING',
69
+ 'COOLDOWN'
70
+ ]
71
+
72
+ # Returns the string representation of the role state
73
+ # @param [String] state String number representing the state
74
+ # @return the state string
75
+ def self.state_str(state_number)
76
+ return STATE_STR[state_number.to_i]
77
+ end
78
+ end
79
+
80
+ module Service
81
+
82
+ STATE = {
83
+ 'PENDING' => 0,
84
+ 'DEPLOYING' => 1,
85
+ 'RUNNING' => 2,
86
+ 'UNDEPLOYING' => 3,
87
+ 'WARNING' => 4,
88
+ 'DONE' => 5,
89
+ 'FAILED_UNDEPLOYING' => 6,
90
+ 'FAILED_DEPLOYING' => 7,
91
+ 'SCALING' => 8,
92
+ 'FAILED_SCALING' => 9,
93
+ 'COOLDOWN' => 10
94
+ }
95
+
96
+ STATE_STR = [
97
+ 'PENDING',
98
+ 'DEPLOYING',
99
+ 'RUNNING',
100
+ 'UNDEPLOYING',
101
+ 'WARNING',
102
+ 'DONE',
103
+ 'FAILED_UNDEPLOYING',
104
+ 'FAILED_DEPLOYING',
105
+ 'SCALING',
106
+ 'FAILED_SCALING',
107
+ 'COOLDOWN'
108
+ ]
109
+
110
+ # Returns the string representation of the service state
111
+ # @param [String] state String number representing the state
112
+ # @return the state string
113
+ def self.state_str(state_number)
114
+ return STATE_STR[state_number.to_i]
115
+ end
116
+
117
+ # Build a json specifying an action
118
+ # @param [String] perform action to be performed (i.e: shutdowm)
119
+ # @param [Hash, nil] params contains the params for the action
120
+ # @return [String] json representing the action
121
+ def self.build_json_action(perform, params=nil)
122
+ body = Hash.new
123
+ body['perform'] = perform
124
+ body['params'] = params if params
125
+
126
+ action = Hash.new
127
+ action['action'] = body
128
+
129
+ JSON.pretty_generate action
130
+ end
131
+
132
+ # CLI options
133
+
134
+ DEFAULT_OPTIONS = [
135
+ ENDPOINT = {
136
+ :name => "server",
137
+ :short => "-s url",
138
+ :large => "--server url",
139
+ :format => String,
140
+ :description => "Service endpoint"
141
+ },
142
+ USERNAME={
143
+ :name => "username",
144
+ :short => "-u name",
145
+ :large => "--username name",
146
+ :format => String,
147
+ :description => "User name"
148
+ },
149
+ PASSWORD={
150
+ :name => "password",
151
+ :short => "-p pass",
152
+ :large => "--password pass",
153
+ :format => String,
154
+ :description => "User password"
155
+ }
156
+ ]
157
+
158
+ JSON_FORMAT = {
159
+ :name => "json",
160
+ :short => "-j",
161
+ :large => "--json",
162
+ :description => "Print the resource in JSON"
163
+ }
164
+
165
+ TOP = {
166
+ :name => "top",
167
+ :short => "-t",
168
+ :large => "--top",
169
+ :description => "Top for the command"
170
+ }
171
+
172
+ PERIOD = {
173
+ :name => "period",
174
+ :short => "-p x",
175
+ :large => "--period x",
176
+ :format => Integer,
177
+ :description => "Seconds between each group of actions"
178
+ }
179
+
180
+ NUMBER = {
181
+ :name => "number",
182
+ :short => "-n x",
183
+ :large => "--number x",
184
+ :format => Integer,
185
+ :description => "Number of VMs to apply the action to each period"
186
+ }
187
+
188
+ FORCE = {
189
+ :name => "force",
190
+ :short => "-f",
191
+ :large => "--force",
192
+ :description => "Force the new cardinality even if it is outside the limits"
193
+ }
194
+
195
+ # Format helpers
196
+
197
+ # def self.rname_to_id(name, poolname, options)
198
+ def self.rname_to_id(name, poolname)
199
+ return 0, name.to_i if name.match(/^[0123456789]+$/)
200
+
201
+ client = Service::Client.new()
202
+
203
+ resource_path = case poolname
204
+ when "SERVICE" then "/service"
205
+ when "SERVICE TEMPLATE" then "/service_template"
206
+ end
207
+
208
+ response = client.get(resource_path)
209
+
210
+ if CloudClient::is_error?(response)
211
+ return -1, "OpenNebula #{poolname} name not found," <<
212
+ " use the ID instead"
213
+ end
214
+
215
+ pool = JSON.parse(response.body)
216
+ name_to_id(name, pool, poolname)
217
+ end
218
+
219
+ def self.rname_to_id_desc(poolname)
220
+ "OpenNebula #{poolname} name or id"
221
+ end
222
+
223
+ def self.name_to_id(name, pool, ename)
224
+ if pool['DOCUMENT_POOL']['DOCUMENT'].nil?
225
+ return -1, "#{ename} named #{name} not found."
226
+ end
227
+
228
+ objects = pool['DOCUMENT_POOL']['DOCUMENT'].select {|object| object['NAME'] == name }
229
+
230
+ if objects.length>0
231
+ if objects.length>1
232
+ return -1, "There are multiple #{ename}s with name #{name}."
233
+ else
234
+ result = objects.first['ID']
235
+ end
236
+ else
237
+ return -1, "#{ename} named #{name} not found."
238
+ end
239
+
240
+ return 0, result
241
+ end
242
+
243
+ def self.list_to_id(names, poolname)
244
+
245
+ client = Service::Client.new()
246
+
247
+ resource_path = case poolname
248
+ when "SERVICE" then "/service"
249
+ when "SERVICE TEMPLATE" then "/service_template"
250
+ end
251
+
252
+ response = client.get(resource_path)
253
+
254
+ if CloudClient::is_error?(response)
255
+ return -1, "OpenNebula #{poolname} name not found," <<
256
+ " use the ID instead"
257
+ end
258
+
259
+ pool = JSON.parse(response.body)
260
+
261
+ result = names.split(',').collect { |name|
262
+ if name.match(/^[0123456789]+$/)
263
+ name.to_i
264
+ else
265
+ rc = name_to_id(name, pool, poolname)
266
+
267
+ if rc.first == -1
268
+ return rc[0], rc[1]
269
+ end
270
+
271
+ rc[1]
272
+ end
273
+ }
274
+
275
+ return 0, result
276
+ end
277
+
278
+ def self.list_to_id_desc(poolname)
279
+ "Comma-separated list of OpenNebula #{poolname} names or ids"
280
+ end
281
+
282
+ # Perform an action on several resources
283
+ # @param [Array] ids resources ids
284
+ # @param [Block] block action to be performed
285
+ # @return [Integer] exit_code
286
+ def self.perform_actions(ids, &block)
287
+ exit_code = 0
288
+
289
+ ids.each do |id|
290
+ response = block.call(id)
291
+
292
+ if CloudClient::is_error?(response)
293
+ puts response.to_s
294
+ exit_code = response.code.to_i
295
+ end
296
+ end
297
+
298
+ exit_code
299
+ end
300
+
301
+ class Client
302
+ def initialize(opts={})
303
+ @username = opts[:username] || ENV['ONEFLOW_USER']
304
+ @password = opts[:password] || ENV['ONEFLOW_PASSWORD']
305
+
306
+ url = opts[:url] || ENV['ONEFLOW_URL'] || 'http://localhost:2474'
307
+
308
+ if @username.nil? && @password.nil?
309
+ if ENV["ONE_AUTH"] and !ENV["ONE_AUTH"].empty? and File.file?(ENV["ONE_AUTH"])
310
+ one_auth = File.read(ENV["ONE_AUTH"])
311
+ elsif File.file?(ENV["HOME"]+"/.one/one_auth")
312
+ one_auth = File.read(ENV["HOME"]+"/.one/one_auth")
313
+ end
314
+
315
+ one_auth.rstrip!
316
+
317
+ @username, @password = one_auth.split(':')
318
+ end
319
+
320
+ @uri = URI.parse(url)
321
+
322
+ @user_agent = "OpenNebula #{CloudClient::VERSION} " <<
323
+ "(#{opts[:user_agent]||"Ruby"})"
324
+
325
+ @host = nil
326
+ @port = nil
327
+
328
+ if ENV['http_proxy']
329
+ uri_proxy = URI.parse(ENV['http_proxy'])
330
+ @host = uri_proxy.host
331
+ @port = uri_proxy.port
332
+ end
333
+ end
334
+
335
+ def get(path)
336
+ req = Net::HTTP::Proxy(@host, @port)::Get.new(path)
337
+
338
+ do_request(req)
339
+ end
340
+
341
+ def delete(path)
342
+ req =Net::HTTP::Proxy(@host, @port)::Delete.new(path)
343
+
344
+ do_request(req)
345
+ end
346
+
347
+ def post(path, body)
348
+ req = Net::HTTP::Proxy(@host, @port)::Post.new(path)
349
+ req.body = body
350
+
351
+ do_request(req)
352
+ end
353
+
354
+ def put(path, body)
355
+ req = Net::HTTP::Proxy(@host, @port)::Put.new(path)
356
+ req.body = body
357
+
358
+ do_request(req)
359
+ end
360
+
361
+ def login
362
+ req = Net::HTTP::Proxy(@host, @port)::Post.new('/login')
363
+
364
+ do_request(req)
365
+ end
366
+
367
+ def logout
368
+ req = Net::HTTP::Proxy(@host, @port)::Post.new('/logout')
369
+
370
+ do_request(req)
371
+ end
372
+
373
+ private
374
+
375
+ def do_request(req)
376
+ req.basic_auth @username, @password
377
+
378
+ req['User-Agent'] = @user_agent
379
+
380
+ res = CloudClient::http_start(@uri, @timeout) do |http|
381
+ http.request(req)
382
+ end
383
+
384
+ res
385
+ end
386
+ end
387
+ end
@@ -111,11 +111,14 @@ module OpenNebula
111
111
 
112
112
  # Replaces the template contents
113
113
  #
114
- # +new_template+ New template contents
115
- def update(new_template)
116
- return Error.new('ID not defined') if !@pe_id
117
-
118
- super(TEMPLATE_METHODS[:update], new_template)
114
+ # @param new_template [String] New template contents
115
+ # @param append [true, false] True to append new attributes instead of
116
+ # replace the whole template
117
+ #
118
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
119
+ # otherwise
120
+ def update(new_template, append=false)
121
+ super(TEMPLATE_METHODS[:update], new_template, append ? 1 : 0)
119
122
  end
120
123
 
121
124
  # Publishes the Template, to be used by other users
@@ -97,9 +97,14 @@ module OpenNebula
97
97
 
98
98
  # Replaces the template contents
99
99
  #
100
- # +new_template+ New template contents
101
- def update(new_template)
102
- super(USER_METHODS[:update], new_template)
100
+ # @param new_template [String] New template contents
101
+ # @param append [true, false] True to append new attributes instead of
102
+ # replace the whole template
103
+ #
104
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
105
+ # otherwise
106
+ def update(new_template, append=false)
107
+ super(USER_METHODS[:update], new_template, append ? 1 : 0)
103
108
  end
104
109
 
105
110
  # Deletes the User
@@ -178,10 +178,14 @@ module OpenNebula
178
178
 
179
179
  # Replaces the template contents
180
180
  #
181
- # @param new_template New template contents. If no argument is provided
182
- # the object will be updated using the @xml variable
183
- def update(new_template=nil)
184
- super(VM_METHODS[:update], new_template)
181
+ # @param new_template [String] New template contents
182
+ # @param append [true, false] True to append new attributes instead of
183
+ # replace the whole template
184
+ #
185
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
186
+ # otherwise
187
+ def update(new_template=nil, append=false)
188
+ super(VM_METHODS[:update], new_template, append ? 1 : 0)
185
189
  end
186
190
 
187
191
  # Returns the <USER_TEMPLATE> element in text form
@@ -91,10 +91,14 @@ module OpenNebula
91
91
 
92
92
  # Replaces the template contents
93
93
  #
94
- # +new_template+ New template contents. If no argument is provided
95
- # the object will be updated using the @xml variable
96
- def update(new_template=nil)
97
- super(VN_METHODS[:update], new_template)
94
+ # @param new_template [String] New template contents
95
+ # @param append [true, false] True to append new attributes instead of
96
+ # replace the whole template
97
+ #
98
+ # @return [nil, OpenNebula::Error] nil in case of success, Error
99
+ # otherwise
100
+ def update(new_template=nil, append=false)
101
+ super(VN_METHODS[:update], new_template, append ? 1 : 0)
98
102
  end
99
103
 
100
104
  # Publishes the VirtualNetwork, to be used by other users
metadata CHANGED
@@ -1,59 +1,54 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: opennebula
3
- version: !ruby/object:Gem::Version
4
- hash: 61
5
- prerelease:
6
- segments:
7
- - 4
8
- - 0
9
- - 1
10
- version: 4.0.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 4.1.80.beta
5
+ prerelease: 7
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - OpenNebula
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2013-05-20 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2013-07-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: nokogiri
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- hash: 3
29
- segments:
30
- - 0
31
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
32
22
  type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
35
- name: json
36
23
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: json
32
+ requirement: !ruby/object:Gem::Requirement
38
33
  none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
46
38
  type: :runtime
47
- version_requirements: *id002
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
48
46
  description: Libraries needed to talk to OpenNebula
49
47
  email: contact@opennebula.org
50
48
  executables: []
51
-
52
49
  extensions: []
53
-
54
50
  extra_rdoc_files: []
55
-
56
- files:
51
+ files:
57
52
  - lib/opennebula.rb
58
53
  - lib/opennebula/acl.rb
59
54
  - lib/opennebula/acl_pool.rb
@@ -73,6 +68,7 @@ files:
73
68
  - lib/opennebula/host_pool.rb
74
69
  - lib/opennebula/image.rb
75
70
  - lib/opennebula/image_pool.rb
71
+ - lib/opennebula/oneflow_client.rb
76
72
  - lib/opennebula/pool.rb
77
73
  - lib/opennebula/pool_element.rb
78
74
  - lib/opennebula/system.rb
@@ -97,36 +93,27 @@ files:
97
93
  - LICENSE
98
94
  homepage: http://opennebula.org
99
95
  licenses: []
100
-
101
96
  post_install_message:
102
97
  rdoc_options: []
103
-
104
- require_paths:
98
+ require_paths:
105
99
  - lib
106
- required_ruby_version: !ruby/object:Gem::Requirement
100
+ required_ruby_version: !ruby/object:Gem::Requirement
107
101
  none: false
108
- requirements:
109
- - - ">="
110
- - !ruby/object:Gem::Version
111
- hash: 3
112
- segments:
113
- - 0
114
- version: "0"
115
- required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
107
  none: false
117
- requirements:
118
- - - ">="
119
- - !ruby/object:Gem::Version
120
- hash: 3
121
- segments:
122
- - 0
123
- version: "0"
108
+ requirements:
109
+ - - ! '>'
110
+ - !ruby/object:Gem::Version
111
+ version: 1.3.1
124
112
  requirements: []
125
-
126
113
  rubyforge_project:
127
114
  rubygems_version: 1.8.25
128
115
  signing_key:
129
116
  specification_version: 3
130
117
  summary: OpenNebula Client API
131
118
  test_files: []
132
-
119
+ has_rdoc: