1
0
Fork 0
mirror of https://github.com/fog/fog.git synced 2022-11-09 13:51:43 -05:00

[openstack|compute] Add Tenants and Fix Authentication Implementation

Fixed typorgraphical errors. Authentication assumes or does not require
certain parameters that is actually needed depending on the setup or
scenario. Opted to simply make it detect it if not specified to make it
easier for first time users to use.

Conflicts:

	lib/fog/openstack.rb
This commit is contained in:
Nelvin Driz 2012-02-22 00:09:26 +08:00
parent 330c28c5a8
commit 7cf6031c81
32 changed files with 325 additions and 103 deletions

53
.fog Normal file
View file

@ -0,0 +1,53 @@
:default:
:aws_access_key_id:
:aws_secret_access_key:
:bluebox_api_key:
:bluebox_customer_id:
:brightbox_client_id:
:brightbox_secret:
:clodo_api_key:
:clodo_username:
:go_grid_api_key:
:go_grid_shared_secret:
:google_storage_access_key_id:
:google_storage_secret_access_key:
:linode_api_key:
:local_root:
:new_servers_password:
:new_servers_username:
:public_key_path:
:private_key_path:
:openstack_api_key:
:openstack_username:
:openstack_auth_url:
:openstack_tenant:
:ovirt_username:
:ovirt_password:
:ovirt_url:
:rackspace_api_key:
:rackspace_username:
:rackspace_servicenet:
:rackspace_cdn_ssl:
:slicehost_password:
:stormondemand_username:
:stormondemand_password:
:terremark_username:
:terremark_password:
:voxel_api_key:
:voxel_api_secret:
:zerigo_email:
:zerigo_token:
:dnsimple_email:
:dnsimple_password:
:dnsmadeeasy_api_key:
:dnsmadeeasy_secret_key:
:cloudstack_host:
:cloudstack_api_key:
:cloudstack_secret_access_key:
:vsphere_server:
:vsphere_username:
:vsphere_password:
:libvirt_username:
:libvirt_password:
:libvirt_uri:
:libvirt_ip_command:

View file

@ -63,6 +63,7 @@ Gem::Specification.new do |s|
s.add_development_dependency('shindo', '~>0.3.4')
s.add_development_dependency('virtualbox', '~>0.9.1')
s.add_development_dependency('fission')
s.add_development_dependency('pry')
# s.add_development_dependency('ruby-libvirt','~>0.4.0')
s.files = `git ls-files`.split("\n")

View file

