Merge "Keystone_endpoint match service by name/type."
This commit is contained in:
commit
8f10d5dfdf
28
README.md
28
README.md
@ -97,8 +97,31 @@ keystone_service { 'nova':
|
||||
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
|
||||
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,
|
||||
public_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**
|
||||
|
||||
A keystone database can be configured separately from the keystone services.
|
||||
|
@ -7,6 +7,10 @@ Puppet::Type.type(:keystone_endpoint).provide(
|
||||
|
||||
desc "Provider to manage keystone endpoints."
|
||||
|
||||
include PuppetX::Keystone::CompositeNamevar::Helpers
|
||||
|
||||
@endpoints = nil
|
||||
@services = nil
|
||||
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
|
||||
|
||||
def initialize(value={})
|
||||
@ -15,16 +19,42 @@ Puppet::Type.type(:keystone_endpoint).provide(
|
||||
end
|
||||
|
||||
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 = []
|
||||
|
||||
created = false
|
||||
[:admin_url, :internal_url, :public_url].each do |scope|
|
||||
if resource[scope]
|
||||
ids << endpoint_create(name, region, scope.to_s.sub(/_url$/,''),
|
||||
resource[scope])[:id]
|
||||
created = true
|
||||
ids << endpoint_create(name, region, scope.to_s.sub(/_url$/, ''),
|
||||
resource[scope])[:id]
|
||||
end
|
||||
end
|
||||
@property_hash[:id] = ids.join(',')
|
||||
@property_hash[:ensure] = :present
|
||||
if created
|
||||
@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
|
||||
|
||||
def destroy
|
||||
@ -53,21 +83,22 @@ Puppet::Type.type(:keystone_endpoint).provide(
|
||||
@property_flush[:admin_url] = value
|
||||
end
|
||||
|
||||
def region=(value)
|
||||
raise(Puppet::Error, "Updating the endpoint's region is not currently supported.")
|
||||
def region=(_)
|
||||
fail(Puppet::Error, "Updating the endpoint's region is not currently supported.")
|
||||
end
|
||||
|
||||
def self.instances
|
||||
names=[]
|
||||
list=[]
|
||||
endpoints = request('endpoint', 'list')
|
||||
names = []
|
||||
list = []
|
||||
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)
|
||||
names << name
|
||||
endpoint = { :name => name, current[:interface].to_sym => current }
|
||||
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)
|
||||
end
|
||||
end
|
||||
@ -88,11 +119,11 @@ Puppet::Type.type(:keystone_endpoint).provide(
|
||||
end
|
||||
|
||||
def self.prefetch(resources)
|
||||
endpoints = instances
|
||||
resources.keys.each do |name|
|
||||
if provider = endpoints.find{ |endpoint| endpoint.name == name }
|
||||
resources[name].provider = provider
|
||||
end
|
||||
prefetch_composite(resources) do |sorted_namevars|
|
||||
name = sorted_namevars[0]
|
||||
region = sorted_namevars[1]
|
||||
type = sorted_namevars[2]
|
||||
transform_name(region, name, type)
|
||||
end
|
||||
end
|
||||
|
||||
@ -118,4 +149,74 @@ Puppet::Type.type(:keystone_endpoint).provide(
|
||||
properties = [name, interface, url, '--region', region]
|
||||
self.class.request('endpoint', 'create', properties)
|
||||
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
|
||||
|
@ -1,34 +1,43 @@
|
||||
# LP#1408531
|
||||
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) }
|
||||
require 'puppet_x/keystone/composite_namevar'
|
||||
require 'puppet_x/keystone/type'
|
||||
|
||||
Puppet::Type.newtype(:keystone_endpoint) do
|
||||
|
||||
desc 'Type for managing keystone endpoints.'
|
||||
|
||||
include PuppetX::Keystone::CompositeNamevar::Helpers
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+\/\S+/)
|
||||
end
|
||||
newparam(:name, :namevar => true)
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
include PuppetX::Keystone::Type::ReadOnly
|
||||
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
|
||||
|
||||
newproperty(:region) do
|
||||
end
|
||||
newproperty(:public_url)
|
||||
|
||||
newproperty(:public_url) do
|
||||
end
|
||||
newproperty(:internal_url)
|
||||
|
||||
newproperty(:internal_url) do
|
||||
end
|
||||
|
||||
newproperty(:admin_url) do
|
||||
end
|
||||
newproperty(:admin_url)
|
||||
|
||||
# we should not do anything until the keystone service is started
|
||||
autorequire(:anchor) do
|
||||
@ -36,7 +45,54 @@ Puppet::Type.newtype(:keystone_endpoint) do
|
||||
end
|
||||
|
||||
autorequire(:keystone_service) do
|
||||
(region, service_name) = self[:name].split('/')
|
||||
[service_name]
|
||||
if parameter_set?(:type)
|
||||
"#{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
|
||||
|
@ -5,8 +5,13 @@ module PuppetX
|
||||
def self.included(klass)
|
||||
klass.class_eval do
|
||||
defaultto do
|
||||
custom = ''
|
||||
if respond_to?(:required_custom_message)
|
||||
custom = send(:required_custom_message)
|
||||
end
|
||||
fail(Puppet::ResourceError,
|
||||
"Parameter #{name} failed on " \
|
||||
"#{custom}" \
|
||||
"Parameter #{name} failed on " \
|
||||
"#{resource.class.to_s.split('::')[-1]}[#{resource.name}]: " \
|
||||
'Required parameter.')
|
||||
end
|
||||
|
@ -234,16 +234,49 @@ describe 'basic keystone server with resources' do
|
||||
end
|
||||
end
|
||||
end
|
||||
describe 'composite namevar for keystone_service' do
|
||||
|
||||
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
|
||||
|
@ -215,4 +215,48 @@ describe 'keystone server running with Apache/WSGI with resources' do
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
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
|
||||
|
@ -2,9 +2,7 @@ require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_endpoint/openstack'
|
||||
|
||||
provider_class = Puppet::Type.type(:keystone_endpoint).provider(:openstack)
|
||||
|
||||
describe provider_class do
|
||||
describe Puppet::Type.type(:keystone_endpoint).provider(:openstack) do
|
||||
|
||||
let(:set_env) do
|
||||
ENV['OS_USERNAME'] = 'test'
|
||||
@ -17,11 +15,11 @@ describe provider_class do
|
||||
|
||||
let(:endpoint_attrs) do
|
||||
{
|
||||
:name => 'region/endpoint',
|
||||
: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',
|
||||
:admin_url => 'http://127.0.0.1:5002'
|
||||
}
|
||||
end
|
||||
|
||||
@ -30,47 +28,79 @@ describe provider_class do
|
||||
end
|
||||
|
||||
let(:provider) do
|
||||
provider_class.new(resource)
|
||||
described_class.new(resource)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
set_env
|
||||
described_class.endpoints = nil
|
||||
described_class.services = nil
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
it 'creates an endpoint' do
|
||||
provider.class.expects(:openstack)
|
||||
.with('endpoint', 'create', '--format', 'shell', ['endpoint', 'admin', 'http://127.0.0.1:5002', '--region', 'region'])
|
||||
before(:each) do
|
||||
described_class.expects(:openstack)
|
||||
.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"
|
||||
id="endpoint1_id"
|
||||
region="region"
|
||||
')
|
||||
provider.class.expects(:openstack)
|
||||
.with('endpoint', 'create', '--format', 'shell', ['endpoint', 'internal', 'http://127.0.0.1:5001', '--region', 'region'])
|
||||
described_class.expects(:openstack)
|
||||
.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"
|
||||
id="endpoint2_id"
|
||||
region="region"
|
||||
')
|
||||
provider.class.expects(:openstack)
|
||||
.with('endpoint', 'create', '--format', 'shell', ['endpoint', 'public', 'http://127.0.0.1:5000', '--region', 'region'])
|
||||
described_class.expects(:openstack)
|
||||
.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"
|
||||
id="endpoint3_id"
|
||||
region="region"
|
||||
')
|
||||
provider.create
|
||||
expect(provider.exists?).to be_truthy
|
||||
expect(provider.id).to eq('endpoint1_id,endpoint2_id,endpoint3_id')
|
||||
described_class.expects(:openstack)
|
||||
.with('service', 'list', '--quiet', '--format', 'csv', [])
|
||||
.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
|
||||
|
||||
describe '#destroy' do
|
||||
it 'destroys an endpoint' do
|
||||
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')
|
||||
provider.class.expects(:openstack)
|
||||
described_class.expects(:openstack)
|
||||
.with('endpoint', 'delete', 'endpoint2_id')
|
||||
provider.class.expects(:openstack)
|
||||
described_class.expects(:openstack)
|
||||
.with('endpoint', 'delete', 'endpoint3_id')
|
||||
provider.destroy
|
||||
expect(provider.exists?).to be_falsey
|
||||
@ -80,7 +110,7 @@ region="region"
|
||||
describe '#exists' do
|
||||
context 'when tenant does not exist' do
|
||||
subject(:response) do
|
||||
response = provider.exists?
|
||||
provider.exists?
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
@ -89,16 +119,130 @@ region="region"
|
||||
|
||||
describe '#instances' do
|
||||
it 'finds every tenant' do
|
||||
provider.class.expects(:openstack)
|
||||
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"
|
||||
')
|
||||
instances = Puppet::Type::Keystone_endpoint::ProviderOpenstack.instances
|
||||
instances = described_class.instances
|
||||
expect(instances.count).to eq(1)
|
||||
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
|
||||
|
@ -1,9 +1,60 @@
|
||||
require 'spec_helper'
|
||||
require 'puppet'
|
||||
require 'puppet/type/keystone_endpoint'
|
||||
|
||||
describe Puppet::Type.type(:keystone_endpoint) do
|
||||
|
||||
it 'should fail when the namevar does not contain a region' do
|
||||
expect do
|
||||
Puppet::Type.type(:keystone_endpoint).new(:name => 'foo')
|
||||
end.to raise_error(Puppet::Error, /Invalid value/)
|
||||
describe 'region_one/endpoint_name::type_one' do
|
||||
include_examples 'parse title correctly',
|
||||
:name => 'endpoint_name',
|
||||
:region => 'region_one',
|
||||
:type => 'type_one'
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user