Implement base aviator provider
This patch adds a dependency on the aimonb/aviator module and adds functionality to support interactions with the OpenStack services' API via aviator. The patch adds a parent provider that is intended for other providers to inherit from. The parent provider has methods to authenticate to openstack services, create session objects, and make requests. The authenticate method can accept credentials as an argument hash or infer credentials from the environment. It also adds a stub type parameter that allows types to incorporate basic parameters they need in order to support using aviator. Change-Id: I56b0d07ae8f4738037eda486b75a0f6e24fe80e7 Implements: blueprint use-aviator-in-module-resources
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
fixtures:
|
||||
repositories:
|
||||
aviator: git://github.com/aimonb/puppet_aviator.git
|
||||
mysql: git://github.com/puppetlabs/puppetlabs-mysql.git
|
||||
stdlib: git://github.com/puppetlabs/puppetlabs-stdlib.git
|
||||
symlinks:
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
*.swp
|
||||
spec/fixtures/
|
||||
spec/fixtures/*
|
||||
!spec/fixtures/vcr/
|
||||
pkg
|
||||
Gemfile.lock
|
||||
|
6
Gemfile
6
Gemfile
@@ -4,9 +4,11 @@ group :development, :test do
|
||||
gem 'puppetlabs_spec_helper', :require => false
|
||||
gem 'puppet-lint', '~> 0.3.2'
|
||||
gem 'rake', '10.1.1'
|
||||
gem 'rspec', '< 2.99'
|
||||
gem 'rspec'
|
||||
gem 'mocha'
|
||||
gem 'json'
|
||||
gem 'webmock'
|
||||
gem 'faraday', '0.8.8', :require => false
|
||||
gem 'vcr', :require => false
|
||||
end
|
||||
|
||||
if puppetversion = ENV['PUPPET_GEM_VERSION']
|
||||
|
@@ -7,5 +7,6 @@ summary 'Puppet Labs OpenStackLib Module'
|
||||
description 'Puppet module library to expose common functionality between OpenStack modules'
|
||||
project_page 'https://launchpad.net/puppet-openstacklib'
|
||||
|
||||
dependency 'aimonb/aviator',
|
||||
dependency 'puppetlabs/mysql', '>=2.2.0 <3.0.0'
|
||||
dependency 'puppetlabs/stdlib', '>=3.2.0'
|
||||
|
55
README.md
55
README.md
@@ -119,6 +119,61 @@ array or string; optional; default to undef
|
||||
Privileges given to the database user;
|
||||
string or array of strings; optional; default to 'ALL'
|
||||
|
||||
### Types and Providers
|
||||
|
||||
#### Aviator
|
||||
|
||||
#####`Puppet::add_aviator_params`
|
||||
|
||||
The aviator type is not a real type, but it serves to simulate a mixin model,
|
||||
whereby other types can call out to the Puppet::add\_aviator\_params method in
|
||||
order to add aviator-specific parameters to themselves. Currently this adds the
|
||||
auth parameter to the given type. The method must be called after the type is
|
||||
declared, e.g.:
|
||||
|
||||
```puppet
|
||||
require 'puppet/type/aviator'
|
||||
Puppet::Type.newtype(:my_type) do
|
||||
# ...
|
||||
end
|
||||
Puppet::add_aviator_params(:my_type)
|
||||
```
|
||||
|
||||
#####`Puppet::Provider::Aviator`
|
||||
|
||||
The aviator provider is a parent provider intended to serve as a base for other
|
||||
providers that need to authenticate against keystone in order to accomplish a
|
||||
task.
|
||||
|
||||
**`Puppet::Provider::Aviator#authenticate`**
|
||||
|
||||
Either creates an authenticated session or sets up an unauthenticated session
|
||||
with instance variables initialized with a token to inject into the next request.
|
||||
It takes as arguments a set of authentication parameters as a hash and a path
|
||||
to a log file. Puppet::Provider::Aviator#authencate looks for five different
|
||||
possible methods of authenticating, in the following order:
|
||||
|
||||
1) Username and password credentials in the auth parameters
|
||||
2) The path to an openrc file containing credentials to read in the auth
|
||||
parameters
|
||||
3) A service token in the auth parameters
|
||||
4) Environment variables set for the environment in which Puppet is running
|
||||
5) A service token in /etc/keystone/keystone.conf. This option provides
|
||||
backwards compatibility with earlier keystone providers.
|
||||
|
||||
If the provider has password credentials, it can create an authenticated
|
||||
session. If it only has a service token, it initializes an unauthenciated
|
||||
session and a hash of session data that can be injected into a future request.
|
||||
|
||||
**`Puppet::Provider::Aviator#make_request`**
|
||||
|
||||
After creating a session, the make\_request method provides an interface that
|
||||
providers can use to make requests without worrying about whether they have an
|
||||
authenticated or unauthenticated session. It takes as arguments the
|
||||
Aviator::Service it is making a request at (for example, keystone), a symbol for
|
||||
the request (for example, :list\_tenants), and optionally a block to execute
|
||||
that will set parameters for an update request.
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
|
297
lib/puppet/provider/aviator.rb
Normal file
297
lib/puppet/provider/aviator.rb
Normal file
@@ -0,0 +1,297 @@
|
||||
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
|
46
lib/puppet/util/aviator.rb
Normal file
46
lib/puppet/util/aviator.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
# Add the auth parameter to whatever type is given
|
||||
module Puppet::Util::Aviator
|
||||
def self.add_aviator_params(type)
|
||||
|
||||
type.newparam(:auth) do
|
||||
|
||||
desc <<EOT
|
||||
Hash of authentication credentials. Credentials can be specified as
|
||||
password credentials, e.g.:
|
||||
|
||||
auth => {
|
||||
'username' => 'test',
|
||||
'password' => 'passw0rd',
|
||||
'tenant_name' => 'test',
|
||||
'host_uri' => 'http://localhost:35357/v2.0',
|
||||
}
|
||||
|
||||
or a path to an openrc file containing these credentials, e.g.:
|
||||
|
||||
auth => {
|
||||
'openrc' => '/root/openrc',
|
||||
}
|
||||
|
||||
or a service token and host, e.g.:
|
||||
|
||||
auth => {
|
||||
'service_token' => 'ADMIN',
|
||||
'host_uri' => '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.
|
||||
EOT
|
||||
|
||||
validate do |value|
|
||||
raise(Puppet::Error, 'This property must be a hash') unless value.is_a?(Hash)
|
||||
end
|
||||
end
|
||||
|
||||
type.newparam(:log_file) do
|
||||
desc 'Log file. Defaults to no logging.'
|
||||
defaultto('/dev/null')
|
||||
end
|
||||
end
|
||||
end
|
67
spec/fixtures/vcr/aviator/request/with_session.yml
vendored
Normal file
67
spec/fixtures/vcr/aviator/request/with_session.yml
vendored
Normal file
File diff suppressed because one or more lines are too long
36
spec/fixtures/vcr/aviator/request/without_session.yml
vendored
Normal file
36
spec/fixtures/vcr/aviator/request/without_session.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
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"
|
67
spec/fixtures/vcr/aviator/session/with_password.yml
vendored
Normal file
67
spec/fixtures/vcr/aviator/session/with_password.yml
vendored
Normal file
File diff suppressed because one or more lines are too long
36
spec/fixtures/vcr/aviator/session/with_token.yml
vendored
Normal file
36
spec/fixtures/vcr/aviator/session/with_token.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
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 +1,7 @@
|
||||
require 'puppetlabs_spec_helper/module_spec_helper'
|
||||
require 'vcr'
|
||||
|
||||
VCR.configure do |c|
|
||||
c.cassette_library_dir = 'spec/fixtures/vcr'
|
||||
c.hook_into :faraday
|
||||
end
|
||||
|
320
spec/unit/provider/aviator_spec.rb
Normal file
320
spec/unit/provider/aviator_spec.rb
Normal file
@@ -0,0 +1,320 @@
|
||||
# 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
|
Reference in New Issue
Block a user