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',
|
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