Skip to content

Commit

Permalink
Merge pull request #45 from ggiamarchi/issue#37
Browse files Browse the repository at this point in the history
Fix #37 - Avoid multiple 'connect_openstack'
  • Loading branch information
ggiamarchi committed Jun 24, 2014
2 parents a1923be + 8fcc351 commit 7d7322e
Show file tree
Hide file tree
Showing 13 changed files with 302 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def initialize(app, _env)
def call(env)
client = VagrantPlugins::Openstack
env[:openstack_client] = client
client.keystone.authenticate(env)
client.keystone.authenticate(env) if client.session.token.nil?
@app.call(env)
end
end
Expand Down
2 changes: 2 additions & 0 deletions source/lib/vagrant-openstack-provider/client/keystone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
module VagrantPlugins
module Openstack
class KeystoneClient
include Singleton

def initialize
@logger = Log4r::Logger.new('vagrant_openstack::keystone')
@session = VagrantPlugins::Openstack.session
Expand Down
21 changes: 15 additions & 6 deletions source/lib/vagrant-openstack-provider/client/neutron.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,30 @@
require 'restclient'
require 'json'

require 'vagrant-openstack-provider/client/utils'

module VagrantPlugins
module Openstack
class NeutronClient
include Singleton
include VagrantPlugins::Openstack::Utils

def initialize
@logger = Log4r::Logger.new('vagrant_openstack::neutron')
@session = VagrantPlugins::Openstack.session
end

def get_private_networks(_env)
networks_json = RestClient.get("#{@session.endpoints[:network]}/networks", 'X-Auth-Token' => @session.token, :accept => :json)
networks = []
JSON.parse(networks_json)['networks'].each do |n|
networks << { id: n['id'], name: n['name'] } if n['tenant_id'].eql? @session.project_id
def get_private_networks(env)
authenticated(env) do
networks_json = RestClient.get("#{@session.endpoints[:network]}/networks",
'X-Auth-Token' => @session.token,
:accept => :json) { |res| handle_response(res) }
networks = []
JSON.parse(networks_json)['networks'].each do |n|
networks << { id: n['id'], name: n['name'] } if n['tenant_id'].eql? @session.project_id
end
networks
end
networks
end
end
end
Expand Down
173 changes: 102 additions & 71 deletions source/lib/vagrant-openstack-provider/client/nova.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,109 +2,140 @@
require 'restclient'
require 'json'

require 'vagrant-openstack-provider/client/utils'

module VagrantPlugins
module Openstack
class NovaClient
include Singleton
include VagrantPlugins::Openstack::Utils

def initialize
@logger = Log4r::Logger.new('vagrant_openstack::nova')
@session = VagrantPlugins::Openstack.session
end

def get_all_flavors(_env)
flavors_json = RestClient.get("#{@session.endpoints[:compute]}/flavors", 'X-Auth-Token' => @session.token, :accept => :json)
JSON.parse(flavors_json)['flavors'].map { |fl| Item.new(fl['id'], fl['name']) }
def get_all_flavors(env)
authenticated(env) do
flavors_json = RestClient.get("#{@session.endpoints[:compute]}/flavors",
'X-Auth-Token' => @session.token,
:accept => :json) { |res| handle_response(res) }

return JSON.parse(flavors_json)['flavors'].map { |fl| Item.new(fl['id'], fl['name']) }
end
end

def get_all_images(_env)
images_json = RestClient.get("#{@session.endpoints[:compute]}/images", 'X-Auth-Token' => @session.token, :accept => :json)
JSON.parse(images_json)['images'].map { |im| Item.new(im['id'], im['name']) }
def get_all_images(env)
authenticated(env) do
images_json = RestClient.get(
"#{@session.endpoints[:compute]}/images",
'X-Auth-Token' => @session.token, :accept => :json) { |res| handle_response(res) }

JSON.parse(images_json)['images'].map { |im| Item.new(im['id'], im['name']) }
end
end

def create_server(_env, name, image_ref, flavor_ref, networks, keypair)
server = {}.tap do |s|
s['name'] = name
s['imageRef'] = image_ref
s['flavorRef'] = flavor_ref
s['key_name'] = keypair

unless networks.nil? || networks.empty?
s['networks'] = []
networks.each do |uuid|
s['networks'] << { uuid: uuid }
def create_server(env, name, image_ref, flavor_ref, networks, keypair)
authenticated(env) do
server = {}.tap do |s|
s['name'] = name
s['imageRef'] = image_ref
s['flavorRef'] = flavor_ref
s['key_name'] = keypair
unless networks.nil? || networks.empty?
s['networks'] = []
networks.each do |uuid|
s['networks'] << { uuid: uuid }
end
end
end
end

server = RestClient.post(
"#{@session.endpoints[:compute]}/servers", { server: server }.to_json,
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json)
server = RestClient.post(
"#{@session.endpoints[:compute]}/servers", { server: server }.to_json,
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json) { |res| handle_response(res) }

JSON.parse(server)['server']['id']
JSON.parse(server)['server']['id']
end
end

def delete_server(_env, server_id)
RestClient.delete(
"#{@session.endpoints[:compute]}/servers/#{server_id}",
'X-Auth-Token' => @session.token,
:accept => :json)
def delete_server(env, server_id)
authenticated(env) do
RestClient.delete(
"#{@session.endpoints[:compute]}/servers/#{server_id}",
'X-Auth-Token' => @session.token,
:accept => :json) { |res| handle_response(res) }
end
end

def suspend_server(_env, server_id)
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "suspend": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json)
def suspend_server(env, server_id)
authenticated(env) do
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "suspend": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json) { |res| handle_response(res) }
end
end