@ -45,9 +45,8 @@ module Fog
# legacy v1.0 style auth
def self.authenticate_v1(options, connection_options = {})
openstack_auth_url = options[:openstack_auth_url]
uri = URI.parse(openstack_auth_url)
connection = Fog::Connection.new(openstack_auth_url, false, connection_options)
uri = options[:openstack_auth_uri]
connection = Fog::Connection.new(uri.to_s, false, connection_options)
@openstack_api_key = options[:openstack_api_key]
@openstack_username = options[:openstack_username]
response = connection.request({
@ -63,19 +62,18 @@ module Fog
return {
:token => response.headers['X-Auth-Token'],
:server_management_url => response.headers['X-Server-Management-Url']
}
:server_management_url => response.headers['X-Server-Management-Url']
}
end
# keystone style auth
def self.authenticate_v2(options, connection_options = {})
openstack_auth_url = options[:openstack_auth_url]
uri = URI.parse(openstack_auth_url)
connection = Fog::Connection.new(openstack_auth_url, false, connection_options)
# Keystone Style Auth
def self.authenticate_v2(options, connection_options = {})
uri = options[:openstack_auth_uri]
connection = Fog::Connection.new(uri.to_s, false, connection_options)
@openstack_api_key = options[:openstack_api_key]
@openstack_username = options[:openstack_username]
@openstack_tenant = options[:openstack_tenant]
@openstack_tenant = options[:openstack_tenant]
@compute_service_name = options[:openstack_compute_service_name]
req_body= {
@ -88,21 +86,47 @@ module Fog
}
req_body['auth']['tenantName'] = @openstack_tenant if @openstack_tenant
body = retrieve_tokens_v2(connection, req_body, uri)
svc = body['access']['serviceCatalog'].detect{|x| x['name'] == @compute_service_name}
unless svc
unless @openstack_tenant
response = connection.request({
:expects => [200, 204],
:headers => {'Content-Type' => 'application/json',
'X-Auth-Token' => body['access']['token']['id']},
:host => uri.host,
:method => 'GET',
:path => '/v2.0/tenants'
})
body = MultiJson.decode(response.body)
req_body['auth']['tenantName'] = body['tenants'].first['name']
end
body = retrieve_tokens_v2(connection, req_body, uri)
svc = body['access']['serviceCatalog'].
detect {|x| x['endpoints'].detect{|y| y['publicURL'].match(/(1\.1|2\.0)/) } }
end
mgmt_url = svc['endpoints'].detect{|x| x['publicURL']}['publicURL']
token = body['access']['token']['id']
{ :token => token,
:server_management_url => mgmt_url }
end
def self.retrieve_tokens_v2(connection, request_body, uri)
response = connection.request({
:expects => [200, 204],
:headers => {'Content-Type' => 'application/json'},
:headers => {'Content-Type' => 'application/json'},
:body => Fog::JSON.encode(req_body),
:host => uri.host,
:method => 'POST',
:path => (uri.path and not uri.path.empty?) ? uri.path : 'v2.0'
})
body=Fog::JSON.decode(response.body)
return {
:token => body['access']['token']['id'],
:access => body['access']
}
Fog::JSON.decode(response.body)
end
end

View file

@ -24,6 +24,8 @@ module Fog
collection :key_pairs
model :security_group
collection :security_groups
model :tenant
collection :tenants
request_path 'fog/openstack/requests/compute'
@ -33,14 +35,14 @@ module Fog
request :get_flavor_details
request :get_image_details
request :get_server_details
request :list_flavors
request :list_flavors_detail
request :list_images
request :list_images_detail
request :list_servers
request :list_servers_detail
request :server_action
request :change_password_server
@ -61,28 +63,29 @@ module Fog
request :update_meta
request :delete_meta
request :list_all_addresses
request :list_private_addresses
request :list_public_addresses
request :list_public_addresses
request :allocate_address
request :associate_address
request :disassociate_address
request :get_address
request :list_addresses
request :release_address
request :create_security_group
request :create_security_group_rule
request :delete_security_group
request :delete_security_group_rule
request :list_security_groups
request :get_security_group
request :create_key_pair
request :delete_key_pair
request :list_key_pairs
request :list_tenants
request :set_tenant
class Mock
@ -138,18 +141,24 @@ module Fog
class Real
def initialize(options={})
@openstack_api_key = options[:openstack_api_key]
@openstack_api_key = options[:openstack_api_key]
@openstack_username = options[:openstack_username]
@openstack_tenant = options[:openstack_tenant]
@openstack_compute_service_name = options[:openstack_compute_service_name] || 'nova'
@openstack_auth_url = options[:openstack_auth_url]
@openstack_tenant = options[:openstack_tenant]
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
@openstack_auth_token = options[:openstack_auth_token]
@openstack_management_url = options[:openstack_management_url]
@openstack_must_reauthenticate = false
@openstack_management_url = options[:openstack_management_url]
@openstack_must_reauthenticate = false
@openstack_compute_service_name = options[:openstack_compute_service_name] || 'nova'
@connection_options = options[:connection_options] || {}
authenticate
@persistent = options[:persistent] || false
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
@identity_connection = Fog::Connection.new(
"#{@openstack_auth_uri.scheme}://#{@openstack_auth_uri.host}:#{@openstack_auth_uri.port}",
false, @connection_options)
end
def reload
@ -164,7 +173,7 @@ module Fog
'X-Auth-Token' => @auth_token
}.merge!(params[:headers] || {}),
:host => @host,
:path => "#{@path}/#{params[:path]}",
:path => "#{@path}/#{@tenant_id}/#{params[:path]}",
:query => ('ignore_awful_caching' << Time.now.to_i.to_s)
}))
rescue Excon::Errors::Unauthorized => error
@ -172,20 +181,22 @@ module Fog
@openstack_must_reauthenticate = true
authenticate
retry
else # bad credentials
else # Bad Credentials
raise error
end
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::Compute::OpenStack::NotFound.slurp(error)
else
error
end
when Excon::Errors::NotFound
Fog::Compute::OpenStack::NotFound.slurp(error)
else
error
end
end
unless response.body.empty?
response.body = Fog::JSON.decode(response.body)
end
response
end
@ -196,38 +207,31 @@ module Fog
options = {
:openstack_api_key => @openstack_api_key,
:openstack_username => @openstack_username,
:openstack_auth_url => @openstack_auth_url,
:openstack_tenant => @openstack_tenant,
:openstack_auth_uri => @openstack_auth_uri,
:openstack_tenant => @openstack_tenant,
:openstack_compute_service_name => @openstack_compute_service_name
}
if @openstack_auth_url =~ /\/v2.0\//
if @openstack_auth_uri.path =~ /\/v2.0\//
credentials = Fog::OpenStack.authenticate_v2(options, @connection_options)
else
credentials = Fog::OpenStack.authenticate_v1(options, @connection_options)
end
@auth_token = credentials[:token]
if svc = credentials[:access]['serviceCatalog'].detect{|x| x['name'] == @openstack_compute_service_name}
mgmt_url = svc['endpoints'].detect{|x| x['publicURL']}['publicURL']
url = mgmt_url
uri = URI.parse(url)
else
raise "Unable to find Compute service in Catalog."
end
@openstack_must_reauthenticate = false
@auth_token = credentials[:token]
@openstack_management_url = credentials[:server_management_url]
uri = URI.parse(@openstack_management_url)
else
@auth_token = @openstack_auth_token
uri = URI.parse(@openstack_management_url)
end
@host = uri.host
@path = uri.path
@path.sub!(/\/$/, '')
unless @path.match(/1\.1/)
raise Fog::Compute::OpenStack::ServiceUnavailable.new(
"OpenStack binding only supports version 1.1")
end
@path, @tenant_id = uri.path.scan(/(\/.*)\/(.*)/).flatten
@port = uri.port
@scheme = uri.scheme
true
end
end

