Move openstackclient parent provider to openstacklib
This patch abandons the use of the Aviator library for interacting with the openstack APIs in favor of the universal openstack client[1]. This work has already been implemented in the keystone module. This patch moves that work into openstacklib in order to make it available for the other modules. [1] https://wiki.openstack.org/wiki/OpenStackClient Change-Id: I68705c28955a54e26d98f1de718016691c64e4b1
This commit is contained in:
parent
75124baf89
commit
ed58789665
|
@ -1,7 +1,6 @@
|
|||
fixtures:
|
||||
repositories:
|
||||
apache: git://github.com/puppetlabs/puppetlabs-apache.git
|
||||
aviator: git://github.com/aimonb/puppet_aviator.git
|
||||
concat: git://github.com/puppetlabs/puppetlabs-concat.git
|
||||
mysql: git://github.com/puppetlabs/puppetlabs-mysql.git
|
||||
postgresql: git://github.com/puppetlabs/puppetlabs-postgresql.git
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
*.swp
|
||||
spec/fixtures/*
|
||||
!spec/fixtures/vcr/
|
||||
pkg
|
||||
Gemfile.lock
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -8,8 +8,6 @@ group :development, :test do
|
|||
gem 'rspec'
|
||||
gem 'mocha'
|
||||
gem 'json'
|
||||
gem 'faraday', '0.8.8', :require => false
|
||||
gem 'vcr', :require => false
|
||||
end
|
||||
|
||||
if puppetversion = ENV['PUPPET_GEM_VERSION']
|
||||
|
|
|
@ -1,297 +0,0 @@
|
|||
require 'puppet'
|
||||
require 'puppet/feature/aviator'
|
||||
require 'puppet/util/inifile'
|
||||
|
||||
class Puppet::Provider::Aviator < Puppet::Provider
|
||||
|
||||
def session
|
||||
@session ||= authenticate(resource[:auth], resource[:log_file])
|
||||
end
|
||||
|
||||
def self.session
|
||||
@session ||= authenticate(nil, nil)
|
||||
end
|
||||
|
||||
def request(service, request, &block)
|
||||
self.class.make_request(service, request, session_data, &block)
|
||||
end
|
||||
|
||||
def self.request(service, request, &block)
|
||||
self.make_request(service, request, session_data, &block)
|
||||
end
|
||||
|
||||
# needed for tests
|
||||
def session_data
|
||||
@session_data
|
||||
end
|
||||
|
||||
def self.session_data
|
||||
@session_data
|
||||
end
|
||||
|
||||
def session_data=(data)
|
||||
@session_data=data
|
||||
end
|
||||
|
||||
def self.session_data=(data)
|
||||
@session_data=data
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Attempt to find credentials in this order:
|
||||
# 1. username,password,tenant,host set in type parameters
|
||||
# 2. openrc file path set in type parameters
|
||||
# 3. service token and host set in type parameters
|
||||
# 4. username,password,tenant,host set in environment variables
|
||||
# 5. service token and host set in keystone.conf (backwards compatible version)
|
||||
def authenticate(auth_params, log_file)
|
||||
auth_params ||= {}
|
||||
if password_credentials_set?(auth_params)
|
||||
@session = get_authenticated_session(auth_params, log_file)
|
||||
|
||||
elsif openrc_set?(auth_params)
|
||||
credentials = get_credentials_from_openrc(auth_params['openrc'])
|
||||
@session = get_authenticated_session(credentials, log_file)
|
||||
|
||||
elsif service_credentials_set?(auth_params)
|
||||
session_hash = get_unauthenticated_session(auth_params, log_file)
|
||||
@session_data = session_hash[:data]
|
||||
@session = session_hash[:session]
|
||||
|
||||
elsif env_vars_set?
|
||||
credentials = get_credentials_from_env
|
||||
@session = get_authenticated_session(credentials, log_file)
|
||||
|
||||
else # Last effort: try to get the token from keystone.conf
|
||||
session_hash = self.class.try_auth_with_token(keystone_file, log_file)
|
||||
@session_data = session_hash[:data]
|
||||
@session = session_hash[:session]
|
||||
end
|
||||
end
|
||||
|
||||
def self.authenticate(auth_params, log_file)
|
||||
auth_params = {} unless auth_params
|
||||
if env_vars_set?
|
||||
credentials = get_credentials_from_env
|
||||
@session = get_authenticated_session(credentials, log_file)
|
||||
|
||||
else # Last effort: try to get the token from keystone.conf
|
||||
session_hash = try_auth_with_token(keystone_file, log_file)
|
||||
@session_data = session_hash[:data]
|
||||
@session = session_hash[:session]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.try_auth_with_token(conf_file, log_file)
|
||||
service_token = get_admin_token_from_keystone_file(conf_file)
|
||||
auth_url = get_auth_url_from_keystone_file(conf_file)
|
||||
session_hash = {}
|
||||
if service_token
|
||||
credentials = {
|
||||
'service_token' => service_token,
|
||||
'host_uri' => auth_url,
|
||||
}
|
||||
session_hash = get_unauthenticated_session(credentials, log_file)
|
||||
else # All authentication efforts failed
|
||||
raise(Puppet::Error, 'No credentials provided.')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.make_request(service, request, session_data, &block)
|
||||
response = nil
|
||||
if service && service.default_session_data
|
||||
response = service.request(request, :endpoint_type => 'admin') do |params|
|
||||
yield(params) if block
|
||||
end
|
||||
elsif session_data
|
||||
response = service.request(request, :endpoint_type => 'admin',
|
||||
:session_data => session_data) do |params|
|
||||
yield(params) if block
|
||||
end
|
||||
else
|
||||
raise(Puppet::Error, 'Cannot make a request with no session data.')
|
||||
end
|
||||
if response.body.hash['error']
|
||||
raise(Puppet::Error, "Error making request: #{response.body.hash['error']['code']} #{response.body.hash['error']['title']}")
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
|
||||
def password_credentials_set?(auth_params)
|
||||
auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['host_uri']
|
||||
end
|
||||
|
||||
|
||||
def openrc_set?(auth_params)
|
||||
auth_params['openrc']
|
||||
end
|
||||
|
||||
|
||||
def service_credentials_set?(auth_params)
|
||||
auth_params['service_token'] && auth_params['host_uri']
|
||||
end
|
||||
|
||||
|
||||
def self.env_vars_set?
|
||||
ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL']
|
||||
end
|
||||
|
||||
|
||||
def env_vars_set?
|
||||
self.class.env_vars_set?
|
||||
end
|
||||
|
||||
|
||||
def get_credentials_from_openrc(file)
|
||||
creds = {}
|
||||
begin
|
||||
File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line|
|
||||
key, value = line.split('=')
|
||||
key = key.split(' ').last
|
||||
value = value.chomp.gsub(/'/, '')
|
||||
creds[key] = value
|
||||
end
|
||||
return creds
|
||||
rescue Exception => error
|
||||
return {}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.get_credentials_from_env
|
||||
ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS/) } # Ruby 1.8.7
|
||||
end
|
||||
|
||||
def get_credentials_from_env
|
||||
self.class.get_credentials_from_env
|
||||
end
|
||||
|
||||
|
||||
def self.keystone_file
|
||||
keystone_file = Puppet::Util::IniConfig::File.new
|
||||
keystone_file.read('/etc/keystone/keystone.conf')
|
||||
keystone_file
|
||||
end
|
||||
|
||||
def keystone_file
|
||||
return @keystone_file if @keystone_file
|
||||
@keystone_file = Puppet::Util::IniConfig::File.new
|
||||
@keystone_file.read('/etc/keystone/keystone.conf')
|
||||
@keystone_file
|
||||
end
|
||||
|
||||
|
||||
def self.get_admin_token_from_keystone_file(conf_file)
|
||||
if conf_file and conf_file['DEFAULT'] and conf_file['DEFAULT']['admin_token']
|
||||
return "#{conf_file['DEFAULT']['admin_token'].strip}"
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def get_admin_token_from_keystone_file
|
||||
conf_file = keystone_file
|
||||
self.class.get_admin_token_from_keystone_file(conf_file)
|
||||
end
|
||||
|
||||
|
||||
def self.get_auth_url_from_keystone_file(conf_file)
|
||||
if conf_file
|
||||
if conf_file['DEFAULT']
|
||||
if conf_file['DEFAULT']['admin_endpoint']
|
||||
auth_url = conf_file['DEFAULT']['admin_endpoint'].strip
|
||||
return versioned_endpoint(auth_url)
|
||||
end
|
||||
|
||||
if conf_file['DEFAULT']['admin_port']
|
||||
admin_port = conf_file['DEFAULT']['admin_port'].strip
|
||||
else
|
||||
admin_port = '35357'
|
||||
end
|
||||
|
||||
if conf_file['DEFAULT']['admin_bind_host']
|
||||
host = conf_file['DEFAULT']['admin_bind_host'].strip
|
||||
if host == "0.0.0.0"
|
||||
host = "127.0.0.1"
|
||||
end
|
||||
else
|
||||
host = "127.0.0.1"
|
||||
end
|
||||
end
|
||||
|
||||
if conf_file['ssl'] && conf_file['ssl']['enable'] && conf_file['ssl']['enable'].strip.downcase == 'true'
|
||||
protocol = 'https'
|
||||
else
|
||||
protocol = 'http'
|
||||
end
|
||||
end
|
||||
|
||||
"#{protocol}://#{host}:#{admin_port}/v2.0/"
|
||||
end
|
||||
|
||||
def get_auth_url_from_keystone_file
|
||||
self.class.get_auth_url_from_keystone_file(keystone_file)
|
||||
end
|
||||
|
||||
|
||||
def self.make_configuration(credentials)
|
||||
host_uri = versioned_endpoint(credentials['host_uri'] || credentials['OS_AUTH_URL'], credentials['api_version'])
|
||||
{
|
||||
:provider => 'openstack',
|
||||
:auth_service => {
|
||||
:name => 'identity',
|
||||
:host_uri => host_uri,
|
||||
:request => 'create_token',
|
||||
:validator => 'list_tenants',
|
||||
},
|
||||
:auth_credentials => {
|
||||
:username => credentials['username'] || credentials['OS_USERNAME'],
|
||||
:password => credentials['password'] || credentials['OS_PASSWORD'],
|
||||
:tenant_name => credentials['tenant_name'] || credentials['OS_TENANT_NAME']
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
def self.get_authenticated_session(credentials, log_file)
|
||||
configuration = make_configuration(credentials)
|
||||
session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
|
||||
session.authenticate
|
||||
session
|
||||
end
|
||||
|
||||
def get_authenticated_session(credentials, log_file)
|
||||
self.class.get_authenticated_session(credentials, log_file)
|
||||
end
|
||||
|
||||
|
||||
def self.get_unauthenticated_session(credentials, log_file)
|
||||
configuration = {
|
||||
:provider => 'openstack',
|
||||
}
|
||||
session_data = {
|
||||
:base_url => credentials['host_uri'],
|
||||
:service_token => credentials['service_token']
|
||||
}
|
||||
session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
|
||||
{ :session => session, :data => session_data }
|
||||
end
|
||||
|
||||
def get_unauthenticated_session(credentials, log_file)
|
||||
self.class.get_unauthenticated_session(credentials, log_file)
|
||||
end
|
||||
|
||||
|
||||
def self.versioned_endpoint(endpoint, version = 'v2.0')
|
||||
version = 'v2.0' if version.nil?
|
||||
if endpoint =~ /\/#{version}\/?$/ || endpoint =~ /\/v2.0\/?$/ || endpoint =~ /\/v3\/?$/
|
||||
endpoint
|
||||
else
|
||||
"#{endpoint.chomp('/')}/#{version}"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,183 @@
|
|||
require 'csv'
|
||||
require 'puppet'
|
||||
|
||||
class Puppet::Error::OpenstackAuthInputError < Puppet::Error
|
||||
end
|
||||
|
||||
class Puppet::Error::OpenstackUnauthorizedError < Puppet::Error
|
||||
end
|
||||
|
||||
class Puppet::Provider::Openstack < Puppet::Provider
|
||||
|
||||
initvars # so commands will work
|
||||
commands :openstack => 'openstack'
|
||||
|
||||
def request(service, action, object, credentials, *properties)
|
||||
if password_credentials_set?(credentials)
|
||||
auth_args = password_auth_args(credentials)
|
||||
elsif openrc_set?(credentials)
|
||||
credentials = get_credentials_from_openrc(credentials['openrc'])
|
||||
auth_args = password_auth_args(credentials)
|
||||
elsif service_credentials_set?(credentials)
|
||||
auth_args = token_auth_args(credentials)
|
||||
elsif env_vars_set?
|
||||
# noop; auth needs no extra arguments
|
||||
auth_args = nil
|
||||
else # All authentication efforts failed
|
||||
raise(Puppet::Error::OpenstackAuthInputError, 'No credentials provided.')
|
||||
end
|
||||
args = [object, properties, auth_args].flatten.compact
|
||||
authenticate_request(service, action, args)
|
||||
end
|
||||
|
||||
def self.request(service, action, object, *properties)
|
||||
if env_vars_set?
|
||||
# noop; auth needs no extra arguments
|
||||
auth_args = nil
|
||||
else # All authentication efforts failed
|
||||
raise(Puppet::Error::OpenstackAuthInputError, 'No credentials provided.')
|
||||
end
|
||||
args = [object, properties, auth_args].flatten.compact
|
||||
authenticate_request(service, action, args)
|
||||
end
|
||||
|
||||
# Returns an array of hashes, where the keys are the downcased CSV headers
|
||||
# with underscores instead of spaces
|
||||
def self.authenticate_request(service, action, *args)
|
||||
rv = nil
|
||||
timeout = 10
|
||||
end_time = Time.now.to_i + timeout
|
||||
loop do
|
||||
begin
|
||||
if(action == 'list')
|
||||
response = openstack(service, action, '--quiet', '--format', 'csv', args)
|
||||
# Ignore warnings - assume legitimate output starts with a double quote
|
||||
# Errors will be caught and raised prior to this
|
||||
response = response.split("\n").select { |line| line =~ /^\".*\",\".*\"/ }.join("\n")
|
||||
response = CSV.parse(response.to_s)
|
||||
keys = response.delete_at(0) # ID,Name,Description,Enabled
|
||||
rv = response.collect do |line|
|
||||
hash = {}
|
||||
keys.each_index do |index|
|
||||
key = keys[index].downcase.gsub(/ /, '_').to_sym
|
||||
hash[key] = line[index]
|
||||
end
|
||||
hash
|
||||
end
|
||||
elsif(action == 'show' || action == 'create')
|
||||
rv = {}
|
||||
# shell output is name="value"\nid="value2"\ndescription="value3" etc.
|
||||
openstack(service, action, '--format', 'shell', args).split("\n").each do |line|
|
||||
# key is everything before the first "="
|
||||
key, val = line.split("=", 2)
|
||||
next unless val # Ignore warnings
|
||||
# value is everything after the first "=", with leading and trailing double quotes stripped
|
||||
val = val.gsub(/\A"|"\Z/, '')
|
||||
rv[key.downcase.to_sym] = val
|
||||
end
|
||||
else
|
||||
rv = openstack(service, action, args)
|
||||
end
|
||||
break
|
||||
rescue Puppet::ExecutionFailure => e
|
||||
if e.message =~ /HTTP 401/
|
||||
raise(Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate.')
|
||||
elsif e.message =~ /Unable to establish connection/
|
||||
current_time = Time.now.to_i
|
||||
if current_time > end_time
|
||||
break
|
||||
else
|
||||
wait = end_time - current_time
|
||||
Puppet::debug("Non-fatal error: \"#{e.message}\"; retrying for #{wait} more seconds.")
|
||||
if wait > timeout - 2 # Only notice the first time
|
||||
notice("#{service} service is unavailable. Will retry for up to #{wait} seconds.")
|
||||
end
|
||||
end
|
||||
sleep(2)
|
||||
else
|
||||
raise e
|
||||
end
|
||||
end
|
||||
end
|
||||
return rv
|
||||
end
|
||||
|
||||
def authenticate_request(service, action, *args)
|
||||
self.class.authenticate_request(service, action, *args)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def password_credentials_set?(auth_params)
|
||||
auth_params && auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['auth_url']
|
||||
end
|
||||
|
||||
|
||||
def openrc_set?(auth_params)
|
||||
auth_params && auth_params['openrc']
|
||||
end
|
||||
|
||||
|
||||
def service_credentials_set?(auth_params)
|
||||
auth_params && auth_params['token'] && auth_params['auth_url']
|
||||
end
|
||||
|
||||
|
||||
def self.env_vars_set?
|
||||
ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL']
|
||||
end
|
||||
|
||||
|
||||
def env_vars_set?
|
||||
self.class.env_vars_set?
|
||||
end
|
||||
|
||||
|
||||
|
||||
def self.password_auth_args(credentials)
|
||||
['--os-username', credentials['username'],
|
||||
'--os-password', credentials['password'],
|
||||
'--os-tenant-name', credentials['tenant_name'],
|
||||
'--os-auth-url', credentials['auth_url']]
|
||||
end
|
||||
|
||||
def password_auth_args(credentials)
|
||||
self.class.password_auth_args(credentials)
|
||||
end
|
||||
|
||||
|
||||
def self.token_auth_args(credentials)
|
||||
['--os-token', credentials['token'],
|
||||
'--os-url', credentials['auth_url']]
|
||||
end
|
||||
|
||||
def token_auth_args(credentials)
|
||||
self.class.token_auth_args(credentials)
|
||||
end
|
||||
|
||||
def get_credentials_from_openrc(file)
|
||||
creds = {}
|
||||
File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line|
|
||||
key, value = line.split('=')
|
||||
key = key.split(' ').last.downcase.sub(/^os_/, '')
|
||||
value = value.chomp.gsub(/'/, '')
|
||||
creds[key] = value
|
||||
end
|
||||
return creds
|
||||
end
|
||||
|
||||
|
||||
def self.get_credentials_from_env
|
||||
env = ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS_/) }
|
||||
credentials = {}
|
||||
env.each do |name, value|
|
||||
credentials[name.downcase.sub(/^os_/, '')] = value
|
||||
end
|
||||
credentials
|
||||
end
|
||||
|
||||
def get_credentials_from_env
|
||||
self.class.get_credentials_from_env
|
||||
end
|
||||
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
# Add the auth parameter to whatever type is given
|
||||
module Puppet::Util::Aviator
|
||||
def self.add_aviator_params(type)
|
||||
module Puppet::Util::Openstack
|
||||
def self.add_openstack_type_methods(type, comment)
|
||||
|
||||
type.newparam(:auth) do
|
||||
|
||||
|
@ -12,7 +12,7 @@ auth => {
|
|||
'username' => 'test',
|
||||
'password' => 'passw0rd',
|
||||
'tenant_name' => 'test',
|
||||
'host_uri' => 'http://localhost:35357/v2.0',
|
||||
'auth_url' => 'http://localhost:35357/v2.0',
|
||||
}
|
||||
|
||||
or a path to an openrc file containing these credentials, e.g.:
|
||||
|
@ -25,12 +25,13 @@ or a service token and host, e.g.:
|
|||
|
||||
auth => {
|
||||
'service_token' => 'ADMIN',
|
||||
'host_uri' => 'http://localhost:35357/v2.0',
|
||||
'auth_url' => 'http://localhost:35357/v2.0',
|
||||
}
|
||||
|
||||
If not present, the provider will first look for environment variables
|
||||
for password credentials and then to /etc/keystone/keystone.conf for a
|
||||
service token.
|
||||
If not present, the provider will look for environment variables for
|
||||
password credentials.
|
||||
|
||||
#{comment}
|
||||
EOT
|
||||
|
||||
validate do |value|
|
||||
|
@ -38,9 +39,9 @@ EOT
|
|||
end
|
||||
end
|
||||
|
||||
type.newparam(:log_file) do
|
||||
desc 'Log file. Defaults to no logging.'
|
||||
defaultto('/dev/null')
|
||||
type.autorequire(:package) do
|
||||
'python-openstackclient'
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
# == Class: openstacklib::openstackclient
|
||||
#
|
||||
# Installs the openstackclient
|
||||
#
|
||||
# == Parameters
|
||||
#
|
||||
# [package_ensure]
|
||||
# Ensure state of the openstackclient package.
|
||||
# Optional. Defaults to 'present'.
|
||||
#
|
||||
class openstacklib::openstackclient(
|
||||
$package_ensure = 'present',
|
||||
){
|
||||
package { 'python-openstackclient':
|
||||
ensure => $package_ensure,
|
||||
tag => 'openstack',
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@
|
|||
],
|
||||
"description": "Puppet module library to expose common functionality between OpenStack modules.",
|
||||
"dependencies": [
|
||||
{ "name": "aimonb/aviator", "version_requirement": ">=0.4.2 <1.0.0" },
|
||||
{ "name": "puppetlabs/apache", "version_requirement": ">=1.0.0 <2.0.0" },
|
||||
{ "name": "puppetlabs/mysql", "version_requirement": ">=3.0.0 <4.0.0" },
|
||||
{ "name": "puppetlabs/stdlib", "version_requirement": ">=4.0.0 <5.0.0" },
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,36 +0,0 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: "http://192.168.11.4:35357/v2.0/tenants"
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ""
|
||||
headers:
|
||||
Content-Type:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- "Faraday v0.8.8"
|
||||
X-Auth-Token:
|
||||
- sosp-kyl
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message:
|
||||
headers:
|
||||
vary:
|
||||
- X-Auth-Token
|
||||
content-type:
|
||||
- application/json
|
||||
content-length:
|
||||
- "491"
|
||||
date:
|
||||
- "Tue, 30 Sep 2014 06:59:48 GMT"
|
||||
connection:
|
||||
- close
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
|
||||
http_version:
|
||||
recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
|
||||
recorded_with: "VCR 2.9.3"
|
File diff suppressed because one or more lines are too long
|
@ -1,36 +0,0 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: "http://192.168.11.4:35357/v2.0/tenants"
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ""
|
||||
headers:
|
||||
Content-Type:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- "Faraday v0.8.8"
|
||||
X-Auth-Token:
|
||||
- sosp-kyl
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message:
|
||||
headers:
|
||||
vary:
|
||||
- X-Auth-Token
|
||||
content-type:
|
||||
- application/json
|
||||
content-length:
|
||||
- "491"
|
||||
date:
|
||||
- "Tue, 30 Sep 2014 06:59:48 GMT"
|
||||
connection:
|
||||
- close
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
|
||||
http_version:
|
||||
recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
|
||||
recorded_with: "VCR 2.9.3"
|
|
@ -1,14 +1,7 @@
|
|||
require 'puppetlabs_spec_helper/module_spec_helper'
|
||||
require 'shared_examples'
|
||||
require 'vcr'
|
||||
|
||||
|
||||
RSpec.configure do |c|
|
||||
c.alias_it_should_behave_like_to :it_configures, 'configures'
|
||||
c.alias_it_should_behave_like_to :it_raises, 'raises'
|
||||
end
|
||||
|
||||
VCR.configure do |c|
|
||||
c.cassette_library_dir = 'spec/fixtures/vcr'
|
||||
c.hook_into :faraday
|
||||
end
|
||||
|
|
|
@ -1,320 +0,0 @@
|
|||
# Load libraries from aviator here to simulate how they live together in a real puppet run
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib'))
|
||||
require 'puppet'
|
||||
require 'vcr'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/aviator'
|
||||
|
||||
|
||||
describe Puppet::Provider::Aviator do
|
||||
|
||||
before(:each) do
|
||||
ENV['OS_USERNAME'] = nil
|
||||
ENV['OS_PASSWORD'] = nil
|
||||
ENV['OS_TENANT_NAME'] = nil
|
||||
ENV['OS_AUTH_URL'] = nil
|
||||
end
|
||||
|
||||
let(:log_file) { '/tmp/aviator_spec.log' }
|
||||
|
||||
let(:type) do
|
||||
Puppet::Type.newtype(:test_resource) do
|
||||
newparam(:name, :namevar => true)
|
||||
newparam(:auth)
|
||||
newparam(:log_file)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
shared_examples 'creating a session using environment variables' do
|
||||
it 'creates an authenticated session' do
|
||||
ENV['OS_USERNAME'] = 'admin'
|
||||
ENV['OS_PASSWORD'] = 'fyby-tet'
|
||||
ENV['OS_TENANT_NAME'] = 'admin'
|
||||
ENV['OS_AUTH_URL'] = 'http://192.168.11.4:35357/v2.0'
|
||||
response = nil
|
||||
VCR.use_cassette('aviator/session/with_password') do
|
||||
session = provider.session
|
||||
response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
|
||||
end
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'creating a session using a service token from keystone.conf' do
|
||||
it 'creates an unauthenticated session' do
|
||||
data = "[DEFAULT]\nadmin_token=sosp-kyl\nadmin_endpoint=http://192.168.11.4:35357/v2.0"
|
||||
response = nil
|
||||
VCR.use_cassette('aviator/session/with_token') do
|
||||
# Stubbing File.read produces inconsistent results because of how IniConfig
|
||||
# overrides the File class in some versions of Puppet.
|
||||
# Stubbing FileType.filetype(:flat) simplifies working with IniConfig
|
||||
Puppet::Util::FileType.filetype(:flat).any_instance.expects(:read).returns(StringIO.new(data).read)
|
||||
session = provider.session
|
||||
Puppet::Util::FileType.filetype(:flat).any_instance.unstub(:read)
|
||||
response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
|
||||
end
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'it has no credentials' do
|
||||
it 'fails to authenticate' do
|
||||
expect{ provider.session }.to raise_error(Puppet::Error, /No credentials provided/)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'making request with an existing session' do
|
||||
it 'makes a successful request' do
|
||||
VCR.use_cassette('aviator/request/with_session') do
|
||||
session = provider.session
|
||||
response = provider.request(session.identity_service, :list_tenants)
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'making request with injected session data' do
|
||||
it 'makes a successful request' do
|
||||
VCR.use_cassette('aviator/request/without_session') do
|
||||
session = provider.session
|
||||
response = provider.request(session.identity_service, :list_tenants)
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'making request with no session or session data' do
|
||||
it 'fails to make a request' do
|
||||
expect{ provider.request(nil, :list_tenants) }.to raise_error(Puppet::Error, /Cannot make a request/)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#session' do
|
||||
|
||||
context 'with valid password credentials in parameters' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'username' => 'admin',
|
||||
'password' => 'fyby-tet',
|
||||
'tenant_name' => 'admin',
|
||||
'host_uri' => 'http://192.168.11.4:35357/v2.0',
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates a session' do
|
||||
provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
|
||||
response = nil
|
||||
VCR.use_cassette('aviator/session/with_password') do
|
||||
session = provider.session
|
||||
response = session.identity_service.request(:list_tenants)
|
||||
end
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid openrc file in parameters' do
|
||||
data = "export OS_USERNAME='admin'\nexport OS_PASSWORD='fyby-tet'\nexport OS_TENANT_NAME='admin'\nexport OS_AUTH_URL='http://192.168.11.4:35357/v2.0'"
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'openrc' => '/root/openrc'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates a session' do
|
||||
provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
|
||||
response = nil
|
||||
VCR.use_cassette('aviator/session/with_password') do
|
||||
File.expects(:open).with('/root/openrc').returns(StringIO.new(data))
|
||||
session = provider.session
|
||||
File.unstub(:open) # Ignore File.open calls to cassette file
|
||||
response = session.identity_service.request(:list_tenants)
|
||||
end
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid service token in parameters' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'service_token' => 'sosp-kyl',
|
||||
'host_uri' => 'http://192.168.11.4:35357/v2.0'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
subject(:session) do
|
||||
provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
|
||||
VCR.use_cassette('aviator/session/with_token') do
|
||||
session = provider.session
|
||||
response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates a session' do
|
||||
expect(session.status).to eq(200)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with valid password credentials in environment variables' do
|
||||
it_behaves_like 'creating a session using environment variables' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Aviator.new(type.new(resource_attrs))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid service token in keystone.conf' do
|
||||
it_behaves_like 'creating a session using a service token from keystone.conf' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Aviator.new(type.new(resource_attrs))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with no valid credentials' do
|
||||
it_behaves_like 'it has no credentials' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
}
|
||||
end
|
||||
let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
describe '::session' do
|
||||
|
||||
context 'with valid password credentials in environment variables' do
|
||||
it_behaves_like 'creating a session using environment variables' do
|
||||
let(:provider) { Puppet::Provider::Aviator.dup }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid service token in keystone.conf' do
|
||||
it_behaves_like 'creating a session using a service token from keystone.conf' do
|
||||
let(:provider) { Puppet::Provider::Aviator.dup }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no valid credentials' do
|
||||
it_behaves_like 'it has no credentials' do
|
||||
let(:provider) { Puppet::Provider::Aviator.dup }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#request' do
|
||||
context 'when a session exists' do
|
||||
it_behaves_like 'making request with an existing session' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'username' => 'admin',
|
||||
'password' => 'fyby-tet',
|
||||
'tenant_name' => 'admin',
|
||||
'host_uri' => 'http://192.168.11.4:35357/v2.0',
|
||||
}
|
||||
}
|
||||
end
|
||||
let (:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when injecting session data' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'service_token' => 'sosp-kyl',
|
||||
'host_uri' => 'http://192.168.11.4:35357/v2.0'
|
||||
}
|
||||
}
|
||||
end
|
||||
let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
|
||||
it 'makes a successful request' do
|
||||
provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
|
||||
VCR.use_cassette('aviator/request/without_session') do
|
||||
session = provider.session
|
||||
response = provider.request(session.identity_service, :list_tenants)
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is no session or session data' do
|
||||
it_behaves_like 'making request with no session or session data' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
}
|
||||
end
|
||||
let(:provider) {Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '::request' do
|
||||
context 'when a session exists' do
|
||||
|
||||
it_behaves_like 'making request with an existing session' do
|
||||
let(:provider) { provider = Puppet::Provider::Aviator.dup }
|
||||
before(:each) do
|
||||
ENV['OS_USERNAME'] = 'admin'
|
||||
ENV['OS_PASSWORD'] = 'fyby-tet'
|
||||
ENV['OS_TENANT_NAME'] = 'admin'
|
||||
ENV['OS_AUTH_URL'] = 'http://192.168.11.4:35357/v2.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when injecting session data' do
|
||||
let(:session_data) do
|
||||
{
|
||||
:base_url => 'http://192.168.11.4:35357/v2.0',
|
||||
:service_token => 'sosp-kyl'
|
||||
}
|
||||
end
|
||||
it 'makes a successful request' do
|
||||
provider = Puppet::Provider::Aviator.dup
|
||||
VCR.use_cassette('aviator/request/without_session') do
|
||||
session = ::Aviator::Session.new(:config => { :provider => 'openstack' }, :log_file => log_file)
|
||||
provider.session_data = session_data
|
||||
response = provider.request(session.identity_service, :list_tenants)
|
||||
expect(response.status).to eq(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is no session or session data' do
|
||||
it_behaves_like 'making request with no session or session data' do
|
||||
let(:provider) { Puppet::Provider::Aviator.dup }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,228 @@
|
|||
# Load libraries from aviator here to simulate how they live together in a real puppet run
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib'))
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/openstack'
|
||||
|
||||
|
||||
describe Puppet::Provider::Openstack do
|
||||
|
||||
before(:each) do
|
||||
ENV['OS_USERNAME'] = nil
|
||||
ENV['OS_PASSWORD'] = nil
|
||||
ENV['OS_TENANT_NAME'] = nil
|
||||
ENV['OS_AUTH_URL'] = nil
|
||||
end
|
||||
|
||||
let(:type) do
|
||||
Puppet::Type.newtype(:test_resource) do
|
||||
newparam(:name, :namevar => true)
|
||||
newparam(:auth)
|
||||
newparam(:log_file)
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'authenticating with environment variables' do
|
||||
it 'makes a successful request' do
|
||||
ENV['OS_USERNAME'] = 'test'
|
||||
ENV['OS_PASSWORD'] = 'abc123'
|
||||
ENV['OS_TENANT_NAME'] = 'test'
|
||||
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0'
|
||||
if provider.class == Class
|
||||
provider.stubs(:openstack)
|
||||
.with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]])
|
||||
.returns('"ID","Name","Description","Enabled"
|
||||
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
|
||||
')
|
||||
else
|
||||
provider.class.stubs(:openstack)
|
||||
.with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]])
|
||||
.returns('"ID","Name","Description","Enabled"
|
||||
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
|
||||
')
|
||||
end
|
||||
response = provider.request('project', 'list', nil, nil, '--long' )
|
||||
expect(response.first[:description]).to match /Test tenant/
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'it has no credentials' do
|
||||
it 'fails to authenticate' do
|
||||
expect{ provider.request('project', 'list', nil, nil, '--long') }.to raise_error(Puppet::Error::OpenstackAuthInputError, /No credentials provided/)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#request' do
|
||||
|
||||
context 'with valid password credentials in parameters' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'username' => 'test',
|
||||
'password' => 'abc123',
|
||||
'tenant_name' => 'test',
|
||||
'auth_url' => 'http://127.0.0.1:5000/v2.0',
|
||||
}
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Openstack.new(type.new(resource_attrs))
|
||||
end
|
||||
|
||||
it 'makes a successful request' do
|
||||
provider.class.stubs(:openstack)
|
||||
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
|
||||
.returns('"ID","Name","Description","Enabled"
|
||||
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
|
||||
')
|
||||
response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
|
||||
expect(response.first[:description]).to match /Test tenant/
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid openrc file in parameters' do
|
||||
mock = "export OS_USERNAME='test'\nexport OS_PASSWORD='abc123'\nexport OS_TENANT_NAME='test'\nexport OS_AUTH_URL='http://127.0.0.1:5000/v2.0'"
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'openrc' => '/root/openrc'
|
||||
}
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Openstack.new(type.new(resource_attrs))
|
||||
end
|
||||
|
||||
it 'makes a successful request' do
|
||||
File.expects(:open).with('/root/openrc').returns(StringIO.new(mock))
|
||||
provider.class.stubs(:openstack)
|
||||
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
|
||||
.returns('"ID","Name","Description","Enabled"
|
||||
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
|
||||
')
|
||||
response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
|
||||
expect(response.first[:description]).to match /Test tenant/
|
||||
end
|
||||
end
|
||||
|
||||
context 'with valid service token in parameters' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'token' => 'secrettoken',
|
||||
'auth_url' => 'http://127.0.0.1:5000/v2.0'
|
||||
}
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Openstack.new(type.new(resource_attrs))
|
||||
end
|
||||
|
||||
it 'makes a successful request' do
|
||||
provider.class.stubs(:openstack)
|
||||
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']])
|
||||
.returns('"ID","Name","Description","Enabled"
|
||||
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
|
||||
')
|
||||
response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
|
||||
expect(response.first[:description]).to match /Test tenant/
|
||||
end
|
||||
|
||||
it 'makes a successful show request' do
|
||||
provider.class.stubs(:openstack)
|
||||
.with('project', 'show', '--format', 'shell', [['test', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']])
|
||||
.returns('ID="1cb05cfed7c24279be884ba4f6520262"
|
||||
Name="test"
|
||||
Description="Test Tenant"
|
||||
Enabled="True"
|
||||
')
|
||||
response = provider.request('project', 'show', 'test', resource_attrs[:auth])
|
||||
expect(response[:description]).to match /Test Tenant/
|
||||
expect(response[:id]).to match /1cb05cfed7c24279be884ba4f6520262/
|
||||
expect(response[:name]).to match /test/
|
||||
expect(response[:enabled]).to match /True/
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context 'with valid password credentials in environment variables' do
|
||||
it_behaves_like 'authenticating with environment variables' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Openstack.new(type.new(resource_attrs))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no valid credentials' do
|
||||
it_behaves_like 'it has no credentials' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Openstack.new(type.new(resource_attrs))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'it retries on connection errors' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
:auth => {
|
||||
'username' => 'test',
|
||||
'password' => 'abc123',
|
||||
'tenant_name' => 'test',
|
||||
'auth_url' => 'http://127.0.0.1:5000/v2.0',
|
||||
}
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Openstack.new(type.new(resource_attrs))
|
||||
end
|
||||
it 'retries' do
|
||||
provider.class.stubs(:openstack)
|
||||
.with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
|
||||
.raises(Puppet::ExecutionFailure, 'Unable to establish connection')
|
||||
.then
|
||||
.returns('')
|
||||
provider.class.expects(:sleep).with(2).returns(nil)
|
||||
provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
describe '::request' do
|
||||
|
||||
context 'with valid password credentials in environment variables' do
|
||||
it_behaves_like 'authenticating with environment variables' do
|
||||
let(:resource_attrs) do
|
||||
{
|
||||
:name => 'stubresource',
|
||||
}
|
||||
end
|
||||
let(:provider) do
|
||||
Puppet::Provider::Openstack.dup
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with no valid credentials' do
|
||||
it_behaves_like 'it has no credentials' do
|
||||
let(:provider) { Puppet::Provider::Openstack.dup }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue