Skip to content

Commit

Permalink
Read service endpoints from keystone authentication response
Browse files Browse the repository at this point in the history
  • Loading branch information
ggiamarchi committed Jun 20, 2014
1 parent bcbab8e commit ae2db14
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 21 deletions.
14 changes: 7 additions & 7 deletions source/lib/vagrant-openstack-provider/action/create_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ def call(env)

# Output the settings we're going to use to the user
env[:ui].info(I18n.t("vagrant_openstack.launching_server"))
env[:ui].info(" -- Flavor : #{flavor.name}")
env[:ui].info(" -- FlavorRef : #{flavor.id}")
env[:ui].info(" -- Image : #{image.name}")
env[:ui].info(" -- KeyPair : #{config.keypair_name}")
env[:ui].info(" -- ImageRef : #{image.id}")
env[:ui].info(" -- Tenant : #{config.tenant_name}")
env[:ui].info(" -- Name : #{server_name}")
env[:ui].info(" -- Flavor : #{flavor.name}")
env[:ui].info(" -- FlavorRef : #{flavor.id}")
env[:ui].info(" -- Image : #{image.name}")
env[:ui].info(" -- KeyPair : #{config.keypair_name}")
env[:ui].info(" -- ImageRef : #{image.id}")
env[:ui].info(" -- Tenant : #{config.tenant_name}")
env[:ui].info(" -- Name : #{server_name}")

server_id = client.create_server(env, server_name, image.id, flavor.id, config.keypair_name)

Expand Down
64 changes: 52 additions & 12 deletions source/lib/vagrant-openstack-provider/openstack_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ class OpenstackClient
def initialize()
@logger = Log4r::Logger.new("vagrant_openstack::openstack_client")
@token = nil
@project_id = nil
@endpoints = Hash.new
end

def authenticate(env)
@logger.debug("Authenticating on Keystone")
config = env[:machine].provider_config
env[:ui].info(I18n.t('vagrant_openstack.client.authentication',
:project => config.tenant_name,
:user => config.username))