View file

@ -14,7 +14,6 @@ module Fog
end
def get(address_id)
if address = connection.get_address(address_id).body['floating_ip']
new(address)
end

View file

@ -2,7 +2,7 @@ require 'fog/core/model'
module Fog
module Compute
class Openstack
class OpenStack
class KeyPair < Fog::Model

View file

@ -3,16 +3,16 @@ require 'fog/openstack/models/compute/key_pair'
module Fog
module Compute
class HP
class OpenStack
class KeyPairs < Fog::Collection
model Fog::Compute::Openstack::KeyPair
model Fog::Compute::OpenStack::KeyPair
def all
items = []
items = Array.new
connection.list_key_pairs.body['keypairs'].each do |kp|
items = items + kp.map { |key, value| value }
items = items + kp.values
end
load(items)
end
@ -21,11 +21,11 @@ module Fog
if key_pair_name
self.all.select {|kp| kp.name == key_pair_name}.first
end
rescue Fog::Compute::Openstack::NotFound
rescue Fog::Compute::OpenStack::NotFound
nil
end
end
end
end
end
end

View file

@ -2,7 +2,7 @@ require 'fog/core/model'
module Fog
module Compute
class Openstack
class OpenStack
class SecurityGroup < Fog::Model

View file

@ -3,11 +3,11 @@ require 'fog/openstack/models/compute/security_group'
module Fog
module Compute
class Openstack
class OpenStack
class SecurityGroups < Fog::Collection
model Fog::Compute::Openstack::SecurityGroup
model Fog::Compute::OpenStack::SecurityGroup
def all
load(connection.list_security_groups.body['security_groups'])
@ -17,11 +17,11 @@ module Fog
if security_group_id
new(connection.get_security_group(security_group_id).body['security_group'])
end
rescue Fog::Compute::Openstack::NotFound
rescue Fog::Compute::OpenStack::NotFound
nil
end
end
end
end
end
end

View file

@ -23,24 +23,24 @@ module Fog
attribute :availability_zone
attribute :user_data_encoded
attribute :state, :aliases => 'status'
attribute :tenant_id
attribute :user_id
attribute :key_name
attr_reader :password
attr_writer :private_key, :private_key_path, :public_key, :public_key_path, :username, :image_ref, :flavor_ref
def initialize(attributes={})
@connection = attributes[:connection]
attributes[:metadata] = {}
self.security_groups = attributes.delete(:security_groups)
self.min_count = attributes.delete(:min_count)
self.max_count = attributes.delete(:max_count)
super
end
@ -77,7 +77,7 @@ module Fog
def private_ip_address
nil
end
def private_key_path
@private_key_path ||= Fog.credentials[:private_key_path]
@private_key_path &&= File.expand_path(@private_key_path)
@ -90,7 +90,7 @@ module Fog
def public_ip_address
addresses['public'].first
end
def public_key_path
@public_key_path ||= Fog.credentials[:public_key_path]
@public_key_path &&= File.expand_path(@public_key_path)
@ -149,11 +149,11 @@ module Fog
connection.confirm_resize_server(id)
true
end
def security_groups=(new_security_groups)
@security_groups = new_security_groups
end
def reboot(type = 'SOFT')
requires :id
connection.reboot_server(id, type)

View file

@ -0,0 +1,19 @@
require 'fog/core/model'
module Fog
module Compute
class OpenStack
class Tenant < Fog::Model
identity :id
attribute :description
attribute :enabled
attribute :name
def to_s
self.name
end
end # class Tenant
end # class OpenStack
end # module Compute
end # module Fog

