diff --git a/lib/facter/current_config_hosts.rb b/lib/facter/current_config_hosts.rb new file mode 100644 index 000000000..aee13e4b3 --- /dev/null +++ b/lib/facter/current_config_hosts.rb @@ -0,0 +1,64 @@ +def get_auth(component) + provider = Object.const_get "Puppet::Provider::#{component.capitalize}" + auth_func = "#{component}_credentials" + if provider.respond_to?(auth_func) + begin + q = provider.send(auth_func) + rescue Puppet::Error + q = {} + end + authenv = { + 'OS_AUTH_URL' => q['auth_url'], + 'OS_USERNAME' => q['username'], + 'OS_PROJECT_NAME' => q['project_name'], + 'OS_PASSWORD' => q['password'] + } + if q.key?('region_name') + authenv['OS_REGION_NAME'] = q['region_name'] + end + authenv + end +end + +def get_live_value_from_auth(component) + # The path is correct for this tripleo version. + provider_file = "/etc/puppet/modules/#{component}/lib/puppet/provider/#{component}.rb" + if File.exists?(provider_file) + require_relative(provider_file) + auth_env = get_auth(component) + host = if auth_env + Facter::Core::Execution.with_env(auth_env) do + # We want to find if the current host value is the fqdn + # or the hostname. We are sure that it will be at + # least the hostname so the grep will work. + Facter::Core::Execution.execute( + "#{component} agent-list -c host -f value 2>/dev/null | grep #{Facter.value(:hostname)} 2>/dev/null", + {:on_fail => ''} + ).split("\n").first + end + end + host || '' + end +end + +def get_nova_live_value + Tempfile.open('get-nova-host') do |nova_stdin| + File.open(nova_stdin, 'w') do |nova_cmd| + nova_cmd.puts("import nova.conf\nprint nova.conf.CONF.host") + end + Facter::Core::Execution.execute("nova-manage shell python 2>/dev/null < #{nova_stdin} | sed -e 's/^[> ]*//'") + end +end + +['nova', 'neutron'].each do |component| + Facter.add("current_#{component}_host") do + confine kernel: 'Linux' + setcode do + if component == 'nova' + get_nova_live_value.strip + else + get_live_value_from_auth(component).strip + end + end + end +end diff --git a/manifests/profile/base/neutron.pp b/manifests/profile/base/neutron.pp index 993028f8d..002f2b870 100644 --- a/manifests/profile/base/neutron.pp +++ b/manifests/profile/base/neutron.pp @@ -63,8 +63,25 @@ class tripleo::profile::base::neutron ( elsif $dhcp_agent_count > 0 { $dhcp_agents_per_net = $dhcp_agent_count } + if hiera('stack_action', undef) == 'UPDATE' { + if !empty($::current_neutron_host) { + $host_real = $::current_neutron_host + } + # Try nova value as we could be on a compute node without all + # the necessary neutron definition. The host value will be identical. + elsif !empty($::current_nova_host) { + $host_real = $::current_nova_host + } else { + # We fail instead of blindly changing that value as it can + # break the overcloud. + fail("We couldn't get the live value of the neutron agent, please contact support.") + } + } else { + $host_real = hiera('neutron::host') + } class { '::neutron' : + host => $host_real, rabbit_hosts => $rabbit_endpoints, dhcp_agents_per_network => $dhcp_agents_per_net, } diff --git a/manifests/profile/base/nova.pp b/manifests/profile/base/nova.pp index 84ba604fc..37eed298e 100644 --- a/manifests/profile/base/nova.pp +++ b/manifests/profile/base/nova.pp @@ -89,8 +89,23 @@ class tripleo::profile::base::nova ( $migration_ssh_localaddrs_real = unique($migration_ssh_localaddrs) if $step >= 4 or ($step >= 3 and $sync_db) { + + if hiera('stack_action', undef) == 'UPDATE' { + if empty($::current_nova_host) { + # We fail instead of blindly changing that value as it can + # break the overcloud. + fail("We couldn't get the live value of the nova agent, please contact support.") + } else { + $host_real = $::current_nova_host + } + } else { + $host_real = hiera('nova::host') + } + + $rabbit_endpoints = suffix(any2array(normalize_ip_for_uri($rabbit_hosts)), ":${rabbit_port}") class { '::nova' : + host => $host_real, rabbit_hosts => $rabbit_endpoints, } include ::nova::config diff --git a/spec/classes/tripleo_profile_base_neutron_spec.rb b/spec/classes/tripleo_profile_base_neutron_spec.rb new file mode 100644 index 000000000..dbdb80853 --- /dev/null +++ b/spec/classes/tripleo_profile_base_neutron_spec.rb @@ -0,0 +1,78 @@ +# +# Copyright (C) 2017 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +require 'spec_helper' + +describe 'tripleo::profile::base::neutron' do + let :params do + { :step => 5} + end + + shared_examples_for 'tripleo::profile::base::neutron' do + before :each do + facts.merge!({ :step => params[:step] }) + end + + context "during deployment" do + let(:facts) { super().merge({:current_neutron_host => ''})} + it 'should set neutron::host to fqdn_canonical' do + is_expected.to contain_class('neutron').with(:host => 'node.example.com') + end + end + + context 'during upgrade' do + let(:facts) { super().merge({:heat_stack_action => '_update'})} + context 'when current host is different from fqdn' do + let(:facts) { super().merge({:current_neutron_host => 'node'})} + it "should use the current_host" do + is_expected.to contain_class('neutron').with( + :host => 'node', + ) + end + end + context 'when current neutron host cannot be found but nova host can' do + let(:facts) { super().merge({:current_neutron_host => '', + :current_nova_host => 'node'})} + it "should use the current_nova_host" do + is_expected.to contain_class('neutron').with( + :host => 'node', + ) + end + end + context 'when both nova and neutron current host cannot be found' do + let(:facts) { super().merge({:current_neutron_host => '', + :current_nova_host => '', + })} + it "fails" do + is_expected.to compile.and_raise_error(/live value of the neutron/) + end + end + end + end + + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) do + facts.merge({ + :hostname => 'node.example.com', + :current_neutron_host => 'node.example.com' + }) + end + + it_behaves_like 'tripleo::profile::base::neutron' + end + end +end diff --git a/spec/classes/tripleo_profile_base_nova_spec.rb b/spec/classes/tripleo_profile_base_nova_spec.rb index 15b82eb48..581c8abf6 100644 --- a/spec/classes/tripleo_profile_base_nova_spec.rb +++ b/spec/classes/tripleo_profile_base_nova_spec.rb @@ -43,6 +43,7 @@ describe 'tripleo::profile::base::nova' do it { is_expected.to contain_class('tripleo::profile::base::nova') is_expected.to contain_class('nova').with( + :host => 'node.example.com', :rabbit_hosts => ['127.0.0.1:5672'] ) @@ -496,13 +497,35 @@ describe 'tripleo::profile::base::nova' do } end + context 'during upgrade' do + let(:params) { { + :step => 4, + } } + let(:facts) { super().merge({:heat_stack_action => '_update'})} + + context 'when current nova host is different from fqdn' do + let(:facts) { super().merge({:current_nova_host => 'node'})} + it "should use the current_host" do + is_expected.to contain_class('nova').with( + :host => 'node', + ) + end + end + context 'when current nova host cannot be found' do + let(:facts) { super().merge({:current_nova_host => ''})} + it "fails" do + is_expected.to compile.and_raise_error(/live value of the nova/) + end + end + end + end on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do - facts.merge({ :hostname => 'node.example.com' }) + facts.merge({:hostname => 'node.example.com'}) end it_behaves_like 'tripleo::profile::base::nova' diff --git a/spec/fixtures/hiera.yaml b/spec/fixtures/hiera.yaml index 1dc3360cb..5c0c40ed3 100644 --- a/spec/fixtures/hiera.yaml +++ b/spec/fixtures/hiera.yaml @@ -5,3 +5,4 @@ :datadir: './spec/fixtures/hieradata' :hierarchy: - default + - 'host_param%{::heat_stack_action}' diff --git a/spec/fixtures/hieradata/host_param.yaml b/spec/fixtures/hieradata/host_param.yaml new file mode 100644 index 000000000..cd0b00afc --- /dev/null +++ b/spec/fixtures/hieradata/host_param.yaml @@ -0,0 +1,3 @@ +--- +neutron::host: 'node.example.com' +nova::host: 'node.example.com' diff --git a/spec/fixtures/hieradata/host_param_update.yaml b/spec/fixtures/hieradata/host_param_update.yaml new file mode 100644 index 000000000..ba1fa4b23 --- /dev/null +++ b/spec/fixtures/hieradata/host_param_update.yaml @@ -0,0 +1,4 @@ +--- +stack_action: 'UPDATE' +neutron::host: 'node.example.com' +nova::host: 'node.example.com'