Add ability to specify IP for service

The problem that this change addresses is that the address_for method
will not work correctly if there are multiple IP address associated
with the specified interface.

The approach to solving this problem and moving towards the overall
goal of having one place where service networking information is
stored is to convert address_for calls into endpoints, and add a
address() method to the endpoints interface for IP address resolution.

The address() method has the following behavior: if the
bind_interface of an endpoint is set, then the IP is looked up on
the interface.  Otherwise, the IP specified in the host attribute is
returned.  This allows the caller to choose either method of
determining what IP a service will be bound to.

This initial change switches both the openstack-ops-database and
openstack-ops-messaging cookbooks over to use endpoints instead of
address_for.  The other cookbooks will be switched over time.

blueprint increase-ip-binding-flexibility

Change-Id: I527e4e734f3c1eea9ac2567e0a90524d78ee867e
This commit is contained in:
Chris Dearborn 2014-02-18 14:35:20 -05:00
parent 5989edff5f
commit f6da45d11f
8 changed files with 101 additions and 40 deletions

View File

@ -70,39 +70,49 @@
# across many zones.
#
# ******************** Database Endpoint **************************************
default['openstack']['endpoints']['db']['host'] = '127.0.0.1'
default['openstack']['endpoints']['db']['scheme'] = nil
default['openstack']['endpoints']['db']['port'] = '3306'
default['openstack']['endpoints']['db']['path'] = nil
default['openstack']['endpoints']['db']['bind_interface'] = nil
# Default database attributes
default['openstack']['db']['server_role'] = 'os-ops-database'
default['openstack']['db']['service_type'] = 'mysql'
default['openstack']['db']['host'] = '127.0.0.1'
default['openstack']['db']['port'] = '3306'
# Note that the openstack:db:host and openstack:db:port attributes are being
# deprecated in favor of the db endpoint and will be removed in a future
# patch set.
default['openstack']['db']['host'] = default['openstack']['endpoints']['db']['host']
default['openstack']['db']['port'] = default['openstack']['endpoints']['db']['port']
# Database used by the OpenStack Compute (Nova) service
default['openstack']['db']['compute']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['compute']['host'] = node['openstack']['db']['host']
default['openstack']['db']['compute']['port'] = node['openstack']['db']['port']
default['openstack']['db']['compute']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['compute']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['compute']['db_name'] = 'nova'
default['openstack']['db']['compute']['username'] = 'nova'
# Database used by the OpenStack Identity (Keystone) service
default['openstack']['db']['identity']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['identity']['host'] = node['openstack']['db']['host']
default['openstack']['db']['identity']['port'] = node['openstack']['db']['port']
default['openstack']['db']['identity']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['identity']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['identity']['db_name'] = 'keystone'
default['openstack']['db']['identity']['username'] = 'keystone'
default['openstack']['db']['identity']['migrate'] = true
# Database used by the OpenStack Image (Glance) service
default['openstack']['db']['image']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['image']['host'] = node['openstack']['db']['host']
default['openstack']['db']['image']['port'] = node['openstack']['db']['port']
default['openstack']['db']['image']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['image']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['image']['db_name'] = 'glance'
default['openstack']['db']['image']['username'] = 'glance'
default['openstack']['db']['image']['migrate'] = true
# Database used by the OpenStack Network (Neutron) service
default['openstack']['db']['network']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['network']['host'] = node['openstack']['db']['host']
default['openstack']['db']['network']['port'] = node['openstack']['db']['port']
default['openstack']['db']['network']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['network']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['network']['db_name'] = 'neutron'
default['openstack']['db']['network']['username'] = 'neutron'
# The SQLAlchemy connection string used to connect to the slave database
@ -129,23 +139,23 @@ default['openstack']['db']['network']['pool_timeout'] = 10
# Database used by the OpenStack Block Storage (Cinder) service
default['openstack']['db']['block-storage']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['block-storage']['host'] = node['openstack']['db']['host']
default['openstack']['db']['block-storage']['port'] = node['openstack']['db']['port']
default['openstack']['db']['block-storage']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['block-storage']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['block-storage']['db_name'] = 'cinder'
default['openstack']['db']['block-storage']['username'] = 'cinder'
# Database used by the OpenStack Dashboard (Horizon)
default['openstack']['db']['dashboard']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['dashboard']['host'] = node['openstack']['db']['host']
default['openstack']['db']['dashboard']['port'] = node['openstack']['db']['port']
default['openstack']['db']['dashboard']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['dashboard']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['dashboard']['db_name'] = 'horizon'
default['openstack']['db']['dashboard']['username'] = 'dash'
default['openstack']['db']['dashboard']['migrate'] = true
# Database used by OpenStack Metering (Ceilometer)
default['openstack']['db']['metering']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['metering']['host'] = node['openstack']['db']['host']
default['openstack']['db']['metering']['port'] = node['openstack']['db']['port']
default['openstack']['db']['metering']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['metering']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['metering']['db_name'] = 'ceilometer'
default['openstack']['db']['metering']['username'] = 'ceilometer'
default['openstack']['db']['metering']['nosql']['used'] = false
@ -153,8 +163,8 @@ default['openstack']['db']['metering']['nosql']['port'] = '27017'
# Database used by OpenStack Orchestration (Heat)
default['openstack']['db']['orchestration']['service_type'] = node['openstack']['db']['service_type']
default['openstack']['db']['orchestration']['host'] = node['openstack']['db']['host']
default['openstack']['db']['orchestration']['port'] = node['openstack']['db']['port']
default['openstack']['db']['orchestration']['host'] = node['openstack']['endpoints']['db']['host']
default['openstack']['db']['orchestration']['port'] = node['openstack']['endpoints']['db']['port']
default['openstack']['db']['orchestration']['db_name'] = 'heat'
default['openstack']['db']['orchestration']['username'] = 'heat'