def resume_server(_env, server_id)
def resume_server(env, server_id)
# TODO(julienvey) check status before (if pause->unpause, if suspend->resume...)
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "resume": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json)
authenticated(env) do
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "resume": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json) { |res| handle_response(res) }
end
end

def stop_server(_env, server_id)
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "os-stop": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json)
def stop_server(env, server_id)
authenticated(env) do
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "os-stop": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json) { |res| handle_response(res) }
end
end

def start_server(_env, server_id)
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "os-start": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json)
def start_server(env, server_id)
authenticated(env) do
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action", '{ "os-start": null }',
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json) { |res| handle_response(res) }
end
end

def get_server_details(_env, server_id)
server_details = RestClient.get(
"#{@session.endpoints[:compute]}/servers/#{server_id}",
'X-Auth-Token' => @session.token,
:accept => :json)
JSON.parse(server_details)['server']
def get_server_details(env, server_id)
authenticated(env) do
server_details = RestClient.get(
"#{@session.endpoints[:compute]}/servers/#{server_id}",
'X-Auth-Token' => @session.token,
:accept => :json) { |res| handle_response(res) }

return JSON.parse(server_details)['server']
end
end

def add_floating_ip(env, server_id, floating_ip)
check_floating_ip(env, floating_ip)
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action",
{
addFloatingIp:
authenticated(env) do
check_floating_ip(env, floating_ip)
RestClient.post(
"#{@session.endpoints[:compute]}/servers/#{server_id}/action",
{
address: floating_ip
}
}.to_json,
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json)
addFloatingIp:
{
address: floating_ip
}
}.to_json,
'X-Auth-Token' => @session.token,
:accept => :json,
:content_type => :json) { |res| handle_response(res) }
end
end

private
Expand All @@ -113,7 +144,7 @@ def check_floating_ip(_env, floating_ip)
ip_details = RestClient.get(
"#{@session.endpoints[:compute]}/os-floating-ips",
'X-Auth-Token' => @session.token,
:accept => :json)
:accept => :json) { |res| handle_response(res) }

JSON.parse(ip_details)['floating_ips'].each do |ip|
next unless ip['ip'] == floating_ip
Expand Down
6 changes: 3 additions & 3 deletions source/lib/vagrant-openstack-provider/client/openstack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ def self.session
end

def self.keystone
Openstack::KeystoneClient.new
Openstack::KeystoneClient.instance
end

def self.nova
Openstack::NovaClient.new
Openstack::NovaClient.instance
end

def self.neutron
Openstack::NeutronClient.new
Openstack::NeutronClient.instance
end
end
end
38 changes: 38 additions & 0 deletions source/lib/vagrant-openstack-provider/client/utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'log4r'
require 'restclient'
require 'json'

require 'vagrant-openstack-provider/client/keystone'

module VagrantPlugins
module Openstack
module Utils
def handle_response(response)
case response.code
when 200, 201, 202, 204
response
when 401
fail Errors::AuthenticationRequired
when 400
fail Errors::VagrantOpenstackError, message: JSON.parse(response.to_s)['badRequest']['message']
else
fail Errors::VagrantOpenstackError, message: response.to_s
end
end

def authenticated(env)
nb_retry = 0
begin
return yield
rescue Errors::AuthenticationRequired => e
nb_retry += 1
env[:ui].warn(e)
env[:ui].warn(I18n.t('vagrant_openstack.trying_authentication'))
env[:openstack_client].keystone.authenticate(env)
retry if nb_retry < 3
raise e
end
end
end
end
end
5 changes: 5 additions & 0 deletions source/lib/vagrant-openstack-provider/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ module Openstack
module Errors
class VagrantOpenstackError < Vagrant::Errors::VagrantError
error_namespace('vagrant_openstack.errors')
error_key(:default)
end

class AuthenticationRequired < VagrantOpenstackError
error_key(:authentication_required)
end

class CreateBadState < VagrantOpenstackError
Expand Down
6 changes: 6 additions & 0 deletions source/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ en:
Starting server...
timeout: |-
Timeout!
trying_authentication: |-
Trying authentication...
rsync_folder: |-
Rsyncing folder: %{hostpath} => %{guestpath}
waiting_for_build: |-
Expand All @@ -50,6 +52,10 @@ en:
A keypair name is required.
errors:
default: |-
%{message}
authentication_required: |-
Authentication token is missing or no longer valid.
create_bad_state: |-
While creating the server, it transitioned to an unexpected
state: '%{state}', instead of properly booting. Run `vagrant status`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
end

before :each do
@keystone_client = VagrantPlugins::Openstack::KeystoneClient.new
@keystone_client = VagrantPlugins::Openstack::KeystoneClient.instance
end

context 'with good credentials' do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
session.token = '123456'
session.project_id = 'a1b2c3'
session.endpoints = { network: 'http://neutron' }
@neutron_client = VagrantPlugins::Openstack::NeutronClient.new
@neutron_client = VagrantPlugins::Openstack::NeutronClient.instance
end

describe 'get_private_networks' do
Expand Down
2 changes: 1 addition & 1 deletion source/spec/vagrant-openstack-provider/client/nova_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
session.token = '123456'
session.project_id = 'a1b2c3'
session.endpoints = { compute: 'http://nova/a1b2c3' }
@nova_client = VagrantPlugins::Openstack::NovaClient.new
@nova_client = VagrantPlugins::Openstack::NovaClient.instance
end

describe 'get_all_flavors' do
Expand Down
Loading

0 comments on commit 7d7322e

Please sign in to comment.