View file

@ -0,0 +1,16 @@
require 'fog/core/collection'
require 'fog/openstack/models/compute/tenant'
module Fog
module Compute
class OpenStack
class Tenants < Fog::Collection
model Fog::Compute::OpenStack::Tenant
def all
load(connection.list_tenants.body['tenants'])
end
end # class Tenants
end # class OpenStack
end # module Compute
end # module Fog

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def allocate_address

View file

@ -1,18 +1,18 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def associate_address(server_id, ip_address)
body = { 'addFloatingIp' => { 'server' => server_id, 'address' => ip_address }}
request(
:body => MultiJson.encode(body),
:expects => 202,
:method => 'POST',
:path => "servers/#{server_id}/action.json"
)
end
end

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def create_key_pair(key_name, public_key = nil)

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def create_security_group(name, description)

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def create_security_group_rule(parent_group_id, ip_protocol, from_port, to_port, cidr, group_id=nil)

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def delete_key_pair(key_name)

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def delete_security_group(security_group_id)

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def delete_security_group_rule(security_group_rule_id)

View file

@ -1,20 +1,20 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def disassociate_address(server_id, ip_address)
body = { 'removeFloatingIp' => { 'server' => server_id, 'address' => ip_address }}
request(
:body => MultiJson.encode(body),
:expects => 202,
:method => 'POST',
:path => "servers/#{server_id}/action.json"
)
end
end

View file

@ -1,10 +1,10 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def get_address(address_id)
request(
:expects => [200],
:method => 'GET',

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def get_security_group(security_group_id)

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def list_all_addresses(server_id)
@ -9,7 +9,7 @@ module Fog
:method => 'GET',
:path => "os-floating-ips.json"
)
end
end

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def list_key_pairs

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def list_security_groups

View file

@ -0,0 +1,23 @@
module Fog
module Compute
class OpenStack
class Real
def list_security_groups
request(
:expects => [200],
:method => 'GET',
:path => 'os-security-groups.json'
)
end
end
class Mock
end
end
end
end

View file

@ -0,0 +1,43 @@
module Fog
module Compute
class OpenStack
class Real
def list_tenants
response = @identity_connection.request({
:expects => [200, 204],
:headers => {'Content-Type' => 'application/json',
'X-Auth-Token' => @auth_token},
:method => 'GET',
:path => '/v2.0/tenants'
})
response.body = MultiJson.decode(response.body)
response
end
end
class Mock
def list_tenants
response = Excon::Response.new
response.status = [200, 204][rand(1)]
response.body = {
'tenants' => [
{'id' => '1',
'description' => 'Has access to everything',
'enabled' => true,
'name' => 'admin'},
{'id' => '2',
'description' => 'Normal tenant',
'enabled' => true,
'name' => 'default'},
{'id' => '3',
'description' => 'Disabled tenant',
'enabled' => false,
'name' => 'disabled'}
]
}
response
end
end # class Mock
end #class OpenStack
end # module Compute
end # module Fog

View file

@ -1,6 +1,6 @@
module Fog
module Compute
class Openstack
class OpenStack
class Real
def release_address(address_id)

View file

@ -0,0 +1,21 @@
module Fog
module Compute
class OpenStack
class Real
def set_tenant(tenant)
@openstack_must_reauthenticate = true
@openstack_tenant = tenant.to_s
authenticate
end
end
class Mock
def set_tenant(tenant)
true
end
end
end # class OpenStack
end # module Compute
end # module Fog

View file

@ -50,7 +50,7 @@ if Fog.mock?
:openstack_api_key => 'openstack_api_key',
:openstack_username => 'openstack_username',
:openstack_tenant => 'openstack_tenant',
:openstack_auth_url => 'openstack_auth_url',
:openstack_auth_url => 'http://openstack:35357/v2.0/tokens',
:ovirt_url => 'http://ovirt:8080/api',
:ovirt_username => 'admin@internal',
:ovirt_password => '123123',

View file

@ -0,0 +1,19 @@
Shindo.tests('Fog::Compute[:openstack] | tenant requests', ['openstack']) do
@tenant_format = {
'id' => String,
'name' => String,
'enabled' => Fog::Boolean,
'description' => String
}
tests('success') do
tests('#list_tenants').formats({'tenants' => [@tenant_format]}) do
Fog::Compute[:openstack].list_tenants.body
end
tests('#set_tenant("admin")').succeeds do
Fog::Compute[:openstack].set_tenant("admin")
end
end
end