diff --git a/lib/puppet/provider/neutron_bgp_dragent_config/openstackconfig.rb b/lib/puppet/provider/neutron_bgp_dragent_config/openstackconfig.rb new file mode 100644 index 000000000..02aa6b32b --- /dev/null +++ b/lib/puppet/provider/neutron_bgp_dragent_config/openstackconfig.rb @@ -0,0 +1,15 @@ +Puppet::Type.type(:neutron_bgp_dragent_config).provide( + :openstackconfig, + :parent => Puppet::Type.type(:openstack_config).provider(:ruby) +) do + + def self.file_path + '/etc/neutron/bgp_dragent.ini' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/lib/puppet/type/neutron_bgp_dragent_config.rb b/lib/puppet/type/neutron_bgp_dragent_config.rb new file mode 100644 index 000000000..058e93420 --- /dev/null +++ b/lib/puppet/type/neutron_bgp_dragent_config.rb @@ -0,0 +1,28 @@ +Puppet::Type.newtype(:neutron_bgp_dragent_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage in bgp dragent config.' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + + newparam(:ensure_absent_val) do + desc 'A value that is specified as the value property will behave as if ensure => absent was specified' + defaultto('') + end + + autorequire(:package) do + ['neutron-dynamic-routing', 'neutron-bgp-dragent'] + end + +end diff --git a/manifests/agents/bgp_dragent.pp b/manifests/agents/bgp_dragent.pp new file mode 100644 index 000000000..92f13465f --- /dev/null +++ b/manifests/agents/bgp_dragent.pp @@ -0,0 +1,98 @@ +# +# Copyright (C) 2018 Binero AB. +# +# Author: Tobias Urdin +# +# 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. +# +# == Class: neutron::agents::bgp_dragent +# +# Install and configure neutron BGP dragent from Neutron Dynamic Routing. +# +# === Parameters: +# +# [*package_ensure*] +# (Optional) The state of the package. +# Defaults to 'present' +# +# [*enabled*] +# (Optional) The state of the service. +# Defaults to true +# +# [*manage_service*] +# (Optional) Whether to start/stop the service. +# Defaults to true +# +# [*bgp_speaker_driver*] +# (Optional) The BGP speaker driver to use. +# Defaults to 'neutron_dynamic_routing.services.bgp.agent.driver.ryu.driver.RyuBgpDriver' +# +# [*bgp_router_id*] +# (Optional) The BGP router ID. +# Defaults to $::ipaddress +# +# [*purge_config*] +# (Optional) Whether to set only the specified config options in the BGP dragent config. +# Defaults to false. +# +class neutron::agents::bgp_dragent( + $package_ensure = 'present', + $enabled = true, + $manage_service = true, + $bgp_speaker_driver = 'neutron_dynamic_routing.services.bgp.agent.driver.ryu.driver.RyuBgpDriver', + $bgp_router_id = $::ipaddress, + $purge_config = false, +) { + + include ::neutron::deps + include ::neutron::params + + resources { 'neutron_bgp_dragent_config': + purge => $purge_config, + } + + neutron_bgp_dragent_config { + 'BGP/bgp_speaker_driver': value => $bgp_speaker_driver; + 'BGP/bgp_router_id': value => $bgp_router_id; + } + + if $::neutron::params::dynamic_routing_package { + ensure_packages('neutron-dynamic-routing', { + ensure => $package_ensure, + name => $::neutron::params::dynamic_routing_package, + tag => ['openstack', 'neutron-package'], + }) + } + + if $::neutron::params::bgp_dragent_package { + ensure_packages('neutron-bgp-dragent', { + ensure => $package_ensure, + name => $::neutron::params::bgp_dragent_package, + tag => ['openstack', 'neutron-package'], + }) + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + service { 'neutron-bgp-dragent': + ensure => $service_ensure, + name => $::neutron::params::bgp_dragent_service, + enable => $enabled, + tag => 'neutron-service', + } + } +} diff --git a/manifests/config.pp b/manifests/config.pp index 97e320b98..6a35d526d 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -63,6 +63,9 @@ # [*vpnaas_agent_config*] # (optional) Manage configuration of vpn_agent.ini # +# [*bgp_dragent_config*] +# (optional) Manage configuration of bgp_dragent.ini +# # [*plugin_linuxbridge_config*] # (optional) Manage configuration of linuxbridge_conf.ini # @@ -114,6 +117,7 @@ class neutron::config ( $ovn_metadata_agent_config = {}, $metering_agent_config = {}, $vpnaas_agent_config = {}, + $bgp_dragent_config = {}, $plugin_linuxbridge_config = {}, $plugin_cisco_db_conn_config = {}, $plugin_cisco_l2network_config = {}, @@ -143,6 +147,7 @@ class neutron::config ( validate_hash($ovn_metadata_agent_config) validate_hash($metering_agent_config) validate_hash($vpnaas_agent_config) + validate_hash($bgp_dragent_config) validate_hash($plugin_linuxbridge_config) validate_hash($plugin_cisco_db_conn_config) validate_hash($plugin_cisco_l2network_config) @@ -167,6 +172,7 @@ class neutron::config ( create_resources('neutron_metadata_agent_config', $metadata_agent_config) create_resources('neutron_metering_agent_config', $metering_agent_config) create_resources('neutron_vpnaas_agent_config', $vpnaas_agent_config) + create_resources('neutron_bgp_dragent_config', $bgp_dragent_config) create_resources('neutron_plugin_linuxbridge', $plugin_linuxbridge_config) create_resources('neutron_plugin_cisco_db_conn', $plugin_cisco_db_conn_config) create_resources('neutron_plugin_cisco_l2network', $plugin_cisco_l2network_config) diff --git a/manifests/deps.pp b/manifests/deps.pp index e6378b8d8..f6cc92a6a 100644 --- a/manifests/deps.pp +++ b/manifests/deps.pp @@ -50,6 +50,7 @@ class neutron::deps { Anchor['neutron::config::begin'] -> Neutron_lbaas_service_config<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_metadata_agent_config<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_metering_agent_config<||> ~> Anchor['neutron::config::end'] + Anchor['neutron::config::begin'] -> Neutron_bgp_dragent_config<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_plugin_cisco_credentials<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_plugin_cisco_db_conn<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_plugin_cisco<||> ~> Anchor['neutron::config::end'] diff --git a/manifests/params.pp b/manifests/params.pp index c41090086..3e42761e4 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -34,6 +34,7 @@ class neutron::params { $l3_agent_service = 'neutron-l3-agent' $metadata_agent_service = 'neutron-metadata-agent' $ovn_metadata_agent_service = 'networking-ovn-metadata-agent' + $bgp_dragent_service = 'neutron-bgp-dragent' $bagpipe_bgp_package = 'openstack-bagpipe-bgp' $bgpvpn_bagpipe_package = "python${pyvers}-networking-bagpipe" $bgpvpn_bagpipe_service = 'bagpipe-bgp' @@ -76,6 +77,8 @@ class neutron::params { $l2gw_agent_package = 'openstack-neutron-l2gw-agent' $l2gw_package = 'python2-networking-l2gw' $ovn_metadata_agent_package = 'python-networking-ovn-metadata-agent' + $dynamic_routing_package = 'openstack-neutron-dynamic-routing' + $bgp_dragent_package = false if $::operatingsystemrelease =~ /^7.*/ or $::operatingsystem == 'Fedora' { $openswan_package = 'libreswan' } else { @@ -100,6 +103,7 @@ class neutron::params { $api_service_name = 'neutron-api' $rpc_package_name = 'neutron-rpc-server' $rpc_service_name = 'neutron-rpc-server' + $dynamic_routing_package = 'neutron-dynamic-routing' } else { $ml2_server_package = 'neutron-plugin-ml2' $server_service = 'neutron-server' @@ -108,7 +112,9 @@ class neutron::params { $api_service_name = false $rpc_package_name = false $rpc_service_name = false + $dynamic_routing_package = 'python-neutron-dynamic-routing' } + $bgp_dragent_package = 'neutron-bgp-dragent' $ovs_agent_package = 'neutron-openvswitch-agent' $ovs_server_package = 'neutron-plugin-openvswitch' $ovs_cleanup_service = false diff --git a/releasenotes/notes/add-bgp-dragent-c6b19e076b1acf0c.yaml b/releasenotes/notes/add-bgp-dragent-c6b19e076b1acf0c.yaml new file mode 100644 index 000000000..f8fcd01e6 --- /dev/null +++ b/releasenotes/notes/add-bgp-dragent-c6b19e076b1acf0c.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + New class neutron::agents::bgp_dragent that installs and manages the + neutron-dynamic-routing and neutron-bgp-dragent packages. + When you are using this feature you must enable the 'bgp' service plugin + by passing it in neutron::service_plugins. diff --git a/spec/classes/neutron_agents_bgp_dragent_spec.rb b/spec/classes/neutron_agents_bgp_dragent_spec.rb new file mode 100644 index 000000000..06dc9a183 --- /dev/null +++ b/spec/classes/neutron_agents_bgp_dragent_spec.rb @@ -0,0 +1,243 @@ +# Copyright (C) 2018 Binero AB. +# +# Author: Tobias Urdin +# +# 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 'neutron::agents::bgp_dragent' do + + let :default_params do + { + :package_ensure => 'present', + :enabled => true, + :manage_service => true, + :bgp_speaker_driver => 'neutron_dynamic_routing.services.bgp.agent.driver.ryu.driver.RyuBgpDriver', + :purge_config => false, + } + end + + let :params do + { + } + end + + shared_examples 'neutron::agents::bgp_dragent' do + context 'with default params' do + it { should contain_class('neutron::deps') } + it { should contain_class('neutron::params') } + + it { should contain_resources('neutron_bgp_dragent_config').with_purge(default_params[:purge_config]) } + + it { should contain_neutron_bgp_dragent_config('BGP/bgp_speaker_driver').with_value(default_params[:bgp_speaker_driver]) } + it { should contain_neutron_bgp_dragent_config('BGP/bgp_router_id').with_value(facts[:ipaddress]) } + end + + context 'with overridden params' do + before do + params.merge!( :bgp_speaker_driver => 'FakeDriver', + :bgp_router_id => '4.3.2.1', + :purge_config => true ) + end + + it { should contain_resources('neutron_bgp_dragent_config').with_purge(true) } + it { should contain_neutron_bgp_dragent_config('BGP/bgp_speaker_driver').with_value('FakeDriver') } + it { should contain_neutron_bgp_dragent_config('BGP/bgp_router_id').with_value('4.3.2.1') } + end + end + + shared_examples 'neutron::agents::bgp_dragent on RedHat' do + context 'with default params' do + it { should contain_package('neutron-dynamic-routing').with( + :ensure => default_params[:package_ensure], + :name => platform_params[:dynamic_routing_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should_not contain_package('neutron-bgp-dragent') } + + it { should contain_service('neutron-bgp-dragent').with( + :ensure => 'running', + :name => platform_params[:bgp_dragent_service], + :enable => default_params[:enabled], + :tag => 'neutron-service', + )} + end + + context 'with overridden params' do + before do + params.merge!( :package_ensure => 'absent', + :enabled => false ) + end + + it { should contain_package('neutron-dynamic-routing').with( + :ensure => 'absent', + :name => platform_params[:dynamic_routing_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should_not contain_package('neutron-bgp-dragent') } + + it { should contain_service('neutron-bgp-dragent').with( + :ensure => 'stopped', + :name => platform_params[:bgp_dragent_service], + :enable => false, + :tag => 'neutron-service', + )} + end + end + + shared_examples 'neutron::agents::bgp_dragent on Debian' do + before do + facts.merge!( :os_package_type => 'debian' ) + end + + context 'with default params' do + it { should contain_package('neutron-dynamic-routing').with( + :ensure => default_params[:package_ensure], + :name => platform_params[:dynamic_routing_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_package('neutron-bgp-dragent').with( + :ensure => default_params[:package_ensure], + :name => platform_params[:bgp_dragent_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_service('neutron-bgp-dragent').with( + :ensure => 'running', + :name => platform_params[:bgp_dragent_service], + :enable => default_params[:enabled], + :tag => 'neutron-service', + )} + end + + context 'with overridden params' do + before do + params.merge!( :package_ensure => 'absent', + :enabled => false ) + end + + it { should contain_package('neutron-dynamic-routing').with( + :ensure => 'absent', + :name => platform_params[:dynamic_routing_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_package('neutron-bgp-dragent').with( + :ensure => 'absent', + :name => platform_params[:bgp_dragent_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_service('neutron-bgp-dragent').with( + :ensure => 'stopped', + :name => platform_params[:bgp_dragent_service], + :enable => false, + :tag => 'neutron-service', + )} + end + end + + shared_examples 'neutron::agents::bgp_dragent on Ubuntu' do + context 'with default params' do + it { should contain_package('neutron-dynamic-routing').with( + :ensure => default_params[:package_ensure], + :name => platform_params[:dynamic_routing_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_package('neutron-bgp-dragent').with( + :ensure => default_params[:package_ensure], + :name => platform_params[:bgp_dragent_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_service('neutron-bgp-dragent').with( + :ensure => 'running', + :name => platform_params[:bgp_dragent_service], + :enable => default_params[:enabled], + :tag => 'neutron-service', + )} + end + + context 'with overridden params' do + before do + params.merge!( :package_ensure => 'absent', + :enabled => false ) + end + + it { should contain_package('neutron-dynamic-routing').with( + :ensure => 'absent', + :name => platform_params[:dynamic_routing_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_package('neutron-bgp-dragent').with( + :ensure => 'absent', + :name => platform_params[:bgp_dragent_package], + :tag => ['openstack', 'neutron-package'], + )} + + it { should contain_service('neutron-bgp-dragent').with( + :ensure => 'stopped', + :name => platform_params[:bgp_dragent_service], + :enable => false, + :tag => 'neutron-service', + )} + end + end + + on_supported_os({ + :supported_os => OSDefaults.get_supported_os + }).each do |os,facts| + context "on #{os}" do + let (:facts) do + facts.merge(OSDefaults.get_facts({:ipaddress => '1.2.3.4'})) + end + + let (:platform_params) do + case facts[:osfamily] + when 'RedHat' + { + :dynamic_routing_package => 'openstack-neutron-dynamic-routing', + :bgp_dragent_package => false, + :bgp_dragent_service => 'neutron-bgp-dragent', + } + when 'Debian' + if facts[:operatingsystem] == 'Debian' + pkg = 'neutron-dynamic-routing' + else + pkg = 'python-neutron-dynamic-routing' + end + { + :dynamic_routing_package => pkg, + :bgp_dragent_package => 'neutron-bgp-dragent', + :bgp_dragent_service => 'neutron-bgp-dragent', + } + end + end + + it_behaves_like 'neutron::agents::bgp_dragent' + + case facts[:osfamily] + when 'RedHat' + it_behaves_like 'neutron::agents::bgp_dragent on RedHat' + when 'Debian' + it_behaves_like "neutron::agents::bgp_dragent on #{facts[:operatingsystem]}" + end + end + end +end diff --git a/spec/classes/neutron_config_spec.rb b/spec/classes/neutron_config_spec.rb index dda7c9664..1b765cb92 100644 --- a/spec/classes/neutron_config_spec.rb +++ b/spec/classes/neutron_config_spec.rb @@ -64,6 +64,7 @@ describe 'neutron::config' do :metering_agent_config => config_hash, :vpnaas_agent_config => config_hash, :l2gw_agent_config => config_hash, + :bgp_dragent_config => config_hash, } end @@ -109,6 +110,12 @@ describe 'neutron::config' do is_expected.to contain_neutron_l2gw_agent_config('DEFAULT/baz').with_ensure('absent') end + it 'configures arbitrary bgp_dragent_config configurations' do + is_expected.to contain_neutron_bgp_dragent_config('DEFAULT/foo').with_value('fooValue') + is_expected.to contain_neutron_bgp_dragent_config('DEFAULT/bar').with_value('barValue') + is_expected.to contain_neutron_bgp_dragent_config('DEFAULT/baz').with_ensure('absent') + end + end shared_examples_for 'neutron_plugin_config' do diff --git a/spec/unit/provider/neutron_bgp_dragent_config/openstackconfig_spec.rb b/spec/unit/provider/neutron_bgp_dragent_config/openstackconfig_spec.rb new file mode 100644 index 000000000..9f25ad148 --- /dev/null +++ b/spec/unit/provider/neutron_bgp_dragent_config/openstackconfig_spec.rb @@ -0,0 +1,74 @@ +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'inifile', + 'lib') +) +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'openstacklib', + 'lib') +) + +require 'spec_helper' + +provider_class = Puppet::Type.type(:neutron_bgp_dragent_config).provider(:openstackconfig) + +describe provider_class do + + it 'should default to the default setting when no other one is specified' do + resource = Puppet::Type::Neutron_bgp_dragent_config.new( + { + :name => 'DEFAULT/foo', + :value => 'bar' + } + ) + provider = provider_class.new(resource) + expect(provider.section).to eq('DEFAULT') + expect(provider.setting).to eq('foo') + expect(provider.file_path).to eq('/etc/neutron/bgp_dragent.ini') + end + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Neutron_bgp_dragent_config.new( + { + :name => 'dude/foo', + :value => 'bar' + } + ) + provider = provider_class.new(resource) + expect(provider.section).to eq('dude') + expect(provider.setting).to eq('foo') + expect(provider.file_path).to eq('/etc/neutron/bgp_dragent.ini') + end + + it 'should ensure absent when is specified as a value' do + resource = Puppet::Type::Neutron_bgp_dragent_config.new( + {:name => 'dude/foo', :value => ''} + ) + provider = provider_class.new(resource) + provider.exists? + expect(resource[:ensure]).to eq :absent + end + + it 'should ensure absent when value matches ensure_absent_val' do + resource = Puppet::Type::Neutron_bgp_dragent_config.new( + {:name => 'dude/foo', :value => 'foo', :ensure_absent_val => 'foo' } + ) + provider = provider_class.new(resource) + provider.exists? + expect(resource[:ensure]).to eq :absent + end + +end diff --git a/spec/unit/type/neutron_bgp_dragent_config_spec.rb b/spec/unit/type/neutron_bgp_dragent_config_spec.rb new file mode 100644 index 000000000..0268e820c --- /dev/null +++ b/spec/unit/type/neutron_bgp_dragent_config_spec.rb @@ -0,0 +1,23 @@ +require 'puppet' +require 'puppet/type/neutron_bgp_dragent_config' + +describe 'Puppet::Type.type(:neutron_bgp_dragent_config)' do + + before :each do + @neutron_bgp_dragent_config = Puppet::Type.type(:neutron_bgp_dragent_config).new(:name => 'DEFAULT/foo', :value => 'bar') + end + + it 'should autorequire the package that install the file' do + catalog = Puppet::Resource::Catalog.new + package1 = Puppet::Type.type(:package).new(:name => 'neutron-dynamic-routing') + package2 = Puppet::Type.type(:package).new(:name => 'neutron-bgp-dragent') + catalog.add_resource package1, package2, @neutron_bgp_dragent_config + dependency = @neutron_bgp_dragent_config.autorequire + expect(dependency.size).to eq(2) + expect(dependency[0].target).to eq(@neutron_bgp_dragent_config) + expect(dependency[0].source).to eq(package1) + expect(dependency[1].target).to eq(@neutron_bgp_dragent_config) + expect(dependency[1].source).to eq(package2) + end + +end