diff --git a/lib/puppet/provider/neutron_agent_macvtap/ini_setting.rb b/lib/puppet/provider/neutron_agent_macvtap/ini_setting.rb new file mode 100644 index 000000000..0533a41b3 --- /dev/null +++ b/lib/puppet/provider/neutron_agent_macvtap/ini_setting.rb @@ -0,0 +1,15 @@ +Puppet::Type.type(:neutron_agent_macvtap).provide( + :ini_setting, + :parent => Puppet::Type.type(:openstack_config).provider(:ini_setting) +) do + + def self.file_path + '/etc/neutron/plugins/ml2/macvtap_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_macvtap.rb b/lib/puppet/type/neutron_agent_macvtap.rb new file mode 100644 index 000000000..f585a2189 --- /dev/null +++ b/lib/puppet/type/neutron_agent_macvtap.rb @@ -0,0 +1,28 @@ +Puppet::Type.newtype(:neutron_agent_macvtap) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from macvtap 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(:anchor) do + ['neutron::install::end'] + end + +end diff --git a/manifests/agents/ml2/macvtap.pp b/manifests/agents/ml2/macvtap.pp new file mode 100644 index 000000000..5ac01eea9 --- /dev/null +++ b/manifests/agents/ml2/macvtap.pp @@ -0,0 +1,87 @@ +# == Class: neutron::agents::ml2::macvtap +# +# Setups Macvtap 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 +# +# [*polling_interval*] +# (optional) The number of seconds the agent will wait between +# polling for local device changes. +# Defaults to $::os_service_default. +# +# [*physical_interface_mappings*] +# (optional) List of : +# tuples mapping physical network names to agent's node-specific physical +# network interfaces. Defaults to empty list. +# +# [*purge_config*] +# (optional) Whether to set only the specified config options +# in the macvtap config. +# Defaults to false. +# +class neutron::agents::ml2::macvtap ( + $package_ensure = 'present', + $enabled = true, + $manage_service = true, + $polling_interval = $::os_service_default, + $physical_interface_mappings = [], + $purge_config = false, +) { + + validate_legacy(Array, 'validate_array', $physical_interface_mappings) + + include neutron::deps + include neutron::params + + resources { 'neutron_agent_macvtap': + purge => $purge_config, + } + + neutron_agent_macvtap { + 'agent/polling_interval': value => $polling_interval; + # NOTE(tkajinam): macvtap supports only noop firewall driver. + 'securitygroup/firewall_driver': value => 'noop'; + } + + if size($physical_interface_mappings) > 0 { + neutron_agent_macvtap { + 'macvtap/physical_interface_mappings': value => join(any2array($physical_interface_mappings), ','); + } + } else { + neutron_agent_macvtap { + 'macvtap/physical_interface_mappings': ensure => absent; + } + } + + package { 'neutron-plugin-macvtap-agent': + ensure => $package_ensure, + name => $::neutron::params::macvtap_agent_package, + tag => ['openstack', 'neutron-package'], + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + service { 'neutron-plugin-macvtap-agent': + ensure => $service_ensure, + name => $::neutron::params::macvtap_agent_service, + enable => $enabled, + tag => 'neutron-service', + } + } +} diff --git a/manifests/config.pp b/manifests/config.pp index 22120826f..292e384fe 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -36,6 +36,9 @@ # [*linuxbridge_agent_config*] # (optional) Manage configuration of linuxbridge_agent.ini # +# [*macvtap_agent_config*] +# (optional) Manage configuration of macvtap_agent.ini +# # [*bgpvpn_bagpipe_config*] # (optional) Manage configuration of bagpipe-bgp bgp.conf # @@ -101,6 +104,7 @@ class neutron::config ( $ovs_agent_config = {}, $sriov_agent_config = {}, $linuxbridge_agent_config = {}, + $macvtap_agent_config = {}, $bgpvpn_bagpipe_config = {}, $bgpvpn_service_config = {}, $l2gw_agent_config = {}, @@ -133,6 +137,7 @@ class neutron::config ( validate_legacy(Hash, 'validate_hash', $ovs_agent_config) validate_legacy(Hash, 'validate_hash', $sriov_agent_config) validate_legacy(Hash, 'validate_hash', $linuxbridge_agent_config) + validate_legacy(Hash, 'validate_hash', $macvtap_agent_config) validate_legacy(Hash, 'validate_hash', $bgpvpn_bagpipe_config) validate_legacy(Hash, 'validate_hash', $bgpvpn_service_config) validate_legacy(Hash, 'validate_hash', $l2gw_agent_config) @@ -156,6 +161,7 @@ class neutron::config ( create_resources('neutron_agent_ovs', $ovs_agent_config) create_resources('neutron_sriov_agent_config', $sriov_agent_config) create_resources('neutron_agent_linuxbridge', $linuxbridge_agent_config) + create_resources('neutron_agent_macvtap', $macvtap_agent_config) create_resources('neutron_bgpvpn_bagpipe_config', $bgpvpn_bagpipe_config) create_resources('neutron_bgpvpn_service_config', $bgpvpn_service_config) create_resources('neutron_l2gw_agent_config', $l2gw_agent_config) diff --git a/manifests/deps.pp b/manifests/deps.pp index 6506da3b0..4a97e0784 100644 --- a/manifests/deps.pp +++ b/manifests/deps.pp @@ -34,6 +34,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_macvtap<||> ~> 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_paste_ini<||> ~> Anchor['neutron::config::end'] diff --git a/manifests/params.pp b/manifests/params.pp index f29f4f2ce..1224ecd74 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -9,6 +9,7 @@ class neutron::params { $ovs_agent_service = 'neutron-openvswitch-agent' $destroy_patch_ports_service = 'neutron-destroy-patch-ports' $linuxbridge_agent_service = 'neutron-linuxbridge-agent' + $macvtap_agent_service = 'neutron-macvtap-agent' $opencontrail_plugin_package = 'neutron-plugin-contrail' $opencontrail_config_file = '/etc/neutron/plugins/opencontrail/ContrailPlugin.ini' $vpp_plugin_package = 'python3-networking-vpp' @@ -48,6 +49,7 @@ class neutron::params { $linuxbridge_server_package = 'openstack-neutron-linuxbridge' $sriov_nic_agent_service = 'neutron-sriov-nic-agent' $sriov_nic_agent_package = 'openstack-neutron-sriov-nic-agent' + $macvtap_agent_package = 'openstack-neutron-macvtap-agent' $dhcp_agent_package = false $metering_agent_package = 'openstack-neutron-metering-agent' $vpnaas_agent_package = 'openstack-neutron-vpnaas' @@ -100,6 +102,7 @@ class neutron::params { $linuxbridge_server_package = 'neutron-plugin-linuxbridge' $sriov_nic_agent_service = 'neutron-sriov-agent' $sriov_nic_agent_package = 'neutron-sriov-agent' + $macvtap_agent_package = 'neutron-macvtap-agent' $dhcp_agent_package = 'neutron-dhcp-agent' $metering_agent_package = 'neutron-metering-agent' $vpnaas_agent_package = 'python3-neutron-vpnaas' diff --git a/manifests/plugins/ml2.pp b/manifests/plugins/ml2.pp index 8a5126685..5b129d363 100644 --- a/manifests/plugins/ml2.pp +++ b/manifests/plugins/ml2.pp @@ -47,7 +47,7 @@ # entrypoints to be loaded from the neutron.ml2.mechanism_drivers namespace. # Should be an array that can have these elements: # logger, test, linuxbridge, openvswitch, hyperv, ncs, arista, cisco_nexus, -# l2population, sriovnicswitch +# l2population, sriovnicswitch, macvtap # Default to ['openvswitch', 'linuxbridge']. # # [*flat_networks*] diff --git a/releasenotes/notes/macvtap-5fa3c025eafcc4e3.yaml b/releasenotes/notes/macvtap-5fa3c025eafcc4e3.yaml new file mode 100644 index 000000000..9ab840421 --- /dev/null +++ b/releasenotes/notes/macvtap-5fa3c025eafcc4e3.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + ``macvtap`` mechanism driver is now supported. diff --git a/spec/classes/neutron_agents_ml2_macvtap_spec.rb b/spec/classes/neutron_agents_ml2_macvtap_spec.rb new file mode 100644 index 000000000..a19380fe6 --- /dev/null +++ b/spec/classes/neutron_agents_ml2_macvtap_spec.rb @@ -0,0 +1,96 @@ +require 'spec_helper' + +describe 'neutron::agents::ml2::macvtap' do + let :pre_condition do + "class { 'neutron': }" + end + + let :params do + {} + end + + shared_examples 'neutron plugin macvtap agent with ml2 plugin' do + context 'with default parameters' do + it { should contain_class('neutron::params') } + + it 'passes purge to resource' do + should contain_resources('neutron_agent_macvtap').with({ + :purge => false + }) + end + + it 'configures ml2_conf.ini' do + should contain_neutron_agent_macvtap('agent/polling_interval').with_value('') + should contain_neutron_agent_macvtap('macvtap/physical_interface_mappings').with_ensure('absent') + should contain_neutron_agent_macvtap('securitygroup/firewall_driver').with_value('noop') + end + + it 'installs neutron macvtap agent package' do + should contain_package('neutron-plugin-macvtap-agent').with( + :name => platform_params[:macvtap_agent_package], + :ensure => 'present', + :tag => ['openstack', 'neutron-package'], + ) + end + + it 'configures neutron macvtap agent service' do + should contain_service('neutron-plugin-macvtap-agent').with( + :name => platform_params[:macvtap_agent_service], + :enable => true, + :ensure => 'running', + :tag => 'neutron-service', + ) + should contain_service('neutron-plugin-macvtap-agent').that_subscribes_to('Anchor[neutron::service::begin]') + should contain_service('neutron-plugin-macvtap-agent').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 manage the service' do + should_not contain_service('neutron-plugin-macvtap-agent') + end + end + end + + context 'when providing the physical_interface_mappings parameter' do + before do + params.merge!(:physical_interface_mappings => ['physnet0:eth0', 'physnet1:eth1']) + end + + it 'configures physical interface mappings' do + should contain_neutron_agent_macvtap('macvtap/physical_interface_mappings').with_value( + params[:physical_interface_mappings].join(',') + ) + 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 + case facts[:osfamily] + when 'Debian' + { + :macvtap_agent_package => 'neutron-macvtap-agent', + :macvtap_agent_service => 'neutron-macvtap-agent' + } + when 'RedHat' + { + :macvtap_agent_package => 'openstack-neutron-macvtap-agent', + :macvtap_agent_service => 'neutron-macvtap-agent' + } + end + end + + it_behaves_like 'neutron plugin macvtap agent with ml2 plugin' + end + end +end diff --git a/spec/classes/neutron_config_spec.rb b/spec/classes/neutron_config_spec.rb index 827e7b877..7ec7bff1d 100644 --- a/spec/classes/neutron_config_spec.rb +++ b/spec/classes/neutron_config_spec.rb @@ -59,6 +59,7 @@ describe 'neutron::config' do { :ovs_agent_config => config_hash, :sriov_agent_config => config_hash, :linuxbridge_agent_config => config_hash, + :macvtap_agent_config => config_hash, :l3_agent_config => config_hash, :dhcp_agent_config => config_hash, :metadata_agent_config => config_hash, @@ -87,6 +88,12 @@ describe 'neutron::config' do should contain_neutron_agent_linuxbridge('DEFAULT/baz').with_ensure('absent') end + it 'configures arbitrary neutron_agent_macvtap configurations' do + should contain_neutron_agent_macvtap('DEFAULT/foo').with_value('fooValue') + should contain_neutron_agent_macvtap('DEFAULT/bar').with_value('barValue') + should contain_neutron_agent_macvtap('DEFAULT/baz').with_ensure('absent') + end + it 'configures arbitrary l3_agent_config configurations' do should contain_neutron_l3_agent_config('DEFAULT/foo').with_value('fooValue') should contain_neutron_l3_agent_config('DEFAULT/bar').with_value('barValue') diff --git a/spec/unit/provider/neutron_agent_macvtap/ini_setting_spec.rb b/spec/unit/provider/neutron_agent_macvtap/ini_setting_spec.rb new file mode 100644 index 000000000..f7da42c49 --- /dev/null +++ b/spec/unit/provider/neutron_agent_macvtap/ini_setting_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +provider_class = Puppet::Type.type(:neutron_agent_macvtap).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_macvtap.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/macvtap_agent.ini') + end + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Neutron_agent_macvtap.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/macvtap_agent.ini') + end + + it 'should ensure absent when is specified as a value' do + resource = Puppet::Type::Neutron_agent_macvtap.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_macvtap.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_macvtap_spec.rb b/spec/unit/type/neutron_agent_macvtap_spec.rb new file mode 100644 index 000000000..c58150c29 --- /dev/null +++ b/spec/unit/type/neutron_agent_macvtap_spec.rb @@ -0,0 +1,20 @@ +require 'puppet' +require 'puppet/type/neutron_agent_macvtap' + +describe 'Puppet::Type.type(:neutron_agent_macvtap)' do + + before :each do + @neutron_agent_macvtap = Puppet::Type.type(:neutron_agent_macvtap).new(:name => 'DEFAULT/foo', :value => 'bar') + end + + it 'should autorequire the package that install the file' do + catalog = Puppet::Resource::Catalog.new + anchor = Puppet::Type.type(:anchor).new(:name => 'neutron::install::end') + catalog.add_resource anchor, @neutron_agent_macvtap + dependency = @neutron_agent_macvtap.autorequire + expect(dependency.size).to eq(1) + expect(dependency[0].target).to eq(@neutron_agent_macvtap) + expect(dependency[0].source).to eq(anchor) + end + +end