puppet-keystone/spec/unit/provider/keystone_spec.rb
Tobias Urdin bc1ff1d7cb Add keystone::bootstrap class
This class combines the keystone-manage bootstrap command
from init, the keystone::endpoint functionality that manages
the keystone endpoints and the keystone::roles::admin class
that manages users and projects.

This is one of the steps to make sure we only have a single
point of entry for bootstrapping (keystone-manage bootstrap)
and then only managing resources after that.

This is especially required since we are getting rid of the
admin token and cannot manage resources before keystone-manage
bootstrap has created the user, project, service and endpoints
for us.

These resources should always be in the default domain and
deployments should manage domain specific configuration themselves
using the provider resources.

This class uses the default values from the keystone-manage
bootstrap command.

In the past puppet-keystone has always created a openstack project
that is assumed as a admin project even though the bootstrap command
creates the admin project. Since this uses the default values from
the bootstrap command we should move away from having an openstack
project, if we need that in testing it should be created there and
not in the default deployment.

Depends-On: https://review.opendev.org/#/c/698528/
Change-Id: I683fcdd743bddf6d4e989dd7e7c553db745934db
2019-12-11 16:37:51 +00:00

245 lines
8.2 KiB
Ruby

require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone'
require 'tempfile'
setup_provider_tests
klass = Puppet::Provider::Keystone
class Puppet::Provider::Keystone
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
end
describe Puppet::Provider::Keystone do
let(:set_env) do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000/v3'
end
let(:another_class) do
class AnotherKlass < Puppet::Provider::Keystone
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
end
AnotherKlass
end
before(:each) { set_env }
after :each do
klass.reset
another_class.reset
end
describe '#domain_id_from_name' do
it 'should list all domains when requesting a domain name from an ID' do
klass.expects(:openstack)
.with('domain', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name","Enabled","Description"
"someid","SomeName",True,"default domain"
')
expect(klass.domain_id_from_name('SomeName')).to eq('someid')
end
it 'should lookup a domain when not found in the hash' do
klass.expects(:openstack)
.with('domain', 'show', '--format', 'shell', 'NewName')
.returns('
name="NewName"
id="newid"
')
expect(klass.domain_id_from_name('NewName')).to eq('newid')
end
it 'should print an error when there is no such domain' do
klass.expects(:openstack)
.with('domain', 'show', '--format', 'shell', 'doesnotexist')
.returns('
')
klass.expects(:err)
.with('Could not find domain with name [doesnotexist]')
expect(klass.domain_id_from_name('doesnotexist')).to eq(nil)
end
end
describe '#fetch_project' do
let(:set_env) do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000/v3'
end
before(:each) do
set_env
end
it 'should be false if the project does not exist' do
klass.expects(:request_timeout).returns(0)
klass.expects(:openstack)
.with('project', 'show', '--format', 'shell', ['no_project', '--domain', 'Default'])
.once
.raises(Puppet::ExecutionFailure, "Execution of '/usr/bin/openstack project show --format shell no_project' returned 1: No project with a name or ID of 'no_project' exists.")
expect(klass.fetch_project('no_project', 'Default')).to be_falsey
end
it 'should return the project' do
klass.expects(:openstack)
.with('project', 'show', '--format', 'shell', ['The Project', '--domain', 'Default'])
.returns('
name="The Project"
id="the_project_id"
')
expect(klass.fetch_project('The Project', 'Default')).to eq({:name=>"The Project", :id=>"the_project_id"})
end
end
describe '#fetch_user' do
let(:set_env) do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000/v3'
end
before(:each) do
set_env
end
it 'should be false if the user does not exist' do
klass.expects(:request_timeout).returns(0)
klass.expects(:openstack)
.with('user', 'show', '--format', 'shell', ['no_user', '--domain', 'Default'])
.once
.raises(Puppet::ExecutionFailure, "Execution of '/usr/bin/openstack user show --format shell no_user' returned 1: No user with a name or ID of 'no_user' exists.")
expect(klass.fetch_user('no_user', 'Default')).to be_falsey
end
it 'should return the user' do
klass.expects(:openstack)
.with('user', 'show', '--format', 'shell', ['The User', '--domain', 'Default'])
.returns('
name="The User"
id="the_user_id"
')
expect(klass.fetch_user('The User', 'Default')).to eq({:name=>"The User", :id=>"the_user_id"})
end
end
describe '#get_auth_url' do
it 'should raise when OS_AUTH_URL is no defined in either the environment or the openrc file and there is no keystone puppet config file' do
home = ENV['HOME']
ENV.clear
File.expects(:exists?).with("#{home}/openrc").returns(false)
File.expects(:exists?).with('/root/openrc').returns(false)
expect { klass.get_auth_url }.to raise_error(Puppet::Error, "File: /etc/keystone/puppet.conf does not contain all required configuration keys. Cannot authenticate to Keystone.")
end
it 'should return the OS_AUTH_URL from the environment' do
ENV.clear
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5001'
expect(klass.get_auth_url).to eq('http://127.0.0.1:5001')
end
it 'should return the OS_AUTH_URL from the openrc file when there is no OS_AUTH_URL in the environment' do
home = ENV['HOME']
ENV.clear
mock = {'OS_AUTH_URL' => 'http://127.0.0.1:5001'}
klass.expects(:get_os_vars_from_rcfile).with("#{home}/openrc").returns(mock)
expect(klass.get_auth_url).to eq('http://127.0.0.1:5001')
end
it 'should use auth_endpoint when nothing else is available' do
ENV.clear
mock = 'http://127.0.0.1:5001'
klass.expects(:auth_endpoint).returns(mock)
expect(klass.get_auth_url).to eq('http://127.0.0.1:5001')
end
end
describe '#set_domain_for_name' do
it 'should raise an error if the domain is not provided' do
expect do
klass.set_domain_for_name('name', nil)
end.to raise_error(Puppet::Error, /Missing domain name for resource/)
end
it 'should return the name only when the provided domain is the default domain id' do
klass.expects(:default_domain_id)
.returns('default')
klass.expects(:openstack)
.with('domain', 'show', '--format', 'shell', 'Default')
.returns('
name="Default"
id="default"
')
expect(klass.set_domain_for_name('name', 'Default')).to eq('name')
end
it 'should return the name and domain when the provided domain is not the default domain id' do
klass.expects(:default_domain_id)
.returns('default')
klass.expects(:openstack)
.with('domain', 'show', '--format', 'shell', 'Other Domain')
.returns('
name="Other Domain"
id="other_domain_id"
')
expect(klass.set_domain_for_name('name', 'Other Domain')).to eq('name::Other Domain')
end
it 'should return the name only if the domain cannot be fetched' do
klass.expects(:default_domain_id)
.returns('default')
klass.expects(:openstack)
.with('domain', 'show', '--format', 'shell', 'Unknown Domain')
.returns('')
expect(klass.set_domain_for_name('name', 'Unknown Domain')).to eq('name')
end
end
describe 'when using domains' do
before(:each) do
set_env
end
it 'should list all domains when requesting a domain name from an ID' do
klass.expects(:openstack)
.with('domain', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name","Enabled","Description"
"somename","SomeName",True,"default domain"
')
expect(klass.domain_name_from_id('somename')).to eq('SomeName')
end
it 'should lookup a domain when not found in the hash' do
klass.expects(:openstack)
.with('domain', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name","Enabled","Description"
"somename","SomeName",True,"default domain"
')
klass.expects(:openstack)
.with('domain', 'show', '--format', 'shell', 'another')
.returns('
name="AnOther"
id="another"
')
expect(klass.domain_name_from_id('somename')).to eq('SomeName')
expect(klass.domain_name_from_id('another')).to eq('AnOther')
end
it 'should print an error when there is no such domain' do
klass.expects(:openstack)
.with('domain', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name","Enabled","Description"
"somename","SomeName",True,"default domain"
')
klass.expects(:openstack)
.with('domain', 'show', '--format', 'shell', 'doesnotexist')
.returns('
')
klass.expects(:err)
.with('Could not find domain with id [doesnotexist]')
expect(klass.domain_name_from_id('doesnotexist')).to eq(nil)
end
end
end