Keystone_endpoint match service by name/type.
This enable keystone_endpoint to specify the type of the service matched. This way one can match services which are different only by type and not only by name, like services nova/compute and nova/computev3 for instance. It does so by fetching the _id_ of the service when it has the type information instead of just using the name. This should be required, and deprecation has been added, as the current code work only because of a convention. Change-Id: I9ea20fbad274d583485bc09a52b9df8000eb1af5 Closes-Bug: #1506996
This commit is contained in:
parent
4c6bd18b6a
commit
0a4e06abb0
28
README.md
28
README.md
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue