Targeting Keystone V3 API support

The default domain (id 'default', name 'Default') is where the V2
tenants/users are defined. So V3, which is now the default API's version
can and should be used.  Beeing able to use V3 domains needs to be
supported by specifying the domain name for a project/user.

This patch :
- Adds project and user domain names
- Renames tenant (v2) as project (v3)
- Renames os-auth-url to os-url, when using an authicated token against a
  service url, to distinct them from each other, as in OSC
(opentackclient)
- Updates newparam(:auth) accordingly to describe v2/v3 credential
  examples

Note: Keystone API v2 is deprecated [1]

[1] http://docs.openstack.org/developer/keystone/http-api.html#should-i-use-v2-0-or-v3

Change-Id: I72f79129a6875eb433eeb8a62f928e7210db134a
This commit is contained in:
Gilles Dubreuil 2015-04-02 16:33:44 +11:00
parent efa9181201
commit d4073c2721
3 changed files with 100 additions and 53 deletions

View File

@ -106,46 +106,51 @@ class Puppet::Provider::Openstack < Puppet::Provider
private private
def password_credentials_set?(auth_params) def password_credentials_set?(auth_params)
auth_params && auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['auth_url'] auth_params && auth_params['username'] && auth_params['password'] && auth_params['project_name'] && auth_params['auth_url']
end end
def openrc_set?(auth_params) def openrc_set?(auth_params)
auth_params && auth_params['openrc'] auth_params && auth_params['openrc']
end end
def service_credentials_set?(auth_params) def service_credentials_set?(auth_params)
auth_params && auth_params['token'] && auth_params['auth_url'] auth_params && auth_params['token'] && auth_params['url']
end end
def self.env_vars_set? def self.env_vars_set?
ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL'] ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_PROJECT_NAME'] && ENV['OS_AUTH_URL']
end end
def env_vars_set? def env_vars_set?
self.class.env_vars_set? self.class.env_vars_set?
end end
def self.password_auth_args(credentials) def self.password_auth_args(credentials)
['--os-username', credentials['username'], creds = [ '--os-username', credentials['username'],
'--os-password', credentials['password'], '--os-password', credentials['password'],
'--os-tenant-name', credentials['tenant_name'], '--os-project-name', credentials['project_name'],
'--os-auth-url', credentials['auth_url']] '--os-auth-url', credentials['auth_url'] ]
if credentials.include?('project_domain_name')
creds << '--os-project-domain-name'
creds << credentials['project_domain_name']
end
if credentials.include?('user_domain_name')
creds << '--os-user-domain-name'
creds << credentials['user_domain_name']
end
creds
end end
def password_auth_args(credentials) def password_auth_args(credentials)
self.class.password_auth_args(credentials) self.class.password_auth_args(credentials)
end end
def self.token_auth_args(credentials) def self.token_auth_args(credentials)
['--os-token', credentials['token'], [ '--os-token', credentials['token'],
'--os-url', credentials['auth_url']] '--os-url', credentials['url'] ]
end end
def token_auth_args(credentials) def token_auth_args(credentials)
@ -163,7 +168,6 @@ class Puppet::Provider::Openstack < Puppet::Provider
return creds return creds
end end
def self.get_credentials_from_env def self.get_credentials_from_env
env = ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS_/) } env = ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS_/) }
credentials = {} credentials = {}

View File

@ -5,27 +5,46 @@ module Puppet::Util::Openstack
type.newparam(:auth) do type.newparam(:auth) do
desc <<EOT desc <<EOT
Hash of authentication credentials. Credentials can be specified as Hash of authentication credentials. Credentials can be specified as either :
password credentials, e.g.:
1. Using a project/user with a password
For Keystone API V2:
auth => { auth => {
'username' => 'test', 'username' => 'test',
'password' => 'passw0rd', 'password' => 'changeme',
'tenant_name' => 'test', 'project_name' => 'test',
'auth_url' => 'http://localhost:35357/v2.0', 'auth_url' => 'http://localhost:35357/v2.0'
} }
or a path to an openrc file containing these credentials, e.g.: or altenatively for Keystone API V3:
auth => { auth => {
'openrc' => '/root/openrc', 'username' => 'test',
'password' => 'changeme',
'project_name' => 'test',
'project_domain_name' => 'domain1',
'user_domain_name' => 'domain1',
'auth_url' => 'http://localhost:35357/v3'
} }
or a service token and host, e.g.: 2. Using a path to an openrc file containing these credentials
auth => { auth => {
'service_token' => 'ADMIN', 'openrc' => '/root/openrc'
'auth_url' => 'http://localhost:35357/v2.0', }
3. Using a service token
For Keystone API V2:
auth => {
'token' => 'example',
'url' => 'http://localhost:35357/v2.0'
}
Alternatively for Keystone API V3:
auth => {
'token' => 'example',
'url' => 'http://localhost:35357/v3.0'
} }
If not present, the provider will look for environment variables for If not present, the provider will look for environment variables for

View File