View File

@ -24,6 +24,13 @@
# expected to create the user, pass, vhost in a wrapper rabbitmq cookbook.
#
# ******************** RabbitMQ Endpoint **************************************
default['openstack']['endpoints']['mq']['host'] = '127.0.0.1'
default['openstack']['endpoints']['mq']['scheme'] = nil
default['openstack']['endpoints']['mq']['port'] = '5672'
default['openstack']['endpoints']['mq']['path'] = nil
default['openstack']['endpoints']['mq']['bind_interface'] = nil
###################################################################
# Services to assign mq attributes for
###################################################################
@ -34,8 +41,11 @@ services = %w{block-storage compute image metering network orchestration}
###################################################################
default['openstack']['mq']['server_role'] = 'os-ops-messaging'
default['openstack']['mq']['service_type'] = 'rabbitmq'
default['openstack']['mq']['host'] = '127.0.0.1'
default['openstack']['mq']['port'] = '5672'
# Note that the openstack:mq:host and openstack:mq:port attributes are being
# deprecated in favor of the mq endpoint and will be removed in a future
# patch set.
default['openstack']['mq']['host'] = default['openstack']['endpoints']['mq']['host']
default['openstack']['mq']['port'] = default['openstack']['endpoints']['mq']['port']
default['openstack']['mq']['user'] = 'guest'
default['openstack']['mq']['vhost'] = '/'
@ -55,16 +65,16 @@ qpid_defaults = {
heartbeat: 60,
protocol: 'tcp',
tcp_nodelay: true,
host: node['openstack']['mq']['host'],
port: node['openstack']['mq']['port'],
qpid_hosts: ["#{node['openstack']['mq']['host']}:#{node['openstack']['mq']['port']}"]
host: node['openstack']['endpoints']['mq']['host'],
port: node['openstack']['endpoints']['mq']['port'],
qpid_hosts: ["#{node['openstack']['endpoints']['mq']['host']}:#{node['openstack']['endpoints']['mq']['port']}"]
}
rabbit_defaults = {
userid: node['openstack']['mq']['user'],
vhost: node['openstack']['mq']['vhost'],
port: node['openstack']['mq']['port'],
host: node['openstack']['mq']['host'],
port: node['openstack']['endpoints']['mq']['port'],
host: node['openstack']['endpoints']['mq']['host'],
ha: false,
use_ssl: false
}

View File

@ -88,6 +88,20 @@ module ::Openstack # rubocop:disable Documentation
end
end
# Return the IPv4 address for the hash.
#
# If the bind_interface is set, then return the first IP on the interface.
# otherwise return the IP specified in the host attribute.
def address(hash)
bind_interface = hash['bind_interface'] if hash['bind_interface']
if bind_interface
return address_for bind_interface
else
return hash['host']
end
end
private
# Instead of specifying the verbose node['openstack']['endpoints'][name],

View File

@ -70,7 +70,7 @@ module ::Openstack # rubocop:disable Documentation
def rabbit_servers # rubocop:disable MethodLength
if node['openstack']['mq']['servers']
servers = node['openstack']['mq']['servers']
port = node['openstack']['mq']['port']
port = node['openstack']['endpoints']['mq']['port']
servers.map { |s| "#{s}:#{port}" }.join ','
else
@ -80,7 +80,7 @@ module ::Openstack # rubocop:disable Documentation
# in the wrapper cookbook. See the reference cookbook
# openstack-ops-messaging.
address = n['openstack']['mq']['listen']
port = n['openstack']['mq']['port']
port = n['openstack']['endpoints']['mq']['port']
"#{address}:#{port}"
end.sort.join ','

