
Keystone v3 API no longer requires all the three endpoint types are created and some deployments may use only public endpoints (or public and internal endpoints). This looses the validation to allow such deployment architecture. Change-Id: I3873352dd3ea8556fbaa4ce3c558a912cc5f52e7
250 lines
7.0 KiB
Ruby
250 lines
7.0 KiB
Ruby
require File.join(File.dirname(__FILE__), '..','..','..', '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
|
|
|
|
attr_accessor :property_hash, :property_flush
|
|
|
|
@endpoints = nil
|
|
@services = nil
|
|
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
|
|
@do_not_manage = false
|
|
|
|
def initialize(value={})
|
|
super(value)
|
|
@property_flush = {}
|
|
end
|
|
|
|
def self.do_not_manage
|
|
@do_not_manage
|
|
end
|
|
|
|
def self.do_not_manage=(value)
|
|
@do_not_manage = value
|
|
end
|
|
|
|
def create
|
|
if self.class.do_not_manage
|
|
fail("Not managing Keystone_endpoint[#{@resource[:name]}] due to earlier Keystone API failures.")
|
|
end
|
|
name = resource[:name]
|
|
region = resource[:region]
|
|
type = resource[:type]
|
|
@property_hash[:type] = type
|
|
ids = []
|
|
s_id = service_id
|
|
created = false
|
|
[:admin_url, :internal_url, :public_url].each do |scope|
|
|
if resource[scope] and !resource[scope].empty?
|
|
created = true
|
|
ids << endpoint_create(s_id, 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
|
|
if self.class.do_not_manage
|
|
fail("Not managing Keystone_endpoint[#{@resource[:name]}] due to earlier Keystone API failures.")
|
|
end
|
|
ids = @property_hash[:id].split(',')
|
|
ids.each do |id|
|
|
self.class.system_request('endpoint', 'delete', id)
|
|
end
|
|
@property_hash.clear
|
|
end
|
|
|
|
def exists?
|
|
@property_hash[:ensure] == :present
|
|
end
|
|
|
|
mk_resource_methods
|
|
|
|
def public_url=(value)
|
|
if self.class.do_not_manage
|
|
fail("Not managing Keystone_endpoint[#{@resource[:name]}] due to earlier Keystone API failures.")
|
|
end
|
|
@property_flush[:public_url] = value
|
|
end
|
|
|
|
def internal_url=(value)
|
|
if self.class.do_not_manage
|
|
fail("Not managing Keystone_endpoint[#{@resource[:name]}] due to earlier Keystone API failures.")
|
|
end
|
|
@property_flush[:internal_url] = value
|
|
end
|
|
|
|
def admin_url=(value)
|
|
if self.class.do_not_manage
|
|
fail("Not managing Keystone_endpoint[#{@resource[:name]}] due to earlier Keystone API failures.")
|
|
end
|
|
@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 => make_id(endpoint),
|
|
:region => get_region(endpoint),
|
|
:admin_url => get_url(endpoint, :admin),
|
|
:internal_url => get_url(endpoint, :internal),
|
|
:public_url => get_url(endpoint, :public)
|
|
)
|
|
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]
|
|
scopes = [:admin_url, :internal_url, :public_url]
|
|
ids = Hash[scopes.zip(property_hash[:id].split(','))]
|
|
scopes.each do |scope|
|
|
if property_flush[scope] and !property_flush[scope].empty?
|
|
if ids[scope].nil? || ids[scope].empty?
|
|
ids[scope] = endpoint_create(service_id, resource[:region],
|
|
scope.to_s.sub(/_url$/, ''),
|
|
property_flush[scope])[:id]
|
|
else
|
|
self.class.system_request('endpoint',
|
|
'set',
|
|
[ids[scope], "--url=#{resource[scope]}"])
|
|
end
|
|
end
|
|
end
|
|
@property_hash = resource.to_hash
|
|
@property_hash[:id] = scopes.map { |s| ids[s] }.join(',')
|
|
@property_hash[:ensure] = :present
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def endpoint_create(name, region, interface, url)
|
|
properties = [name, interface, url, '--region', region]
|
|
self.class.system_request('endpoint', 'create', properties)
|
|
end
|
|
|
|
private
|
|
|
|
def self.endpoints
|
|
return @endpoints unless @endpoints.nil?
|
|
prev_do_not_manage = self.do_not_manage
|
|
self.do_not_manage = true
|
|
@endpoints = system_request('endpoint', 'list')
|
|
self.do_not_manage = prev_do_not_manage
|
|
@endpoints
|
|
end
|
|
|
|
def self.endpoints=(value)
|
|
@endpoints = value
|
|
end
|
|
|
|
def self.services
|
|
return @services unless @services.nil?
|
|
prev_do_not_manage = self.do_not_manage
|
|
self.do_not_manage = true
|
|
@services = system_request('service', 'list')
|
|
self.do_not_manage = prev_do_not_manage
|
|
@services
|
|
end
|
|
|
|
def self.services=(value)
|
|
@services = value
|
|
end
|
|
|
|
def self.transform_name(region, name, type)
|
|
"#{region}/#{name}::#{type}"
|
|
end
|
|
|
|
def self.make_id(endpoint)
|
|
id_str = ''
|
|
id_sep = ''
|
|
[:admin, :internal, :public].each do |type|
|
|
id_str += id_sep
|
|
id_str += endpoint[type][:id] if endpoint[type]
|
|
id_sep = ','
|
|
end
|
|
id_str
|
|
end
|
|
|
|
def self.get_region(endpoint)
|
|
type = [:admin, :internal, :public].detect { |t| endpoint.key? t }
|
|
type ? endpoint[type][:region] : ''
|
|
end
|
|
|
|
def self.get_url(endpoint, type, default='')
|
|
endpoint[type][:url] rescue default
|
|
end
|
|
|
|
def service_id
|
|
# Reset the cache.
|
|
self.class.services = nil
|
|
name = resource[:name]
|
|
type = resource[:type]
|
|
|
|
services = self.class.services.find_all { |s| s[:name] == name }
|
|
service = services.find { |s| s[:type] == type }
|
|
service_id = ''
|
|
if service.nil? && services.count == 1
|
|
# For backward compatibility, match the service by name only.
|
|
service_id = services[0][:id]
|
|
else
|
|
# Math the service by id.
|
|
service_id = service[:id] if service
|
|
end
|
|
if service_id.nil? || service_id.empty?
|
|
title = self.class.transform_name(resource[:region], resource[:name], resource[:type])
|
|
fail(Puppet::Error, "Cannot find service associated with #{title}")
|
|
end
|
|
|
|
service_id
|
|
end
|
|
end
|