@ -10,7 +10,7 @@ describe Puppet::Provider::Openstack do
before(:each) do before(:each) do
ENV['OS_USERNAME'] = nil ENV['OS_USERNAME'] = nil
ENV['OS_PASSWORD'] = nil ENV['OS_PASSWORD'] = nil
ENV['OS_TENANT_NAME'] = nil ENV['OS_PROJECT_NAME'] = nil
ENV['OS_AUTH_URL'] = nil ENV['OS_AUTH_URL'] = nil
end end
@ -22,11 +22,11 @@ describe Puppet::Provider::Openstack do
end end
end end
shared_examples 'authenticating with environment variables' do shared_examples 'authenticating with environment variables using API v2' do
it 'makes a successful request' do it 'makes a successful request' do
ENV['OS_USERNAME'] = 'test' ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123' ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_TENANT_NAME'] = 'test' ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0' ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0'
if provider.class == Class if provider.class == Class
provider.stubs(:openstack) provider.stubs(:openstack)
@ -46,6 +46,30 @@ describe Puppet::Provider::Openstack do
end end
end end
shared_examples 'authenticating with environment variables using API v3' do
it 'makes a successful request' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v3'
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 shared_examples 'it has no credentials' do
it 'fails to authenticate' do it 'fails to authenticate' do
expect{ provider.request('project', 'list', nil, nil, '--long') }.to raise_error(Puppet::Error::OpenstackAuthInputError, /No credentials provided/) expect{ provider.request('project', 'list', nil, nil, '--long') }.to raise_error(Puppet::Error::OpenstackAuthInputError, /No credentials provided/)
@ -61,7 +85,7 @@ describe Puppet::Provider::Openstack do
:auth => { :auth => {
'username' => 'test', 'username' => 'test',
'password' => 'abc123', 'password' => 'abc123',
'tenant_name' => 'test', 'project_name' => 'test',
'auth_url' => 'http://127.0.0.1:5000/v2.0', 'auth_url' => 'http://127.0.0.1:5000/v2.0',
} }
} }
@ -72,7 +96,7 @@ describe Puppet::Provider::Openstack do
it 'makes a successful request' do it 'makes a successful request' do
provider.class.stubs(:openstack) 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']]) .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-project-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
.returns('"ID","Name","Description","Enabled" .returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True "1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
') ')
@ -82,7 +106,7 @@ describe Puppet::Provider::Openstack do
end end
context 'with valid openrc file in parameters' do 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'" mock = "export OS_USERNAME='test'\nexport OS_PASSWORD='abc123'\nexport OS_PROJECT_NAME='test'\nexport OS_AUTH_URL='http://127.0.0.1:5000/v2.0'"
let(:resource_attrs) do let(:resource_attrs) do
{ {
:name => 'stubresource', :name => 'stubresource',
@ -98,7 +122,7 @@ describe Puppet::Provider::Openstack do
it 'makes a successful request' do it 'makes a successful request' do
File.expects(:open).with('/root/openrc').returns(StringIO.new(mock)) File.expects(:open).with('/root/openrc').returns(StringIO.new(mock))
provider.class.stubs(:openstack) 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']]) .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-project-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
.returns('"ID","Name","Description","Enabled" .returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True "1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
') ')
@ -113,7 +137,7 @@ describe Puppet::Provider::Openstack do
:name => 'stubresource', :name => 'stubresource',
:auth => { :auth => {
'token' => 'secrettoken', 'token' => 'secrettoken',
'auth_url' => 'http://127.0.0.1:5000/v2.0' 'url' => 'http://127.0.0.1:5000/v2.0'
} }
} }
end end
@ -149,7 +173,7 @@ Enabled="True"
end end
context 'with valid password credentials in environment variables' do context 'with valid password credentials in environment variables' do
it_behaves_like 'authenticating with environment variables' do it_behaves_like 'authenticating with environment variables using API v2' do
let(:resource_attrs) do let(:resource_attrs) do
{ {
:name => 'stubresource', :name => 'stubresource',
@ -181,7 +205,7 @@ Enabled="True"
:auth => { :auth => {
'username' => 'test', 'username' => 'test',
'password' => 'abc123', 'password' => 'abc123',
'tenant_name' => 'test', 'project_name' => 'test',
'auth_url' => 'http://127.0.0.1:5000/v2.0', 'auth_url' => 'http://127.0.0.1:5000/v2.0',
} }
} }
@ -191,7 +215,7 @@ Enabled="True"
end end
it 'retries' do it 'retries' do
provider.class.stubs(:openstack) 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']]) .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-project-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
.raises(Puppet::ExecutionFailure, 'Unable to establish connection') .raises(Puppet::ExecutionFailure, 'Unable to establish connection')
.then .then
.returns('') .returns('')
@ -205,7 +229,7 @@ Enabled="True"
describe '::request' do describe '::request' do
context 'with valid password credentials in environment variables' do context 'with valid password credentials in environment variables' do
it_behaves_like 'authenticating with environment variables' do it_behaves_like 'authenticating with environment variables using API v2' do
let(:resource_attrs) do let(:resource_attrs) do
{ {
:name => 'stubresource', :name => 'stubresource',