authentication = RestClient.post(config.openstack_auth_url, {
:auth => {
:tenantName => config.tenant_name,
Expand All @@ -26,28 +32,34 @@ def authenticate(env)
:content_type => :json,
:accept => :json)

response_token = JSON.parse(authentication)['access']['token']
access = JSON.parse(authentication)['access']

read_endpoint_catalog(env, access['serviceCatalog'])
override_endpoint_catalog_with_user_config(env)
print_endpoint_catalog(env)

response_token = access['token']
@token = response_token['id']
@project_id = response_token['tenant']['id']
end

def get_all_flavors(env)
config = env[:machine].provider_config
flavors_json = RestClient.get("#{config.openstack_compute_url}/#{@project_id}/flavors",
flavors_json = RestClient.get("#{@endpoints['compute']}/flavors",
{"X-Auth-Token" => @token, :accept => :json})
return JSON.parse(flavors_json)['flavors'].map { |fl| Item.new(fl['id'], fl['name']) }
end

def get_all_images(env)
config = env[:machine].provider_config
images_json = RestClient.get("#{config.openstack_compute_url}/#{@project_id}/images",
images_json = RestClient.get("#{@endpoints['compute']}/images",
{"X-Auth-Token" => @token, :accept => :json})
return JSON.parse(images_json)['images'].map { |im| Item.new(im['id'], im['name']) }
end

def create_server(env, name, image_ref, flavor_ref, keypair)
config = env[:machine].provider_config
server = RestClient.post("#{config.openstack_compute_url}/#{@project_id}/servers", {
server = RestClient.post("#{@endpoints['compute']}/servers", {
:server => {
:name => name,
:imageRef => image_ref,
Expand All @@ -63,14 +75,14 @@ def create_server(env, name, image_ref, flavor_ref, keypair)

def delete_server(env, server_id)
config = env[:machine].provider_config
RestClient.delete("#{config.openstack_compute_url}/#{@project_id}/servers/#{server_id}",
RestClient.delete("#{@endpoints['compute']}/servers/#{server_id}",
"X-Auth-Token" => @token,
:accept => :json)
end

def suspend_server(env, server_id)
config = env[:machine].provider_config
RestClient.post("#{config.openstack_compute_url}/#{@project_id}/servers/#{server_id}/action", '{ "suspend": null }',
RestClient.post("#{@endpoints['compute']}/servers/#{server_id}/action", '{ "suspend": null }',
"X-Auth-Token" => @token,
:accept => :json,
:content_type => :json)
Expand All @@ -79,31 +91,31 @@ def suspend_server(env, server_id)
def resume_server(env, server_id)
#TODO(julienvey) check status before (if pause->unpause, if suspend->resume...)
config = env[:machine].provider_config
RestClient.post("#{config.openstack_compute_url}/#{@project_id}/servers/#{server_id}/action", '{ "resume": null }',
RestClient.post("#{@endpoints['compute']}/servers/#{server_id}/action", '{ "resume": null }',
"X-Auth-Token" => @token,
:accept => :json,
:content_type => :json)
end

def stop_server(env, server_id)
config = env[:machine].provider_config
RestClient.post("#{config.openstack_compute_url}/#{@project_id}/servers/#{server_id}/action", '{ "os-stop": null }',
RestClient.post("#{@endpoints['compute']}/servers/#{server_id}/action", '{ "os-stop": null }',
"X-Auth-Token" => @token,
:accept => :json,
:content_type => :json)
end

def start_server(env, server_id)
config = env[:machine].provider_config
RestClient.post("#{config.openstack_compute_url}/#{@project_id}/servers/#{server_id}/action", '{ "os-start": null }',
RestClient.post("#{@endpoints['compute']}/servers/#{server_id}/action", '{ "os-start": null }',
"X-Auth-Token" => @token,
:accept => :json,
:content_type => :json)
end

def get_server_details(env, server_id)
config = env[:machine].provider_config
server_details = RestClient.get("#{config.openstack_compute_url}/#{@project_id}/servers/#{server_id}",
server_details = RestClient.get("#{@endpoints['compute']}/servers/#{server_id}",
"X-Auth-Token" => @token,
:accept => :json)
return JSON.parse(server_details)['server']
Expand All @@ -112,7 +124,7 @@ def get_server_details(env, server_id)
def add_floating_ip(env, server_id, floating_ip)
check_floating_ip(env, floating_ip)
config = env[:machine].provider_config
RestClient.post("#{config.openstack_compute_url}/#{@project_id}/servers/#{server_id}/action", {
RestClient.post("#{@endpoints['compute']}/servers/#{server_id}/action", {
:addFloatingIp => {
:address => floating_ip
}
Expand All @@ -124,9 +136,37 @@ def add_floating_ip(env, server_id, floating_ip)

private

def read_endpoint_catalog(env, catalog)
env[:ui].info(I18n.t('vagrant_openstack.client.looking_for_available_endpoints'))
for service in catalog
se = service['endpoints']
if se.size > 1 then
env[:ui].warn I18n.t('vagrant_openstack.client.multiple_endpoint', :size => se.size, :type => service['type'])
env[:ui].warn " => #{service['endpoints'][0]['publicURL']}"
end
url = se[0]['publicURL'].strip
if !url.empty? then
@endpoints[service['type']] = url
end
end
end

def override_endpoint_catalog_with_user_config(env)
config = env[:machine].provider_config
if !config.openstack_compute_url.nil? then
@endpoints['compute'] = config.openstack_compute_url
end
end

def print_endpoint_catalog(env)
@endpoints.each do |key, value|
env[:ui].info(" -- #{key.ljust 15}: #{value}")
end
end

def check_floating_ip(env, floating_ip)
config = env[:machine].provider_config
ip_details = RestClient.get("#{config.openstack_compute_url}/#{@project_id}/os-floating-ips",
ip_details = RestClient.get("#{@endpoints['compute']}/os-floating-ips",
"X-Auth-Token" => @token,
:accept => :json)
for ip in JSON.parse(ip_details)['floating_ips']
Expand Down
8 changes: 8 additions & 0 deletions source/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,11 @@ en:
not created
long_not_created: |-
The server is not created. Run `vagrant up` to create it.
client:
looking_for_available_endpoints: |-
Looking for available endpoints...
multiple_endpoint: |-
%{size} endpoints are available for service '%{type}' but only the first one will be used
authentication: |-
Authentication on project %{project} with user %{user}
42 changes: 40 additions & 2 deletions source/spec/vagrant-openstack-provider/openstack_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
let(:config) {
double("config").tap do |config|
config.stub(:openstack_auth_url) { "http://keystoneAuthV2" }
config.stub(:openstack_compute_url) { "http://nova" }
config.stub(:openstack_compute_url) { nil }
config.stub(:tenant_name) { "testTenant" }
config.stub(:username) { "username" }
config.stub(:password) { "password" }
Expand All @@ -14,6 +14,8 @@

let(:env) {
Hash.new.tap do |env|
env[:ui] = double("ui")
env[:ui].stub(:info).with(anything())
env[:machine] = double("machine")
env[:machine].stub(:provider_config) { config }
end
Expand All @@ -29,6 +31,10 @@ def get_token()
def get_project_id()
return @project_id
end

def get_endpoints()
return @endpoints
end
end

let(:keystone_request_headers) {
Expand All @@ -42,26 +48,56 @@ def get_project_id()
'{"auth":{"tenantName":"testTenant","passwordCredentials":{"username":"username","password":"password"}}}'
}

let(:keystone_response_body) {
'{"access":{"token":{"id":"0123456789","tenant":{"id":"testTenantId"}},"serviceCatalog":[{"endpoints":[{"id":"eid1","publicURL":"http://nova"}],"type":"compute"},{"endpoints":[{"id":"eid2","publicURL":"http://neutron"}],"type":"network"}]}}'
}

before :each do
@os_client = OpenstackClientTest.new
end

context "with good credentials" do

it "store token and tenant id" do
stub_request(:post, "http://keystoneAuthV2").
with(
:body => keystone_request_body,
:headers => keystone_request_headers).
to_return(
:status => 200,
:body => '{"access":{"token":{"id":"0123456789","tenant":{"id":"testTenantId"}}}}',
:body => keystone_response_body,
:headers => keystone_request_headers)

@os_client.authenticate(env)

@os_client.get_token.should eq("0123456789")
@os_client.get_project_id.should eq("testTenantId")
@os_client.get_endpoints()['compute'].should eq('http://nova')
@os_client.get_endpoints()['network'].should eq('http://neutron')
end

context "with compute endpoint override" do
it "store token and tenant id" do
config.stub(:openstack_compute_url) { 'http://novaOverride' }

stub_request(:post, "http://keystoneAuthV2").
with(
:body => keystone_request_body,
:headers => keystone_request_headers).
to_return(
:status => 200,
:body => keystone_response_body,
:headers => keystone_request_headers)

@os_client.authenticate(env)

@os_client.get_token.should eq("0123456789")
@os_client.get_project_id.should eq("testTenantId")
@os_client.get_endpoints()['compute'].should eq('http://novaOverride')
@os_client.get_endpoints()['network'].should eq('http://neutron')
end
end

end

context "with wrong credentials" do
Expand Down Expand Up @@ -93,6 +129,8 @@ class OpenstackClientNovaTest < VagrantPlugins::Openstack::OpenstackClient
def initialize()
@token = "123456"
@project_id = "a1b2c3"
@endpoints = Hash.new
@endpoints['compute'] = "http://nova/a1b2c3"
end
end

Expand Down

0 comments on commit ae2db14

Please sign in to comment.