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
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
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']
auth_params && auth_params['token'] && auth_params['url']
end
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
def env_vars_set?
self.class.env_vars_set?
end
def self.password_auth_args(credentials)
['--os-username', credentials['username'],
creds = [ '--os-username', credentials['username'],
'--os-password', credentials['password'],
'--os-tenant-name', credentials['tenant_name'],
'--os-project-name', credentials['project_name'],
'--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
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']]
'--os-url', credentials['url'] ]
end
def token_auth_args(credentials)
@ -163,7 +168,6 @@ class Puppet::Provider::Openstack < Puppet::Provider
return creds
end
def self.get_credentials_from_env
env = ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS_/) }
credentials = {}

View File

@ -5,27 +5,46 @@ module Puppet::Util::Openstack
type.newparam(:auth) do
desc <<EOT
Hash of authentication credentials. Credentials can be specified as
password credentials, e.g.:
Hash of authentication credentials. Credentials can be specified as either :
1. Using a project/user with a password
For Keystone API V2:
auth => {
'username' => 'test',
'password' => 'passw0rd',
'tenant_name' => 'test',
'auth_url' => 'http://localhost:35357/v2.0',
'password' => 'changeme',
'project_name' => 'test',
'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 => {
'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 => {
'service_token' => 'ADMIN',
'auth_url' => 'http://localhost:35357/v2.0',
'openrc' => '/root/openrc'
}
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

View File

@ -10,7 +10,7 @@ describe Puppet::Provider::Openstack do
before(:each) do
ENV['OS_USERNAME'] = nil
ENV['OS_PASSWORD'] = nil
ENV['OS_TENANT_NAME'] = nil
ENV['OS_PROJECT_NAME'] = nil
ENV['OS_AUTH_URL'] = nil
end
@ -22,11 +22,11 @@ describe Puppet::Provider::Openstack do
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
ENV['OS_USERNAME'] = 'test'
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'
if provider.class == Class
provider.stubs(:openstack)
@ -46,6 +46,30 @@ describe Puppet::Provider::Openstack do
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
it 'fails to authenticate' do
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 => {
'username' => 'test',
'password' => 'abc123',
'tenant_name' => 'test',
'project_name' => 'test',
'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
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"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
')
@ -82,7 +106,7 @@ describe Puppet::Provider::Openstack do
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'"
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
{
:name => 'stubresource',
@ -98,7 +122,7 @@ describe Puppet::Provider::Openstack do
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']])
.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"
"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
')
@ -113,7 +137,7 @@ describe Puppet::Provider::Openstack do
:name => 'stubresource',
:auth => {
'token' => 'secrettoken',
'auth_url' => 'http://127.0.0.1:5000/v2.0'
'url' => 'http://127.0.0.1:5000/v2.0'
}
}
end
@ -149,7 +173,7 @@ Enabled="True"
end
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
{
:name => 'stubresource',
@ -181,7 +205,7 @@ Enabled="True"
:auth => {
'username' => 'test',
'password' => 'abc123',
'tenant_name' => 'test',
'project_name' => 'test',
'auth_url' => 'http://127.0.0.1:5000/v2.0',
}
}
@ -191,7 +215,7 @@ Enabled="True"
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']])
.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')
.then
.returns('')
@ -205,7 +229,7 @@ Enabled="True"
describe '::request' 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
{
:name => 'stubresource',