openstack 1.1.2 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: #{method} => #{path}"
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["publicURL"])
355
+ @uri = URI.parse(ep[connection.endpoint_type])
328
356
  end
329
357
  end
330
358
  else
331
- @uri = URI.parse(endpoints[0]["publicURL"])
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["publicURL"])
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
- class Network
4
-
5
- attr_reader :id
6
- attr_reader :name
7
- attr_reader :admin_state_up
8
- attr_reader :status
9
- attr_reader :subnets
10
- attr_reader :shared
11
- attr_reader :tenant_id
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 :tenant_ip
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
- @external_geteway_info = router_info['external_gateway_info']
17
+ @external_gateway_info = router_info['external_gateway_info']
18
18
  @admin_state_up = router_info['admin_state_up']
19
- @tenant_ip = router_info['tenant_ip']
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
- def read(foo)
172
- @file.read(@size)
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