Fix endpoint update when one endpoint is missing.

Endpoint are created for admin, internal and public network by this
provider.  If only one of the endpoint is missing then all the endpoints
are recreated as puppet fails to match the resource with the remaining
endpoint.

This fix enable one to update the resource where update means "recreate
the missing endpoint".

Change-Id: Ic605725d1923680c6518ebadda36cb5d596c08fe
Closes-bug: 1559013
This commit is contained in:
Sofer Athlan-Guyot 2016-06-20 13:14:58 +02:00
parent a02d2aeec7
commit fe0edef97d
4 changed files with 142 additions and 33 deletions

View File

@ -9,6 +9,8 @@ Puppet::Type.type(:keystone_endpoint).provide(
include PuppetX::Keystone::CompositeNamevar::Helpers
attr_accessor :property_hash, :property_flush
@endpoints = nil
@services = nil
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
@ -31,30 +33,18 @@ Puppet::Type.type(:keystone_endpoint).provide(
if self.class.do_not_manage
fail("Not managing Keystone_endpoint[#{@resource[:name]}] due to earlier Keystone API failures.")
end
# 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 = []
s_id = service_id
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$/, ''),
ids << endpoint_create(s_id, region, scope.to_s.sub(/_url$/, ''),
resource[scope])[:id]
end
end
@ -134,11 +124,11 @@ Puppet::Type.type(:keystone_endpoint).provide(
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]
: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
@ -153,19 +143,27 @@ Puppet::Type.type(:keystone_endpoint).provide(
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]}"])
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]
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.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
@property_hash = resource.to_hash
end
private
@ -252,4 +250,47 @@ Puppet::Type.type(:keystone_endpoint).provide(
"#{region}/#{name}::#{type}"
end
end
def self.make_id(endpoint)
id_str = ''
id_sep = ''
[:admin, :internal, :public].each do |type|
id_str += "#{id_sep}#{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 comptatibility, 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

View File

@ -0,0 +1,6 @@
---
fixes:
- Fixes `bug 1559013
<https://bugs.launchpad.net/puppet-keystone/+bug/1559013>`__ so
update of a keystone_endpoint does not recreate all endpoints when
one or two network endpoint are missing.

View File

@ -233,9 +233,9 @@ describe 'keystone server running with Apache/WSGI with resources' do
ensure => present,
region => 'RegionOne',
type => 'type_1',
public_url => 'http://public_url/',
internal_url => 'http://public_url/',
admin_url => 'http://public_url/'
public_url => 'http://public_service1_type1/',
internal_url => 'http://internal_service1_type1/',
admin_url => 'http://admin_service1_type1/'
}
EOM
end

View File

@ -326,5 +326,67 @@ region="region"
end
end
end
describe '#flush' do
let(:endpoint_attrs) do
{
:title => 'region/service_1',
: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:4999',
:type => 'service_type1'
}
end
context '#update a missing endpoint' do
it 'creates an endpoint' do
described_class.expects(:openstack)
.with('endpoint', 'create', '--format', 'shell',
['service_id_1', 'admin', 'http://127.0.0.1:4999',
'--region', 'region'])
.returns(<<-eoo
enabled="True"
id="endpoint1_id"
interface="internal"
region="None"
region_id="None"
service_id="service_id_1"
service_name="service_1"
service_type="service_type1"
url="http://127.0.0.1:5001"
eoo
)
provider.expects(:property_flush)
.times(5)
.returns({:admin_url => 'http://127.0.0.1:4999'})
provider.expects(:property_hash)
.twice
.returns({:id => ',endpoint2_id,endpoint3_id'})
provider.expects(:service_id)
.returns('service_id_1')
provider.flush
expect(provider.exists?).to be_truthy
expect(provider.id).to eq('endpoint1_id,endpoint2_id,endpoint3_id')
end
end
context 'adjust a url' do
it 'update the url' do
described_class.expects(:openstack)
.with('endpoint', 'set',
['endpoint1_id', '--url=http://127.0.0.1:4999'])
provider.expects(:property_flush)
.times(4)
.returns({:admin_url => 'http://127.0.0.1:4999'})
provider.expects(:property_hash)
.twice
.returns({:id => 'endpoint1_id,endpoint2_id,endpoint3_id'})
provider.flush
expect(provider.exists?).to be_truthy
expect(provider.id).to eq('endpoint1_id,endpoint2_id,endpoint3_id')
end
end
end
end
end