opennebula 4.0.1 → 4.1.80.beta

Sign up to get free protection for your applications and to get access to all the features.
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: