openstack 1.1.2 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +58 -0
- data/README.md +19 -0
- data/VERSION +1 -0
- data/lib/openstack.rb +5 -19
- data/lib/openstack/compute/connection.rb +74 -31
- data/lib/openstack/compute/flavor.rb +18 -30
- data/lib/openstack/compute/server.rb +98 -0
- data/lib/openstack/connection.rb +45 -8
- data/lib/openstack/core_ext/to_query.rb +84 -0
- data/lib/openstack/identity/connection.rb +69 -0
- data/lib/openstack/identity/tenant.rb +17 -0
- data/lib/openstack/identity/user.rb +19 -0
- data/lib/openstack/network/network.rb +21 -22
- data/lib/openstack/network/router.rb +3 -5
- data/lib/openstack/swift/connection.rb +10 -4
- data/lib/openstack/volume/connection.rb +25 -0
- data/test/runner.rb +10 -0
- data/test/test_helper.rb +6 -9
- metadata +33 -35
- data/README.rdoc +0 -462
- data/lib/openstack/version.rb +0 -3
- data/test/authentication_test.rb +0 -120
- data/test/connection_test.rb +0 -39
- data/test/exception_test.rb +0 -49
- data/test/metadata_test.rb +0 -210
- data/test/servers_test.rb +0 -210
data/lib/openstack/connection.rb
CHANGED
@@ -22,11 +22,14 @@ class Connection
|
|
22
22
|
attr_reader :service_type
|
23
23
|
attr_reader :proxy_host
|
24
24
|
attr_reader :proxy_port
|
25
|
+
attr_reader :ca_cert
|
26
|
+
attr_reader :ssl_version
|
25
27
|
attr_reader :region
|
26
28
|
attr_reader :regions_list #e.g. os.connection.regions_list == {"region-a.geo-1" => [ {:service=>"object-store", :versionId=>"1.0"}, {:service=>"identity", :versionId=>"2.0"}], "region-b.geo-1"=>[{:service=>"identity", :versionId=>"2.0"}] }
|
27
29
|
|
28
30
|
attr_reader :http
|
29
31
|
attr_reader :is_debug
|
32
|
+
attr_reader :endpoint_type
|
30
33
|
|
31
34
|
# Creates and returns a new Connection object, depending on the service_type
|
32
35
|
# passed in the options:
|
@@ -52,6 +55,9 @@ class Connection
|
|
52
55
|
# :retry_auth - Whether to retry if your auth token expires (defaults to true)
|
53
56
|
# :proxy_host - If you need to connect through a proxy, supply the hostname here
|
54
57
|
# :proxy_port - If you need to connect through a proxy, supply the port here
|
58
|
+
# :ca_cert - path to a CA chain in PEM format
|
59
|
+
# :ssl_version - explicitly set an version (:SSLv3 etc, see OpenSSL::SSL::SSLContext::METHODS)
|
60
|
+
# :is_debug - Only for development purpose for debug output
|
55
61
|
#
|
56
62
|
# The options hash is used to create a new OpenStack::Connection object
|
57
63
|
# (private constructor) and this is passed to the constructor of OpenStack::Compute::Connection
|
@@ -72,6 +78,8 @@ class Connection
|
|
72
78
|
OpenStack::Image::Connection.new(connection)
|
73
79
|
when "network"
|
74
80
|
OpenStack::Network::Connection.new(connection)
|
81
|
+
when "identity"
|
82
|
+
OpenStack::Identity::Connection.new(connection)
|
75
83
|
else
|
76
84
|
raise Exception::InvalidArgument, "Invalid :service_type parameter: #{@service_type}"
|
77
85
|
end
|
@@ -105,9 +113,12 @@ class Connection
|
|
105
113
|
@retry_auth = options[:retry_auth]
|
106
114
|
@proxy_host = options[:proxy_host]
|
107
115
|
@proxy_port = options[:proxy_port]
|
116
|
+
@ca_cert = options[:ca_cert]
|
117
|
+
@ssl_version = options[:ssl_version]
|
108
118
|
@authok = false
|
109
119
|
@http = {}
|
110
120
|
@quantum_version = 'v2.0' if @service_type == 'network'
|
121
|
+
@endpoint_type = options[:endpoint_type] || "publicURL"
|
111
122
|
end
|
112
123
|
|
113
124
|
#specialised from of csreq for PUT object... uses body_stream if possible
|
@@ -155,7 +166,6 @@ class Connection
|
|
155
166
|
|
156
167
|
# This method actually makes the HTTP REST calls out to the server
|
157
168
|
def csreq(method,server,path,port,scheme,headers = {},data = nil,attempts = 0, &block) # :nodoc:
|
158
|
-
|
159
169
|
tries = @retries
|
160
170
|
time = 3
|
161
171
|
|
@@ -173,7 +183,7 @@ class Connection
|
|
173
183
|
response = @http[server].request(request)
|
174
184
|
end
|
175
185
|
if @is_debug
|
176
|
-
puts "REQUEST: #{
|
186
|
+
puts "REQUEST: #{auth_method} => #{path}"
|
177
187
|
puts data if data
|
178
188
|
puts "RESPONSE: #{response.body}"
|
179
189
|
puts '----------------------------------------'
|
@@ -232,6 +242,15 @@ class Connection
|
|
232
242
|
if scheme == "https"
|
233
243
|
@http[server].use_ssl = true
|
234
244
|
@http[server].verify_mode = OpenSSL::SSL::VERIFY_NONE
|
245
|
+
|
246
|
+
# use the ca_cert if were given one, and make sure we verify!
|
247
|
+
if ! @ca_cert.nil?
|
248
|
+
@http[server].ca_file = @ca_cert
|
249
|
+
@http[server].verify_mode = OpenSSL::SSL::VERIFY_PEER
|
250
|
+
end
|
251
|
+
|
252
|
+
# explicitly set the SSL version to use
|
253
|
+
@http[server].ssl_version= @ssl_version if ! @ssl_version.nil?
|
235
254
|
end
|
236
255
|
@http[server].start
|
237
256
|
rescue
|
@@ -280,6 +299,15 @@ class AuthV20
|
|
280
299
|
if connection.auth_scheme == "https"
|
281
300
|
server.use_ssl = true
|
282
301
|
server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
302
|
+
|
303
|
+
# use the ca_cert if were given one, and make sure we verify!
|
304
|
+
if !connection.ca_cert.nil?
|
305
|
+
server.ca_file = connection.ca_cert
|
306
|
+
server.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
307
|
+
end
|
308
|
+
|
309
|
+
# explicitly set the SSL version to use
|
310
|
+
server.ssl_version = connection.ssl_version if !connection.ssl_version.nil?
|
283
311
|
end
|
284
312
|
server.start
|
285
313
|
rescue
|
@@ -324,23 +352,23 @@ class AuthV20
|
|
324
352
|
if connection.region
|
325
353
|
endpoints.each do |ep|
|
326
354
|
if ep["region"] and ep["region"].upcase == connection.region.upcase
|
327
|
-
@uri = URI.parse(ep[
|
355
|
+
@uri = URI.parse(ep[connection.endpoint_type])
|
328
356
|
end
|
329
357
|
end
|
330
358
|
else
|
331
|
-
@uri = URI.parse(endpoints[0][
|
359
|
+
@uri = URI.parse(endpoints[0][connection.endpoint_type])
|
332
360
|
end
|
333
361
|
if @uri == ""
|
334
362
|
raise OpenStack::Exception::Authentication, "No API endpoint for region #{connection.region}"
|
335
363
|
else
|
336
364
|
if @version #already got one version of endpoints
|
337
|
-
current_version = get_version_from_response(service)
|
365
|
+
current_version = get_version_from_response(service,connection.endpoint_type)
|
338
366
|
if @version.to_f > current_version.to_f
|
339
367
|
next
|
340
368
|
end
|
341
369
|
end
|
342
370
|
#grab version to check next time round for multi-version deployments
|
343
|
-
@version = get_version_from_response(service)
|
371
|
+
@version = get_version_from_response(service,connection.endpoint_type)
|
344
372
|
connection.service_host = @uri.host
|
345
373
|
connection.service_path = @uri.path
|
346
374
|
connection.service_port = @uri.port
|
@@ -356,8 +384,8 @@ class AuthV20
|
|
356
384
|
server.finish if server.started?
|
357
385
|
end
|
358
386
|
|
359
|
-
def get_version_from_response(service)
|
360
|
-
service["endpoints"].first["versionId"] || parse_version_from_endpoint(service["endpoints"].first[
|
387
|
+
def get_version_from_response(service,endpoint_type)
|
388
|
+
service["endpoints"].first["versionId"] || parse_version_from_endpoint(service["endpoints"].first[endpoint_type])
|
361
389
|
end
|
362
390
|
|
363
391
|
#IN --> https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/46871569847393
|
@@ -381,6 +409,15 @@ class AuthV10
|
|
381
409
|
if connection.auth_scheme == "https"
|
382
410
|
server.use_ssl = true
|
383
411
|
server.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
412
|
+
|
413
|
+
# use the ca_cert if were given one, and make sure to verify!
|
414
|
+
if !connection.ca_cert.nil?
|
415
|
+
server.ca_file = connection.ca_cert
|
416
|
+
server.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
417
|
+
end
|
418
|
+
|
419
|
+
# explicitly set the SSL version to use
|
420
|
+
server.ssl_version = connection.ssl_version if !connection.ssl_version.nil?
|
384
421
|
end
|
385
422
|
server.start
|
386
423
|
rescue
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# Alias of <tt>to_s</tt>.
|
5
|
+
def to_param
|
6
|
+
to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
# Converts an object into a string suitable for use as a URL query string,
|
10
|
+
# using the given <tt>key</tt> as the param name.
|
11
|
+
def to_query(key)
|
12
|
+
"#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class NilClass
|
17
|
+
# Returns +self+.
|
18
|
+
def to_param
|
19
|
+
self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class TrueClass
|
24
|
+
# Returns +self+.
|
25
|
+
def to_param
|
26
|
+
self
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class FalseClass
|
31
|
+
# Returns +self+.
|
32
|
+
def to_param
|
33
|
+
self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Array
|
38
|
+
# Calls <tt>to_param</tt> on all its elements and joins the result with
|
39
|
+
# slashes. This is used by <tt>url_for</tt> in Action Pack.
|
40
|
+
def to_param
|
41
|
+
collect(&:to_param).join '/'
|
42
|
+
end
|
43
|
+
|
44
|
+
# Converts an array into a string suitable for use as a URL query string,
|
45
|
+
# using the given +key+ as the param name.
|
46
|
+
#
|
47
|
+
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
|
48
|
+
def to_query(key)
|
49
|
+
prefix = "#{key}[]"
|
50
|
+
|
51
|
+
if empty?
|
52
|
+
nil.to_query(prefix)
|
53
|
+
else
|
54
|
+
collect { |value| value.to_query(prefix) }.join '&'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Hash
|
60
|
+
# Returns a string representation of the receiver suitable for use as a URL
|
61
|
+
# query string:
|
62
|
+
#
|
63
|
+
# {name: 'David', nationality: 'Danish'}.to_query
|
64
|
+
# # => "name=David&nationality=Danish"
|
65
|
+
#
|
66
|
+
# An optional namespace can be passed to enclose key names:
|
67
|
+
#
|
68
|
+
# {name: 'David', nationality: 'Danish'}.to_query('user')
|
69
|
+
# # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
|
70
|
+
#
|
71
|
+
# The string pairs "key=value" that conform the query string
|
72
|
+
# are sorted lexicographically in ascending order.
|
73
|
+
#
|
74
|
+
# This method is also aliased as +to_param+.
|
75
|
+
def to_query(namespace = nil)
|
76
|
+
collect do |key, value|
|
77
|
+
unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
|
78
|
+
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
|
79
|
+
end
|
80
|
+
end.compact.sort! * '&'
|
81
|
+
end
|
82
|
+
|
83
|
+
alias_method :to_param, :to_query
|
84
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Identity
|
3
|
+
class Connection
|
4
|
+
attr_accessor :connection
|
5
|
+
|
6
|
+
def initialize(connection)
|
7
|
+
@connection = connection
|
8
|
+
OpenStack::Authentication.init(@connection)
|
9
|
+
end
|
10
|
+
|
11
|
+
def list_tenants
|
12
|
+
response = @connection.req('GET', '/tenants')
|
13
|
+
tenants_hash = JSON.parse(response.body)['tenants']
|
14
|
+
tenants_hash.map { |res| OpenStack::Identity::Tenant.new(res) }
|
15
|
+
end
|
16
|
+
alias_method :tenants, :list_tenants
|
17
|
+
|
18
|
+
# create_tenant(name: 'tenant1', description: 'description', enabled: true)
|
19
|
+
#
|
20
|
+
def create_tenant(options)
|
21
|
+
req_body = JSON.generate('tenant' => options)
|
22
|
+
response = @connection.req('POST', '/tenants', data: req_body)
|
23
|
+
OpenStack::Identity::Tenant.new(JSON.parse(response.body)['tenant'])
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_tenant_by_name(name)
|
27
|
+
response = @connection.req('GET', "/tenants?name=#{name}")
|
28
|
+
OpenStack::Identity::Tenant.new(JSON.parse(response.body)['tenant'])
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete_tenant(id)
|
32
|
+
@connection.req('DELETE', "/tenants/#{id}")
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
def list_users
|
37
|
+
response = @connection.req('GET', '/users')
|
38
|
+
users_hash = JSON.parse(response.body)['users']
|
39
|
+
users_hash.map { |res| OpenStack::Identity::User.new(res) }
|
40
|
+
end
|
41
|
+
alias_method :users, :list_users
|
42
|
+
|
43
|
+
# create_user(name: 'user1', password: 'password1', email: 'email@mail.ru')
|
44
|
+
#
|
45
|
+
def create_user(options)
|
46
|
+
req_body = JSON.generate('user' => options)
|
47
|
+
response = @connection.req('POST', '/users', data: req_body)
|
48
|
+
OpenStack::Identity::User.new(JSON.parse(response.body)['user'])
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete_user(id)
|
52
|
+
@connection.req('DELETE', "/users/#{id}")
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_user_to_tenant(options)
|
57
|
+
req_body = JSON.generate('role' => { 'tenantId' => options[:tenant_id], 'roleId' => options[:role_id] })
|
58
|
+
@connection.req('POST', "/users/#{options[:user_id]}/roleRefs", data: req_body)
|
59
|
+
true
|
60
|
+
end
|
61
|
+
|
62
|
+
def list_roles
|
63
|
+
response = @connection.req('GET', '/OS-KSADM/roles')
|
64
|
+
OpenStack.symbolize_keys(JSON.parse(response.body)['roles'])
|
65
|
+
end
|
66
|
+
alias_method :roles, :list_roles
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Identity
|
3
|
+
class Tenant
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :description
|
7
|
+
attr_reader :enabled
|
8
|
+
|
9
|
+
def initialize(tenant_info = {})
|
10
|
+
@id = tenant_info['id']
|
11
|
+
@name = tenant_info['name']
|
12
|
+
@description = tenant_info['description']
|
13
|
+
@enabled = tenant_info['enabled']
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Identity
|
3
|
+
class User
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :tenant_id
|
7
|
+
attr_reader :enabled
|
8
|
+
attr_reader :email
|
9
|
+
|
10
|
+
def initialize(tenant_info = {})
|
11
|
+
@id = tenant_info['id']
|
12
|
+
@name = tenant_info['name']
|
13
|
+
@tenant_id = tenant_info['tenant_id']
|
14
|
+
@email = tenant_info['email']
|
15
|
+
@enabled = tenant_info['enabled']
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,26 +1,25 @@
|
|
1
1
|
module OpenStack
|
2
|
-
module Network
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(net_info={})
|
14
|
-
@id = net_info["id"]
|
15
|
-
@name = net_info["name"]
|
16
|
-
@admin_state_up = net_info["admin_state_up"]
|
17
|
-
@status = net_info["status"]
|
18
|
-
@subnets = net_info["subnets"]
|
19
|
-
@shared = net_info["shared"]
|
20
|
-
@tenant_id = net_info["tenant_id"]
|
21
|
-
end
|
2
|
+
module Network
|
3
|
+
class Network
|
4
|
+
attr_reader :id
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :admin_state_up
|
7
|
+
attr_reader :status
|
8
|
+
attr_reader :subnets
|
9
|
+
attr_reader :shared
|
10
|
+
attr_reader :external
|
11
|
+
attr_reader :tenant_id
|
22
12
|
|
13
|
+
def initialize(net_info = {})
|
14
|
+
@id = net_info['id']
|
15
|
+
@name = net_info['name']
|
16
|
+
@admin_state_up = net_info['admin_state_up']
|
17
|
+
@status = net_info['status']
|
18
|
+
@subnets = net_info['subnets']
|
19
|
+
@shared = net_info['shared']
|
20
|
+
@external = net_info['router:external']
|
21
|
+
@tenant_id = net_info['tenant_id']
|
22
|
+
end
|
23
|
+
end
|
23
24
|
end
|
24
25
|
end
|
25
|
-
end
|
26
|
-
|
@@ -7,20 +7,18 @@ module Network
|
|
7
7
|
attr_reader :admin_state_up
|
8
8
|
attr_reader :status
|
9
9
|
attr_reader :external_gateway_info
|
10
|
-
attr_reader :
|
10
|
+
attr_reader :tenant_id
|
11
11
|
attr_reader :enable_snat
|
12
12
|
attr_reader :admin_state_up
|
13
13
|
|
14
14
|
def initialize(router_info={})
|
15
15
|
@name = router_info['name']
|
16
16
|
@status = router_info['status']
|
17
|
-
@
|
17
|
+
@external_gateway_info = router_info['external_gateway_info']
|
18
18
|
@admin_state_up = router_info['admin_state_up']
|
19
|
-
@
|
19
|
+
@tenant_id = router_info['tenant_id']
|
20
20
|
@id = router_info['id']
|
21
21
|
@enable_snat = router_info['enable_snat']
|
22
|
-
# @admin_state_up = router_info['external_gateway_info']['admin_state_up']
|
23
|
-
# @network_id = router_info['external_gateway_info']['network_id']
|
24
22
|
end
|
25
23
|
end
|
26
24
|
end
|
@@ -73,7 +73,7 @@ module Swift
|
|
73
73
|
# cf.containers(2,'cftest')
|
74
74
|
# => ["test", "video"]
|
75
75
|
def containers(limit = nil, marker = nil)
|
76
|
-
path = OpenStack.get_query_params({:limit=>limit, :marker=>marker}, [:limit, :marker], "")
|
76
|
+
path = OpenStack.get_query_params({:limit=>limit, :marker=>marker, :format=>'json'}, [:limit, :marker, :format], "")
|
77
77
|
response = @connection.req("GET", URI.encode(path))
|
78
78
|
OpenStack.symbolize_keys(JSON.parse(response.body)).inject([]){|res,cur| res << cur[:name]; res }
|
79
79
|
end
|
@@ -89,7 +89,7 @@ module Swift
|
|
89
89
|
# => { "container1" => { :bytes => "36543", :count => "146" },
|
90
90
|
# "container2" => { :bytes => "105943", :count => "25" } }
|
91
91
|
def containers_detail(limit = nil, marker = nil)
|
92
|
-
path = OpenStack.get_query_params({:limit=>limit, :marker=>marker}, [:limit, :marker], "")
|
92
|
+
path = OpenStack.get_query_params({:limit=>limit, :marker=>marker, :format=>'json'}, [:limit, :marker, :format], "")
|
93
93
|
response = @connection.req("GET", URI.encode(path))
|
94
94
|
OpenStack.symbolize_keys(JSON.parse(response.body)).inject({}){|res,current| res.merge!({current[:name]=>{:bytes=>current[:bytes].to_s,:count=>current[:count].to_s}}) ; res }
|
95
95
|
end
|
@@ -168,8 +168,14 @@ module Swift
|
|
168
168
|
@file = data
|
169
169
|
end
|
170
170
|
|
171
|
-
|
172
|
-
|
171
|
+
#for ruby 2.x
|
172
|
+
def read(length, buffer=nil)
|
173
|
+
if buffer.nil?
|
174
|
+
chunk = @file.read(length)
|
175
|
+
else
|
176
|
+
chunk = @file.read(length, buffer)
|
177
|
+
end
|
178
|
+
chunk
|
173
179
|
end
|
174
180
|
|
175
181
|
def eof!
|
@@ -88,6 +88,31 @@ module Volume
|
|
88
88
|
true
|
89
89
|
end
|
90
90
|
|
91
|
+
# [ {:extra_specs=>{:volume_backend_name=>"volumes-standard"}, :name=>"slow", :id=>"b3a104b6-fe70-4450-8681-e911a153f41f"},
|
92
|
+
# {:extra_specs=>{:volume_backend_name=>"volumes-speed"}, :name=>"fast", :id=>"0e278952-9baa-4aa8-88a7-fe8387f1d86c"} ]
|
93
|
+
def list_volume_types
|
94
|
+
response = @connection.req('GET', '/types')
|
95
|
+
OpenStack.symbolize_keys(JSON.parse(response.body)['volume_types'])
|
96
|
+
end
|
97
|
+
alias :types :list_volume_types
|
98
|
+
|
99
|
+
# get_quotas(1)
|
100
|
+
# => { "volumes_slow"=>-1, "snapshots_slow"=>-1, "gigabytes_slow"=>-1,
|
101
|
+
# "volumes_fast"=>-1, "snapshots_fast"=>-1, "gigabytes_fast"=>-1,
|
102
|
+
# "volumes"=>10, "snapshots"=>10, "gigabytes"=>1001, "id"=>"1"}
|
103
|
+
def get_quotas(tenant_id)
|
104
|
+
response = @connection.req('GET', "/os-quota-sets/#{tenant_id}")
|
105
|
+
JSON.parse(response.body)['quota_set']
|
106
|
+
end
|
107
|
+
|
108
|
+
# quota_set = { gigabytes: 500, gigabytes_slow: 200, gigabytes_fast: 300 }
|
109
|
+
# cinder.update_quotas(1, quota_set)
|
110
|
+
def update_quotas(tenant_id, quota_set)
|
111
|
+
req_body = JSON.generate({'quota_set' => quota_set})
|
112
|
+
response = @connection.req('PUT', "/os-quota-sets/#{tenant_id}", data: req_body)
|
113
|
+
JSON.parse(response.body)['quota_set']
|
114
|
+
end
|
115
|
+
|
91
116
|
private
|
92
117
|
|
93
118
|
#fudge... not clear if volumes support is available as 'native' volume API or
|