Merge "Keystone_endpoint match service by name/type."

This commit is contained in:
Jenkins 2015-11-24 15:29:02 +00:00 committed by Gerrit Code Review
commit 8f10d5dfdf
8 changed files with 523 additions and 61 deletions

View File

@ -97,8 +97,31 @@ keystone_service { 'nova':
description => 'Openstack Compute Service', description => 'Openstack Compute Service',
} }
```
Services can also be written with the type as a suffix:
```puppet
keystone_service { 'nova::type':
ensure => present,
description => 'Openstack Compute Service',
}
# Setup nova keystone endpoint # Setup nova keystone endpoint
keystone_endpoint { 'example-1-west/nova': keystone_endpoint { 'example-1-west/nova':
ensure => present,
type => 'compute',
public_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
admin_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
internal_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
}
```
Endpoints can also be written with the type as a suffix:
```puppet
keystone_endpoint { 'example-1-west/nova::compute':
ensure => present, ensure => present,
public_url => "http://127.0.0.1:8774/v2/%(tenant_id)s", public_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
admin_url => "http://127.0.0.1:8774/v2/%(tenant_id)s", admin_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
@ -106,6 +129,11 @@ keystone_endpoint { 'example-1-west/nova':
} }
``` ```
Defining a endpoint without the type is supported in Liberty release
for backward compatibility, but will be dropped in Mitaka, as this can
lead to corruption of the endpoint database if omitted. See (this
bug)[https://bugs.launchpad.net/puppet-keystone/+bug/1506996]
**Setting up a database for keystone** **Setting up a database for keystone**
A keystone database can be configured separately from the keystone services. A keystone database can be configured separately from the keystone services.

View File

@ -7,6 +7,10 @@ Puppet::Type.type(:keystone_endpoint).provide(
desc "Provider to manage keystone endpoints." desc "Provider to manage keystone endpoints."
include PuppetX::Keystone::CompositeNamevar::Helpers
@endpoints = nil
@services = nil
@credentials = Puppet::Provider::Openstack::CredentialsV3.new @credentials = Puppet::Provider::Openstack::CredentialsV3.new
def initialize(value={}) def initialize(value={})
@ -15,16 +19,42 @@ Puppet::Type.type(:keystone_endpoint).provide(
end end
def create def create
region, name = resource[:name].split('/') # Reset the cache.
self.class.services = nil
name = resource[:name]
region = resource[:region]
type = resource[:type]
type = self.class.type_from_service(name) unless set?(:type)
@property_hash[:type] = type
services = self.class.services.find_all { |s| s[:name] == name }
service = services.find { |s| s[:type] == type }
if service.nil? && services.count == 1
# For backward comptatibility, match the service by name only.
name = services[0][:id]
else
# Math the service by id.
name = service[:id] if service
end
ids = [] ids = []
created = false
[:admin_url, :internal_url, :public_url].each do |scope| [:admin_url, :internal_url, :public_url].each do |scope|
if resource[scope] if resource[scope]
ids << endpoint_create(name, region, scope.to_s.sub(/_url$/,''), created = true
resource[scope])[:id] ids << endpoint_create(name, region, scope.to_s.sub(/_url$/, ''),
resource[scope])[:id]
end end
end end
@property_hash[:id] = ids.join(',') if created
@property_hash[:ensure] = :present @property_hash[:id] = ids.join(',')
@property_hash[:ensure] = :present
else
warning('Specifying a keystone_endpoint without an ' \
'admin_url/public_url/internal_url ' \
"won't create the endpoint at all, despite what Puppet is saying.")
@property_hash[:ensure] = :absent
end
end end
def destroy def destroy
@ -53,21 +83,22 @@ Puppet::Type.type(:keystone_endpoint).provide(
@property_flush[:admin_url] = value @property_flush[:admin_url] = value
end end
def region=(value) def region=(_)
raise(Puppet::Error, "Updating the endpoint's region is not currently supported.") fail(Puppet::Error, "Updating the endpoint's region is not currently supported.")
end end
def self.instances def self.instances
names=[] names = []
list=[] list = []
endpoints = request('endpoint', 'list')
endpoints.each do |current| endpoints.each do |current|
name = "#{current[:region]}/#{current[:service_name]}" name = transform_name(current[:region], current[:service_name], current[:service_type])
unless names.include?(name) unless names.include?(name)
names << name names << name
endpoint = { :name => name, current[:interface].to_sym => current } endpoint = { :name => name, current[:interface].to_sym => current }
endpoints.each do |ep_osc| endpoints.each do |ep_osc|
if (ep_osc[:id] != current[:id]) && (ep_osc[:service_name] == current[:service_name]) if (ep_osc[:id] != current[:id]) &&
(ep_osc[:service_name] == current[:service_name]) &&
(ep_osc[:service_type] == current[:service_type])
endpoint.merge!(ep_osc[:interface].to_sym => ep_osc) endpoint.merge!(ep_osc[:interface].to_sym => ep_osc)
end end
end end
@ -88,11 +119,11 @@ Puppet::Type.type(:keystone_endpoint).provide(
end end
def self.prefetch(resources) def self.prefetch(resources)
endpoints = instances prefetch_composite(resources) do |sorted_namevars|
resources.keys.each do |name| name = sorted_namevars[0]
if provider = endpoints.find{ |endpoint| endpoint.name == name } region = sorted_namevars[1]
resources[name].provider = provider type = sorted_namevars[2]
end transform_name(region, name, type)
end end
end end
@ -118,4 +149,74 @@ Puppet::Type.type(:keystone_endpoint).provide(
properties = [name, interface, url, '--region', region] properties = [name, interface, url, '--region', region]
self.class.request('endpoint', 'create', properties) self.class.request('endpoint', 'create', properties)
end end
private
def self.endpoints
return @endpoints unless @endpoints.nil?
@endpoints = request('endpoint', 'list')
end
def self.endpoints=(value)
@endpoints = value
end
def self.services
return @services unless @services.nil?
@services = request('service', 'list')
end
def self.services=(value)
@services = value
end
def self.endpoint_from_region_name(region, name)
endpoints.find_all { |e| e[:region] == region && e[:service_name] == name }
.map { |e| e[:service_type] }.uniq
end
def self.type_from_service(name)
types = services.find_all { |s| s[:name] == name }.map { |e| e[:type] }.uniq
if types.count == 1
types[0]
else
# We don't fail here as it can happen during a ensure => absent.
PuppetX::Keystone::CompositeNamevar::Unset
end
end
def self.service_type(services, region, name)
nbr_of_services = services.count
err_msg = ["endpoint matching #{region}/#{name}:"]
type = nil
case
when nbr_of_services == 1
type = services[0]
when nbr_of_services > 1
err_msg += [endpoint_from_region_name(region, name).join(' ')]
when nbr_of_services < 1
# Then we try to get the type by service name.
type = type_from_service(name)
end
if !type.nil?
type
else
fail(Puppet::Error, 'Cannot get the correct endpoint type: ' \
"#{err_msg.join(' ')}")
end
end
def self.transform_name(region, name, type)
if type == PuppetX::Keystone::CompositeNamevar::Unset
type = service_type(endpoint_from_region_name(region, name), region, name)
end
if type == PuppetX::Keystone::CompositeNamevar::Unset
Puppet.debug("Could not find the type for endpoint #{region}/#{name}")
"#{region}/#{name}"
else
"#{region}/#{name}::#{type}"
end
end
end end

View File

@ -1,34 +1,43 @@
# LP#1408531 # LP#1408531
File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
require 'puppet_x/keystone/composite_namevar'
require 'puppet_x/keystone/type'
Puppet::Type.newtype(:keystone_endpoint) do Puppet::Type.newtype(:keystone_endpoint) do
desc 'Type for managing keystone endpoints.' desc 'Type for managing keystone endpoints.'
include PuppetX::Keystone::CompositeNamevar::Helpers
ensurable ensurable
newparam(:name, :namevar => true) do newparam(:name, :namevar => true)
newvalues(/\S+\/\S+/)
end
newproperty(:id) do newproperty(:id) do
validate do |v| include PuppetX::Keystone::Type::ReadOnly
raise(Puppet::Error, 'This is a read only property') end
newparam(:region) do
isnamevar
include PuppetX::Keystone::Type::Required
end
newparam(:type) do
isnamevar
defaultto do
deprecation_msg = 'Support for a endpoint without the type ' \
'set is deprecated in Liberty. ' \
'It will be dropped in Mitaka.'
warning(deprecation_msg)
PuppetX::Keystone::CompositeNamevar::Unset
end end
end end
newproperty(:region) do newproperty(:public_url)
end
newproperty(:public_url) do newproperty(:internal_url)
end
newproperty(:internal_url) do newproperty(:admin_url)
end
newproperty(:admin_url) do
end
# we should not do anything until the keystone service is started # we should not do anything until the keystone service is started
autorequire(:anchor) do autorequire(:anchor) do
@ -36,7 +45,54 @@ Puppet::Type.newtype(:keystone_endpoint) do
end end
autorequire(:keystone_service) do autorequire(:keystone_service) do
(region, service_name) = self[:name].split('/') if parameter_set?(:type)
[service_name] "#{name}::#{self[:type]}"
else
title = catalog.resources
.find_all { |e| e.type == :keystone_service && e[:name] == name }
.map { |e| e.title }.uniq
if title.count == 1
title
else
warning("Couldn't find the type of the domain to require using #{name}")
name
end
end
end
def self.title_patterns
name = PuppetX::Keystone::CompositeNamevar.not_two_colon_regex
type = Regexp.new(/.+/)
region = Regexp.new(/[^\/]+/)
[
[
/^(#{region})\/(#{name})::(#{type})$/,
[
[:region],
[:name],
[:type]
]
],
[
/^(#{region})\/(#{name})$/,
[
[:region],
[:name]
]
],
[
/^(#{name})::(#{type})$/,
[
[:name],
[:type]
]
],
[
/^(#{name})$/,
[
[:name]
]
]
]
end end
end end

View File

@ -5,8 +5,13 @@ module PuppetX
def self.included(klass) def self.included(klass)
klass.class_eval do klass.class_eval do
defaultto do defaultto do
custom = ''
if respond_to?(:required_custom_message)
custom = send(:required_custom_message)
end
fail(Puppet::ResourceError, fail(Puppet::ResourceError,
"Parameter #{name} failed on " \ "#{custom}" \
"Parameter #{name} failed on " \
"#{resource.class.to_s.split('::')[-1]}[#{resource.name}]: " \ "#{resource.class.to_s.split('::')[-1]}[#{resource.name}]: " \
'Required parameter.') 'Required parameter.')
end end

View File

@ -234,16 +234,49 @@ describe 'basic keystone server with resources' do
end end
end end
end end
describe 'composite namevar for keystone_service' do
describe 'composite namevar for keystone_service and keystone_endpoint' do
let(:pp) do let(:pp) do
<<-EOM <<-EOM
keystone_service { 'service_1::type_1': ensure => present } keystone_service { 'service_1::type_1': ensure => present }
keystone_service { 'service_1': type => 'type_2', ensure => present } keystone_service { 'service_1': type => 'type_2', ensure => present }
keystone_endpoint { 'RegionOne/service_1::type_2':
ensure => present,
public_url => 'http://public_service1_type2',
internal_url => 'http://internal_service1_type2',
admin_url => 'http://admin_service1_type2'
}
keystone_endpoint { 'service_1':
ensure => present,
region => 'RegionOne',
type => 'type_1',
public_url => 'http://public_url/',
internal_url => 'http://public_url/',
admin_url => 'http://public_url/'
}
EOM EOM
end end
it 'should be possible to create two services different only by their type' do it 'should be possible to create two services different only by their type' do
apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true) apply_manifest(pp, :catch_changes => true)
end end
describe 'puppet service are created' do
it 'for service' do
shell('puppet resource keystone_service') do |result|
expect(result.stdout)
.to include_regexp([/keystone_service { 'service_1::type_1':/,
/keystone_service { 'service_1::type_2':/])
end
end
end
describe 'puppet endpoints are created' do
it 'for service' do
shell('puppet resource keystone_endpoint') do |result|
expect(result.stdout)
.to include_regexp([/keystone_endpoint { 'RegionOne\/service_1::type_1':/,
/keystone_endpoint { 'RegionOne\/service_1::type_2':/])
end
end
end
end end
end end

View File

@ -215,4 +215,48 @@ describe 'keystone server running with Apache/WSGI with resources' do
apply_manifest(pp, :catch_changes => true) apply_manifest(pp, :catch_changes => true)
end end
end end
describe 'composite namevar for keystone_service and keystone_endpoint' do
let(:pp) do
<<-EOM
keystone_service { 'service_1::type_1': ensure => present }
keystone_service { 'service_1': type => 'type_2', ensure => present }
keystone_endpoint { 'RegionOne/service_1::type_2':
ensure => present,
public_url => 'http://public_service1_type2',
internal_url => 'http://internal_service1_type2',
admin_url => 'http://admin_service1_type2'
}
keystone_endpoint { 'service_1':
ensure => present,
region => 'RegionOne',
type => 'type_1',
public_url => 'http://public_url/',
internal_url => 'http://public_url/',
admin_url => 'http://public_url/'
}
EOM
end
it 'should be possible to create two services different only by their type' do
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
describe 'puppet service are created' do
it 'for service' do
shell('puppet resource keystone_service') do |result|
expect(result.stdout)
.to include_regexp([/keystone_service { 'service_1::type_1':/,
/keystone_service { 'service_1::type_2':/])
end
end
end
describe 'puppet endpoints are created' do
it 'for service' do
shell('puppet resource keystone_endpoint') do |result|
expect(result.stdout)
.to include_regexp([/keystone_endpoint { 'RegionOne\/service_1::type_1':/,
/keystone_endpoint { 'RegionOne\/service_1::type_2':/])
end
end
end
end
end end

View File

@ -2,9 +2,7 @@ require 'puppet'
require 'spec_helper' require 'spec_helper'
require 'puppet/provider/keystone_endpoint/openstack' require 'puppet/provider/keystone_endpoint/openstack'
provider_class = Puppet::Type.type(:keystone_endpoint).provider(:openstack) describe Puppet::Type.type(:keystone_endpoint).provider(:openstack) do
describe provider_class do
let(:set_env) do let(:set_env) do
ENV['OS_USERNAME'] = 'test' ENV['OS_USERNAME'] = 'test'
@ -17,11 +15,11 @@ describe provider_class do
let(:endpoint_attrs) do let(:endpoint_attrs) do
{ {
:name => 'region/endpoint', :title => 'region/endpoint',
:ensure => 'present', :ensure => 'present',
:public_url => 'http://127.0.0.1:5000', :public_url => 'http://127.0.0.1:5000',
:internal_url => 'http://127.0.0.1:5001', :internal_url => 'http://127.0.0.1:5001',
:admin_url => 'http://127.0.0.1:5002', :admin_url => 'http://127.0.0.1:5002'
} }
end end
@ -30,47 +28,79 @@ describe provider_class do
end end
let(:provider) do let(:provider) do
provider_class.new(resource) described_class.new(resource)
end end
before(:each) do before(:each) do
set_env set_env
described_class.endpoints = nil
described_class.services = nil
end end
describe '#create' do describe '#create' do
it 'creates an endpoint' do before(:each) do
provider.class.expects(:openstack) described_class.expects(:openstack)
.with('endpoint', 'create', '--format', 'shell', ['endpoint', 'admin', 'http://127.0.0.1:5002', '--region', 'region']) .with('endpoint', 'create', '--format', 'shell',
['service_id1', 'admin', 'http://127.0.0.1:5002', '--region', 'region'])
.returns('admin_url="http://127.0.0.1:5002" .returns('admin_url="http://127.0.0.1:5002"
id="endpoint1_id" id="endpoint1_id"
region="region" region="region"
') ')
provider.class.expects(:openstack) described_class.expects(:openstack)
.with('endpoint', 'create', '--format', 'shell', ['endpoint', 'internal', 'http://127.0.0.1:5001', '--region', 'region']) .with('endpoint', 'create', '--format', 'shell',
['service_id1', 'internal', 'http://127.0.0.1:5001', '--region', 'region'])
.returns('internal_url="http://127.0.0.1:5001" .returns('internal_url="http://127.0.0.1:5001"
id="endpoint2_id" id="endpoint2_id"
region="region" region="region"
') ')
provider.class.expects(:openstack) described_class.expects(:openstack)
.with('endpoint', 'create', '--format', 'shell', ['endpoint', 'public', 'http://127.0.0.1:5000', '--region', 'region']) .with('endpoint', 'create', '--format', 'shell',
['service_id1', 'public', 'http://127.0.0.1:5000', '--region', 'region'])
.returns('public_url="http://127.0.0.1:5000" .returns('public_url="http://127.0.0.1:5000"
id="endpoint3_id" id="endpoint3_id"
region="region" region="region"
') ')
provider.create described_class.expects(:openstack)
expect(provider.exists?).to be_truthy .with('service', 'list', '--quiet', '--format', 'csv', [])
expect(provider.id).to eq('endpoint1_id,endpoint2_id,endpoint3_id') .returns('"ID","Name","Type"
"service_id1","endpoint","type_one"
')
end
context 'without the type' do
it 'creates an endpoint' do
provider.create
expect(provider.exists?).to be_truthy
expect(provider.id).to eq('endpoint1_id,endpoint2_id,endpoint3_id')
end
end
context 'with the type' do
let(:endpoint_attrs) do
{
:title => 'region/endpoint',
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000',
:internal_url => 'http://127.0.0.1:5001',
:admin_url => 'http://127.0.0.1:5002',
:type => 'type_one'
}
end
it 'creates an endpoint' do
provider.create
expect(provider.exists?).to be_truthy
expect(provider.id).to eq('endpoint1_id,endpoint2_id,endpoint3_id')
end
end end
end end
describe '#destroy' do describe '#destroy' do
it 'destroys an endpoint' do it 'destroys an endpoint' do
provider.instance_variable_get('@property_hash')[:id] = 'endpoint1_id,endpoint2_id,endpoint3_id' provider.instance_variable_get('@property_hash')[:id] = 'endpoint1_id,endpoint2_id,endpoint3_id'
provider.class.expects(:openstack) described_class.expects(:openstack)
.with('endpoint', 'delete', 'endpoint1_id') .with('endpoint', 'delete', 'endpoint1_id')
provider.class.expects(:openstack) described_class.expects(:openstack)
.with('endpoint', 'delete', 'endpoint2_id') .with('endpoint', 'delete', 'endpoint2_id')
provider.class.expects(:openstack) described_class.expects(:openstack)
.with('endpoint', 'delete', 'endpoint3_id') .with('endpoint', 'delete', 'endpoint3_id')
provider.destroy provider.destroy
expect(provider.exists?).to be_falsey expect(provider.exists?).to be_falsey
@ -80,7 +110,7 @@ region="region"
describe '#exists' do describe '#exists' do
context 'when tenant does not exist' do context 'when tenant does not exist' do
subject(:response) do subject(:response) do
response = provider.exists? provider.exists?
end end
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
@ -89,16 +119,130 @@ region="region"
describe '#instances' do describe '#instances' do
it 'finds every tenant' do it 'finds every tenant' do
provider.class.expects(:openstack) described_class.expects(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', []) .with('endpoint', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Region","Service Name","Service Type","Enabled","Interface","URL" .returns('"ID","Region","Service Name","Service Type","Enabled","Interface","URL"
"endpoint1_id","RegionOne","keystone","identity",True,"admin","http://127.0.0.1:5002" "endpoint1_id","RegionOne","keystone","identity",True,"admin","http://127.0.0.1:5002"
"endpoint2_id","RegionOne","keystone","identity",True,"internal","https://127.0.0.1:5001" "endpoint2_id","RegionOne","keystone","identity",True,"internal","https://127.0.0.1:5001"
"endpoint3_id","RegionOne","keystone","identity",True,"public","https://127.0.0.1:5000" "endpoint3_id","RegionOne","keystone","identity",True,"public","https://127.0.0.1:5000"
') ')
instances = Puppet::Type::Keystone_endpoint::ProviderOpenstack.instances instances = described_class.instances
expect(instances.count).to eq(1) expect(instances.count).to eq(1)
end end
end end
describe '#prefetch' do
context 'working: fq or nfq and matching resource' do
before(:each) do
described_class.expects(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Region","Service Name","Service Type","Enabled","Interface","URL"
"endpoint1_id","RegionOne","keystone","identity",True,"admin","http://127.0.0.1:5002"
"endpoint2_id","RegionOne","keystone","identity",True,"internal","https://127.0.0.1:5001"
"endpoint3_id","RegionOne","keystone","identity",True,"public","https://127.0.0.1:5000"
')
end
context '#fq resource in title' do
let(:resources) do
[Puppet::Type.type(:keystone_endpoint).new(:title => 'RegionOne/keystone::identity', :ensure => :present),
Puppet::Type.type(:keystone_endpoint).new(:title => 'RegionOne/keystone::identityv3', :ensure => :present)]
end
include_examples 'prefetch the resources'
end
context '#fq resource' do
let(:resources) do
[Puppet::Type.type(:keystone_endpoint).new(:title => 'keystone', :region => 'RegionOne', :type => 'identity', :ensure => :present),
Puppet::Type.type(:keystone_endpoint).new(:title => 'RegionOne/keystone::identityv3', :ensure => :present)]
end
include_examples 'prefetch the resources'
end
context '#nfq resource in title matching existing endpoint' do
let(:resources) do
[Puppet::Type.type(:keystone_endpoint).new(:title => 'RegionOne/keystone', :ensure => :present),
Puppet::Type.type(:keystone_endpoint).new(:title => 'RegionOne/keystone::identityv3', :ensure => :present)]
end
include_examples 'prefetch the resources'
end
context '#nfq resource matching existing endpoint' do
let(:resources) do
[Puppet::Type.type(:keystone_endpoint).new(:title => 'keystone', :region => 'RegionOne', :ensure => :present),
Puppet::Type.type(:keystone_endpoint).new(:title => 'RegionOne/keystone::identityv3', :ensure => :present)]
end
include_examples 'prefetch the resources'
end
end
context 'not working' do
context 'too many type' do
before(:each) do
described_class.expects(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Region","Service Name","Service Type","Enabled","Interface","URL"
"endpoint1_id","RegionOne","keystone","identity",True,"admin","http://127.0.0.1:5002"
"endpoint2_id","RegionOne","keystone","identity",True,"internal","https://127.0.0.1:5001"
"endpoint3_id","RegionOne","keystone","identity",True,"public","https://127.0.0.1:5000"
"endpoint4_id","RegionOne","keystone","identityv3",True,"admin","http://127.0.0.1:5002"
"endpoint5_id","RegionOne","keystone","identityv3",True,"internal","https://127.0.0.1:5001"
"endpoint6_id","RegionOne","keystone","identityv3",True,"public","https://127.0.0.1:5000"
')
end
it "should fail as it's not possible to get the right type here" do
existing = Puppet::Type.type(:keystone_endpoint)
.new(:title => 'RegionOne/keystone', :ensure => :present)
resource = mock
r = []
r << existing
catalog = Puppet::Resource::Catalog.new
r.each { |res| catalog.add_resource(res) }
m_value = mock
m_first = mock
resource.expects(:values).returns(m_value)
m_value.expects(:first).returns(m_first)
m_first.expects(:catalog).returns(catalog)
m_first.expects(:class).returns(described_class.resource_type)
expect { described_class.prefetch(resource) }
.to raise_error(Puppet::Error,
/endpoint matching RegionOne\/keystone: identity identityv3/)
end
end
end
context 'not any type but existing service' do
before(:each) do
described_class.expects(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Region","Service Name","Service Type","Enabled","Interface","URL"
"endpoint1_id","RegionOne","keystone","identity",True,"admin","http://127.0.0.1:5002"
"endpoint2_id","RegionOne","keystone","identity",True,"internal","https://127.0.0.1:5001"
"endpoint3_id","RegionOne","keystone","identity",True,"public","https://127.0.0.1:5000"
')
described_class.expects(:openstack)
.with('service', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name","Type"
"service1_id","keystonev3","identity"
')
end
it 'should be successful' do
existing = Puppet::Type.type(:keystone_endpoint)
.new(:title => 'RegionOne/keystonev3', :ensure => :present)
resource = mock
r = []
r << existing
catalog = Puppet::Resource::Catalog.new
r.each { |res| catalog.add_resource(res) }
m_value = mock
m_first = mock
resource.expects(:values).returns(m_value)
m_value.expects(:first).returns(m_first)
m_first.expects(:catalog).returns(catalog)
m_first.expects(:class).returns(described_class.resource_type)
expect { described_class.prefetch(resource) }.not_to raise_error
expect(existing.provider.ensure).to eq(:absent)
end
end
end
end end
end end

View File

@ -1,9 +1,60 @@
require 'spec_helper'
require 'puppet'
require 'puppet/type/keystone_endpoint'
describe Puppet::Type.type(:keystone_endpoint) do describe Puppet::Type.type(:keystone_endpoint) do
it 'should fail when the namevar does not contain a region' do describe 'region_one/endpoint_name::type_one' do
expect do include_examples 'parse title correctly',
Puppet::Type.type(:keystone_endpoint).new(:name => 'foo') :name => 'endpoint_name',
end.to raise_error(Puppet::Error, /Invalid value/) :region => 'region_one',
:type => 'type_one'
end end
describe 'new_endpoint_without_region::type' do
include_examples 'croak on the required parameter',
'Parameter region failed on Keystone_endpoint[new_endpoint_without_region]:'
end
describe '#autorequire' do
let(:service_one) do
Puppet::Type.type(:keystone_service).new(:title => 'service_one', :type => 'type_one')
end
let(:service_two) do
Puppet::Type.type(:keystone_service).new(:title => 'service_one::type_two')
end
let(:service_three) do
Puppet::Type.type(:keystone_service).new(:title => 'service_two::type_one')
end
context 'domain autorequire from title' do
let(:endpoint) do
Puppet::Type.type(:keystone_endpoint).new(:title => 'region_one/service_one::type_one')
end
describe 'should require the correct domain' do
let(:resources) { [endpoint, service_one, service_two] }
include_examples 'autorequire the correct resources'
end
end
context 'domain autorequire from title without type (to be removed at Mitaka)' do
let(:endpoint) do
Puppet::Type.type(:keystone_endpoint).new(:title => 'region_one/service_one')
end
describe 'should require the correct domain' do
let(:resources) { [endpoint, service_one, service_two] }
include_examples 'autorequire the correct resources'
end
end
context 'domain autorequire from title without type on fq service name (to be removed at Mitaka)' do
let(:endpoint) do
Puppet::Type.type(:keystone_endpoint).new(:title => 'region_one/service_two')
end
describe 'should require the correct domain' do
let(:resources) { [endpoint, service_three, service_one] }
include_examples 'autorequire the correct resources'
end
end
end
end end