
The code matching the existing endpoints did not take the region into account. This was giving random results and messing up the catalog badly. This code fix it this and add associated rspec checks. Closes-Bug: #1535939 Change-Id: If1cdf30c37194b3a7b08bf85860cf7fb7266f6e1
224 lines
6.1 KiB
Ruby
224 lines
6.1 KiB
Ruby
require 'puppet/provider/keystone'
|
|
|
|
Puppet::Type.type(:keystone_endpoint).provide(
|
|
:openstack,
|
|
:parent => Puppet::Provider::Keystone
|
|
) do
|
|
|
|
desc "Provider to manage keystone endpoints."
|
|
|
|
include PuppetX::Keystone::CompositeNamevar::Helpers
|
|
|
|
@endpoints = nil
|
|
@services = nil
|
|
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
|
|
|
|
def initialize(value={})
|
|
super(value)
|
|
@property_flush = {}
|
|
end
|
|
|
|
def create
|
|
# 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]
|
|
created = true
|
|
ids << endpoint_create(name, region, scope.to_s.sub(/_url$/, ''),
|
|
resource[scope])[:id]
|
|
end
|
|
end
|
|
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
|
|
ids = @property_hash[:id].split(',')
|
|
ids.each do |id|
|
|
self.class.request('endpoint', 'delete', id)
|
|
end
|
|
@property_hash.clear
|
|
end
|
|
|
|
def exists?
|
|
@property_hash[:ensure] == :present
|
|
end
|
|
|
|
mk_resource_methods
|
|
|
|
def public_url=(value)
|
|
@property_flush[:public_url] = value
|
|
end
|
|
|
|
def internal_url=(value)
|
|
@property_flush[:internal_url] = value
|
|
end
|
|
|
|
def admin_url=(value)
|
|
@property_flush[:admin_url] = value
|
|
end
|
|
|
|
def region=(_)
|
|
fail(Puppet::Error, "Updating the endpoint's region is not currently supported.")
|
|
end
|
|
|
|
def self.instances
|
|
names = []
|
|
list = []
|
|
endpoints.each do |current|
|
|
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]) &&
|
|
(ep_osc[:service_type] == current[:service_type]) &&
|
|
(ep_osc[:region] == current[:region])
|
|
endpoint.merge!(ep_osc[:interface].to_sym => ep_osc)
|
|
end
|
|
end
|
|
list << endpoint
|
|
end
|
|
end
|
|
list.collect do |endpoint|
|
|
new(
|
|
:name => endpoint[:name],
|
|
:ensure => :present,
|
|
:id => "#{endpoint[:admin][:id]},#{endpoint[:internal][:id]},#{endpoint[:public][:id]}",
|
|
:region => endpoint[:admin][:region],
|
|
:admin_url => endpoint[:admin][:url],
|
|
:internal_url => endpoint[:internal][:url],
|
|
:public_url => endpoint[:public][:url]
|
|
)
|
|
end
|
|
end
|
|
|
|
def self.prefetch(resources)
|
|
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
|
|
|
|
def flush
|
|
if @property_flush && @property_hash[:id]
|
|
ids = @property_hash[:id].split(',')
|
|
if @property_flush[:admin_url]
|
|
self.class.request('endpoint', 'set', [ids[0], "--url=#{resource[:admin_url]}"])
|
|
end
|
|
if @property_flush[:internal_url]
|
|
self.class.request('endpoint', 'set', [ids[1], "--url=#{resource[:internal_url]}"])
|
|
end
|
|
if @property_flush[:public_url]
|
|
self.class.request('endpoint', 'set', [ids[2], "--url=#{resource[:public_url]}"])
|
|
end
|
|
end
|
|
@property_hash = resource.to_hash
|
|
end
|
|
|
|
private
|
|
|
|
def endpoint_create(name, region, interface, url)
|
|
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
|