diff --git a/lib/puppet/provider/neutron_agent_vpp/ini_settings.rb b/lib/puppet/provider/neutron_agent_vpp/ini_settings.rb new file mode 100644 index 000000000..d8da7ab13 --- /dev/null +++ b/lib/puppet/provider/neutron_agent_vpp/ini_settings.rb @@ -0,0 +1,15 @@ +Puppet::Type.type(:neutron_agent_vpp).provide( + :ini_setting, + :parent => Puppet::Type.type(:openstack_config).provider(:ini_setting) +) do + + def self.file_path + '/etc/neutron/plugins/ml2/vpp_agent.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_agent_vpp.rb b/lib/puppet/type/neutron_agent_vpp.rb new file mode 100644 index 000000000..0718db816 --- /dev/null +++ b/lib/puppet/type/neutron_agent_vpp.rb @@ -0,0 +1,28 @@ +Puppet::Type.newtype(:neutron_agent_vpp) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from vpp agent 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-vpp-agent' + end + +end diff --git a/manifests/agents/ml2/vpp.pp b/manifests/agents/ml2/vpp.pp new file mode 100644 index 000000000..f17d67e87 --- /dev/null +++ b/manifests/agents/ml2/vpp.pp @@ -0,0 +1,92 @@ +# == Class: neutron::agents::ml2::vpp +# +# Configure networking-vpp Neutron agent for ML2 plugin. +# +# === Parameters +# +# [*package_ensure*] +# (optional) Package ensure state. +# Defaults to 'present'. +# +# [*enabled*] +# (required) Whether or not to enable the agent. +# Defaults to true. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*physnets*] +# (optional) Comma-separated list of : +# tuples mapping physical network names to agent's node-specific physical +# network interfaces. Defaults to $::os_service_default. +# +# [*etcd_host*] +# (optional) etcd server host name/ip +# Defaults to $::os_service_default. +# +# [*etcd_port*] +# (optional) etcd server listening port. +# Defaults to $::os_service_default. +# +# [*etcd_user*] +# (optional) User name for etcd authentication +# Defaults to $::os_service_default. +# +# [*etcd_pass*] +# (optional) Password for etcd authentication +# Defaults to $::os_service_default. +# +# [*purge_config*] +# (optional) Whether to set only the specified config options +# in the vpp config. +# Defaults to false. +# +class neutron::agents::ml2::vpp ( + $package_ensure = 'present', + $enabled = true, + $manage_service = true, + $physnets = $::os_service_default, + $etcd_host = $::os_service_default, + $etcd_port = $::os_service_default, + $etcd_user = $::os_service_default, + $etcd_pass = $::os_service_default, + $purge_config = false, +) { + include ::neutron::deps + include ::neutron::params + + resources { 'neutron_agent_vpp': + purge => $purge_config, + } + + neutron_agent_vpp { + 'ml2_vpp/physnets': value => $physnets; + 'ml2_vpp/etcd_host': value => $etcd_host; + 'ml2_vpp/etcd_port': value => $etcd_port; + 'ml2_vpp/etcd_user': value => $etcd_user; + 'ml2_vpp/etcd_pass': value => $etcd_pass; + 'DEFAULT/host': value => $::hostname; + } + + package { 'neutron-vpp-agent': + ensure => $package_ensure, + name => $::neutron::params::vpp_plugin_package, + tag => ['openstack', 'neutron-package'], + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-vpp-agent-service': + ensure => $service_ensure, + name => $::neutron::params::vpp_agent_service, + enable => $enabled, + tag => ['neutron-service'], + } +} diff --git a/manifests/deps.pp b/manifests/deps.pp index 94b6f78df..835e90662 100644 --- a/manifests/deps.pp +++ b/manifests/deps.pp @@ -35,6 +35,7 @@ class neutron::deps { # All other inifile providers need to be processed in the config block Anchor['neutron::config::begin'] -> Neutron_agent_linuxbridge<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_agent_ovs<||> ~> Anchor['neutron::config::end'] + Anchor['neutron::config::begin'] -> Neutron_agent_vpp<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_api_config<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_api_paste_ini<||> ~> Anchor['neutron::config::end'] Anchor['neutron::config::begin'] -> Neutron_config<||> ~> Anchor['neutron::config::end'] diff --git a/manifests/params.pp b/manifests/params.pp index 87f1cf5d2..55b235bac 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -15,6 +15,8 @@ class neutron::params { $midonet_server_package = 'python-networking-midonet' $midonet_config_file = '/etc/neutron/plugins/midonet/midonet.ini' $ovn_plugin_package = 'python-networking-ovn' + $vpp_plugin_package = 'python-networking-vpp' + $vpp_agent_service = 'neutron-vpp-agent' $plumgrid_plugin_package = 'networking-plumgrid' $plumgrid_pythonlib_package = 'plumgrid-pythonlib' $plumgrid_config_file = '/etc/neutron/plugins/plumgrid/plumgrid.ini' diff --git a/manifests/plugins/ml2/vpp.pp b/manifests/plugins/ml2/vpp.pp new file mode 100644 index 000000000..837a6148d --- /dev/null +++ b/manifests/plugins/ml2/vpp.pp @@ -0,0 +1,38 @@ +# +# Install the networking-vpp ML2 mechanism driver and generate config file +# from parameters in the other classes. +# +# === Parameters +# +# [*etcd_host*] +# (optional) etcd server host name or IP. +# Defaults to $::os_service_default +# +# [*etcd_port*] +# (optional) etcd server listening port. +# Defaults to $::os_service_default. +# +# [*etcd_user*] +# (optional) User name for etcd authentication +# Defaults to $::os_service_default. +# +# [*etcd_pass*] +# (optional) Password for etcd authentication +# Defaults to $::os_service_default. +# +class neutron::plugins::ml2::vpp ( + $etcd_host = $::os_service_default, + $etcd_port = $::os_service_default, + $etcd_user = $::os_service_default, + $etcd_pass = $::os_service_default, +) { + include ::neutron::deps + require ::neutron::plugins::ml2 + + neutron_plugin_ml2 { + 'ml2_vpp/etcd_host': value => $etcd_host; + 'ml2_vpp/etcd_port': value => $etcd_port; + 'ml2_vpp/etcd_user': value => $etcd_user; + 'ml2_vpp/etcd_pass': value => $etcd_pass; + } +} diff --git a/releasenotes/notes/add_vpp_ml2_plugin-46de25de925d4cf0.yaml b/releasenotes/notes/add_vpp_ml2_plugin-46de25de925d4cf0.yaml new file mode 100644 index 000000000..7df6f248c --- /dev/null +++ b/releasenotes/notes/add_vpp_ml2_plugin-46de25de925d4cf0.yaml @@ -0,0 +1,3 @@ +--- +features: + - Add support for VPP ML2 driver. diff --git a/spec/acceptance/neutron_config_spec.rb b/spec/acceptance/neutron_config_spec.rb index 4a955adc6..d8fa837d5 100644 --- a/spec/acceptance/neutron_config_spec.rb +++ b/spec/acceptance/neutron_config_spec.rb @@ -22,7 +22,8 @@ describe 'basic neutron_config resource' do '/etc/neutron/plugins/opencontrail/ContrailPlugin.ini', '/etc/neutron/plugins/plumgrid/plumgrid.ini', '/etc/neutron/plugins/ml2/ml2_conf_sriov.ini', - '/etc/neutron/plugins/ml2/sriov_agent.ini'] + '/etc/neutron/plugins/ml2/sriov_agent.ini', + '/etc/neutron/plugins/ml2/vpp_agent.ini'] pp= <<-EOS Exec { logoutput => 'on_failure' } @@ -51,6 +52,8 @@ describe 'basic neutron_config resource' do File <||> -> Neutron_plumlib_plumgrid <||> File <||> -> Neutron_plugin_sriov <||> File <||> -> Neutron_sriov_agent_config <||> + File <||> -> Neutron_agent_vpp <||> + $neutron_directories = ['/etc/neutron', '/etc/neutron/plugins', @@ -82,7 +85,8 @@ describe 'basic neutron_config resource' do '/etc/neutron/plugins/opencontrail/ContrailPlugin.ini', '/etc/neutron/plugins/plumgrid/plumgrid.ini', '/etc/neutron/plugins/ml2/ml2_conf_sriov.ini', - '/etc/neutron/plugins/ml2/sriov_agent.ini'] + '/etc/neutron/plugins/ml2/sriov_agent.ini', + '/etc/neutron/plugins/ml2/vpp_agent.ini'] file { $neutron_directories : ensure => directory, @@ -522,6 +526,25 @@ describe 'basic neutron_config resource' do ensure_absent_val => 'toto', } + neutron_agent_vpp { 'DEFAULT/thisshouldexist' : + value => 'foo', + } + + neutron_agent_vpp { 'DEFAULT/thisshouldnotexist' : + value => '', + } + + neutron_agent_vpp { 'DEFAULT/thisshouldexist2' : + value => '', + ensure_absent_val => 'toto', + } + + neutron_agent_vpp { 'DEFAULT/thisshouldnotexist2' : + value => 'toto', + ensure_absent_val => 'toto', + } + + EOS resource_names = ['neutron_api_config', @@ -546,7 +569,8 @@ describe 'basic neutron_config resource' do 'neutron_agent_ovs', 'neutron_plugin_plumgrid', 'neutron_plugin_sriov', - 'neutron_sriov_agent_config'] + 'neutron_sriov_agent_config', + 'neutron_agent_vpp'] pp_resource_names = " $resource_names = [" + resource_names.collect { |r| " '#{r}'," }.join("\n") + " ]\n" diff --git a/spec/classes/neutron_agents_ml2_vpp_spec.rb b/spec/classes/neutron_agents_ml2_vpp_spec.rb new file mode 100644 index 000000000..3573ef226 --- /dev/null +++ b/spec/classes/neutron_agents_ml2_vpp_spec.rb @@ -0,0 +1,105 @@ +require 'spec_helper' + +describe 'neutron::agents::ml2::vpp' do + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :manage_service => true, + :etcd_host => '127.0.0.1', + :etcd_port => 4001, + } + end + + let :params do + {} + end + + shared_examples_for 'neutron plugin vpp agent with ml2 plugin' do + let :p do + default_params.merge(params) + end + + it { is_expected.to contain_class('neutron::params') } + + it 'passes purge to resource' do + is_expected.to contain_resources('neutron_agent_vpp').with({ + :purge => false + }) + end + + it 'configures plugins/ml2/vpp_agent.ini' do + is_expected.to contain_neutron_agent_vpp('ml2_vpp/physnets').with_value('') + is_expected.to contain_neutron_agent_vpp('ml2_vpp/etcd_user').with_value('') + is_expected.to contain_neutron_agent_vpp('ml2_vpp/etcd_pass').with_value('') + end + + it 'installs neutron vpp agent package' do + is_expected.to contain_package('neutron-vpp-agent').with( + :name => platform_params[:vpp_plugin_package], + :ensure => p[:package_ensure], + :tag => ['openstack', 'neutron-package'], + ) + end + + it 'configures neutron vpp agent service' do + is_expected.to contain_service('neutron-vpp-agent-service').with( + :name => platform_params[:vpp_agent_service], + :enable => true, + :ensure => 'running', + :tag => ['neutron-service'], + ) + is_expected.to contain_service('neutron-vpp-agent-service').that_subscribes_to('Anchor[neutron::service::begin]') + is_expected.to contain_service('neutron-vpp-agent-service').that_notifies('Anchor[neutron::service::end]') + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + is_expected.to contain_service('neutron-vpp-agent-service').without_ensure + end + end + + context 'when supplying a physnet mapping' do + before :each do + params.merge!(:physnets => 'physnet:GigabitEthernet2/2/0') + end + it 'should configure physnets' do + is_expected.to contain_neutron_agent_vpp('ml2_vpp/physnets').with_value('physnet:GigabitEthernet2/2/0') + end + end + + context 'when enabling etcd authentication' do + before :each do + params.merge!(:etcd_user => 'admin', + :etcd_pass => 'password' ) + end + it 'should configure etcd username and password' do + is_expected.to contain_neutron_agent_vpp('ml2_vpp/etcd_user').with_value('admin') + is_expected.to contain_neutron_agent_vpp('ml2_vpp/etcd_pass').with_value('password') + end + 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()) + end + + let :platform_params do + { :vpp_plugin_package => 'python-networking-vpp', + :vpp_agent_service => 'neutron-vpp-agent' } + end + + it_behaves_like 'neutron plugin vpp agent with ml2 plugin' + end + end +end diff --git a/spec/classes/neutron_plugins_ml2_vpp_spec.rb b/spec/classes/neutron_plugins_ml2_vpp_spec.rb new file mode 100644 index 000000000..72bc7da83 --- /dev/null +++ b/spec/classes/neutron_plugins_ml2_vpp_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe 'neutron::plugins::ml2::vpp' do + + let :pre_condition do + "class { '::neutron::keystone::authtoken': + password => 'passw0rd', + } + class { 'neutron::server': } + class { 'neutron': + rabbit_password => 'passw0rd', + core_plugin => 'neutron.plugins.ml2.plugin.Ml2Plugin' }" + end + + let :default_params do + { + :etcd_host => '127.0.0.1', + :etcd_port => 4001, + } + end + + let :params do + { + } + end + + let :test_facts do + { + :operatingsystem => 'default', + :operatingsystemrelease => 'default', + } + end + + + shared_examples_for 'neutron plugin vpp ml2' do + before do + params.merge!(default_params) + end + + it 'configures ml2_vpp settings' do + is_expected.to contain_neutron_plugin_ml2('ml2_vpp/etcd_host').with_value(params[:etcd_host]) + is_expected.to contain_neutron_plugin_ml2('ml2_vpp/etcd_port').with_value(params[:etcd_port]) + is_expected.to contain_neutron_plugin_ml2('ml2_vpp/etcd_user').with_value('') + is_expected.to contain_neutron_plugin_ml2('ml2_vpp/etcd_pass').with_value('') + end + + context 'when enabling etcd authentication' do + before :each do + params.merge!(:etcd_user => 'admin', + :etcd_pass => 'password' ) + end + it 'should configure etcd username and password' do + is_expected.to contain_neutron_plugin_ml2('ml2_vpp/etcd_user').with_value('admin') + is_expected.to contain_neutron_plugin_ml2('ml2_vpp/etcd_pass').with_value('password') + end + 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()) + end + + it_configures 'neutron plugin vpp ml2' + end + end + +end diff --git a/spec/unit/provider/neutron_agent_vpp/ini_setting_spec.rb b/spec/unit/provider/neutron_agent_vpp/ini_setting_spec.rb new file mode 100644 index 000000000..516c57fa8 --- /dev/null +++ b/spec/unit/provider/neutron_agent_vpp/ini_setting_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_agent_vpp).provider(:ini_setting) + +describe provider_class do + + it 'should default to the default setting when no other one is specified' do + resource = Puppet::Type::Neutron_agent_vpp.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/plugins/ml2/vpp_agent.ini') + end + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Neutron_agent_vpp.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/plugins/ml2/vpp_agent.ini') + end + + it 'should ensure absent when is specified as a value' do + resource = Puppet::Type::Neutron_agent_vpp.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_agent_vpp.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_agent_vpp_spec.rb b/spec/unit/type/neutron_agent_vpp_spec.rb new file mode 100644 index 000000000..6ff2da761 --- /dev/null +++ b/spec/unit/type/neutron_agent_vpp_spec.rb @@ -0,0 +1,20 @@ +require 'puppet' +require 'puppet/type/neutron_agent_vpp' + +describe 'Puppet::Type.type(:neutron_agent_vpp)' do + + before :each do + @neutron_agent_vpp = Puppet::Type.type(:neutron_agent_vpp).new(:name => 'DEFAULT/foo', :value => 'bar') + end + + it 'should autorequire the package that install the file' do + catalog = Puppet::Resource::Catalog.new + package = Puppet::Type.type(:package).new(:name => 'neutron-vpp-agent') + catalog.add_resource package, @neutron_agent_vpp + dependency = @neutron_agent_vpp.autorequire + expect(dependency.size).to eq(1) + expect(dependency[0].target).to eq(@neutron_agent_vpp) + expect(dependency[0].source).to eq(package) + end + +end