View File

@ -24,19 +24,23 @@ require 'uri'
module ::Openstack # rubocop:disable Documentation
# Returns a uri::URI from a hash. If the hash has a 'uri' key, the value
# of that is returned. If not, then the routine attempts to construct
# the URI from other parts of the hash, notably looking for keys of
# 'host', 'port', 'scheme', and 'path' to construct the URI.
# the URI from other parts of the hash. The values of the 'port' and 'path'
# keys are used directly from the hash. For the host, if the
# 'bind_interface' key is non-nil then it will use the first IP address on
# the specified interface, otherwise it will use the value of the 'host' key
# from the hash.
#
# Returns nil if neither 'uri' or 'host' keys exist in the supplied
# hash.
# Returns nil if the 'uri' key does not exist in the supplied hash and if
# the determined host is nil (both the values of the 'bind_interface' and
# 'host' keys are nil).
def uri_from_hash(hash)
if hash['uri']
::URI.parse hash['uri']
else
return nil unless hash['host']
host = address hash
return nil unless host
scheme = hash['scheme'] ? hash['scheme'] : 'http'
host = hash['host']
port = hash['port'] # Returns nil if missing, which is fine.
path = hash['path'] # Returns nil if missing, which is fine.
::URI::Generic.new scheme, nil, host, port, nil, path, nil, nil, nil

View File

@ -25,7 +25,7 @@ end
# iterate over the endpoints, look for bind_interface to set the host
node['openstack']['endpoints'].keys.each do |component|
unless node['openstack']['endpoints'][component]['bind_interface'].nil?
ip_address = address_for node['openstack']['endpoints'][component]['bind_interface']
ip_address = address node['openstack']['endpoints'][component]
node.default['openstack']['endpoints'][component]['host'] = ip_address
end
end

View File

@ -183,5 +183,28 @@ describe 'openstack-common::set_endpoints_by_interface' do
).to eq(expected)
end
end
describe '#address' do
it 'returns interface IP if bind_interface specified' do
ep_hash = {
'bind_interface' => 'eth0',
'host' => '5.6.7.8'
}
subject.stub('address_for').and_return('1.2.3.4')
expect(
subject.address(ep_hash)
).to eq('1.2.3.4')
end
it 'returns host IP if bind_interface not specified' do
ep_hash = {
'bind_interface' => nil,
'host' => '5.6.7.8'
}
subject.stub('address_for').and_return('1.2.3.4')
expect(
subject.address(ep_hash)
).to eq('5.6.7.8')
end
end
end
end

View File

@ -8,7 +8,7 @@ describe 'openstack-common::default' do
let(:node) { runner.node }
let(:chef_run) do
node.set['openstack']['mq']['server_role'] = 'openstack-ops-mq'
node.set['openstack']['mq']['port'] = 5672
node.set['openstack']['endpoints']['mq']['port'] = 5672
runner.converge(described_recipe)
end
@ -103,8 +103,8 @@ describe 'openstack-common::default' do
describe '#rabbit_servers' do
it 'returns rabbit servers' do
nodes = [
{ 'openstack' => { 'mq' => { 'listen' => '1.1.1.1', 'port' => '5672' } } },
{ 'openstack' => { 'mq' => { 'listen' => '2.2.2.2', 'port' => '5672' } } }
{ 'openstack' => { 'mq' => { 'listen' => '1.1.1.1' }, 'endpoints' => { 'mq' => { 'port' => '5672' } } } },
{ 'openstack' => { 'mq' => { 'listen' => '2.2.2.2' }, 'endpoints' => { 'mq' => { 'port' => '5672' } } } }
]
subject.stub(:node).and_return(chef_run.node)
subject.stub(:search_for)
@ -115,9 +115,9 @@ describe 'openstack-common::default' do
it 'returns sorted rabbit servers' do
nodes = [
{ 'openstack' => { 'mq' => { 'listen' => '3.3.3.3', 'port' => '5672' } } },
{ 'openstack' => { 'mq' => { 'listen' => '1.1.1.1', 'port' => '5672' } } },
{ 'openstack' => { 'mq' => { 'listen' => '2.2.2.2', 'port' => '5672' } } }
{ 'openstack' => { 'mq' => { 'listen' => '3.3.3.3' }, 'endpoints' => { 'mq' => { 'port' => '5672' } } } },
{ 'openstack' => { 'mq' => { 'listen' => '1.1.1.1' }, 'endpoints' => { 'mq' => { 'port' => '5672' } } } },
{ 'openstack' => { 'mq' => { 'listen' => '2.2.2.2' }, 'endpoints' => { 'mq' => { 'port' => '5672' } } } }
]
subject.stub(:node).and_return(chef_run.node)
subject.stub(:search_for)