From e3ada8a858e9abc0535d615d04afed92edd93c4e Mon Sep 17 00:00:00 2001 From: Tim Rozet Date: Tue, 24 Nov 2015 14:39:12 -0500 Subject: [PATCH] Adds configuration support for OpenDaylight SDN Controller In order to use OpenDaylight with Neutron, ML2 must be configured to point to the OpenDaylight controller instance. It also requires the networking-odl python library to drive communication with ODL. Additionally each Open vSwitch instance must be configured to set the ODL Controller as it's manager. Change-Id: If067e1057bec2d48f700838d86077a550bd27bd2 Signed-off-by: Tim Rozet (cherry picked from commit 45954a106abc107b7d260b5d16b2e3c6c592893c) --- manifests/plugins/ml2/opendaylight.pp | 60 +++++++++++++ manifests/plugins/ovs/opendaylight.pp | 75 ++++++++++++++++ .../neutron_plugins_ml2_opendaylight_spec.rb | 73 +++++++++++++++ .../neutron_plugins_ovs_opendaylight_spec.rb | 88 +++++++++++++++++++ 4 files changed, 296 insertions(+) create mode 100644 manifests/plugins/ml2/opendaylight.pp create mode 100644 manifests/plugins/ovs/opendaylight.pp create mode 100644 spec/classes/neutron_plugins_ml2_opendaylight_spec.rb create mode 100644 spec/classes/neutron_plugins_ovs_opendaylight_spec.rb diff --git a/manifests/plugins/ml2/opendaylight.pp b/manifests/plugins/ml2/opendaylight.pp new file mode 100644 index 000000000..a8945fd8c --- /dev/null +++ b/manifests/plugins/ml2/opendaylight.pp @@ -0,0 +1,60 @@ +# +# Install the OpenDaylight and generate config file +# from parameters in the other classes. +# +# === Parameters +# +# [*package_ensure*] +# (optional) The intended state of the python-networking-odl +# package, i.e. any of the possible values of the 'ensure' +# property for a package resource type. +# Defaults to 'present' +# +# [*odl_username*] +# (optional) The opendaylight controller username +# Defaults to undef +# Example: 'admin' +# +# [*odl_password*] +# (optional) The opendaylight controller password +# Defaults to undef +# Example: 'admin' +# +# [*odl_url*] +# (optional) The opendaylight controller neutron URL +# Defaults to undef +# Example: 'http://127.0.0.1:8080/controller/nb/v2/neutron' +# +class neutron::plugins::ml2::opendaylight ( + $package_ensure = 'present', + $odl_username = undef, + $odl_password = undef, + $odl_url = undef +) { + require ::neutron::plugins::ml2 + + ensure_resource('package', 'python-networking-odl', + { + ensure => $package_ensure, + tag => 'openstack', + } + ) + + if ($odl_username) { + neutron_plugin_ml2 { 'ml2_odl/username': value => $odl_username; } + } else { + neutron_plugin_ml2 { 'ml2_odl/username': ensure => absent; } + } + + if ($odl_password) { + neutron_plugin_ml2 { 'ml2_odl/password': value => $odl_password; } + } else { + neutron_plugin_ml2 { 'ml2_odl/password': ensure => absent; } + } + + if ($odl_url) { + neutron_plugin_ml2 { 'ml2_odl/url': value => $odl_url; } + } else { + neutron_plugin_ml2 { 'ml2_odl/url': ensure => absent; } + } +} diff --git a/manifests/plugins/ovs/opendaylight.pp b/manifests/plugins/ovs/opendaylight.pp new file mode 100644 index 000000000..bb489c6a3 --- /dev/null +++ b/manifests/plugins/ovs/opendaylight.pp @@ -0,0 +1,75 @@ +# +# Configure OVS to use OpenDaylight +# +# === Parameters +# +# [*tunnel_ip*] +# (required) The IP of the host to use for tunneling +# tenant VXLAN/GRE over +# +# [*odl_username*] +# (optional) The opendaylight controller username +# Defaults to 'admin' +# +# [*odl_password*] +# (optional) The opendaylight controller password +# Defaults to 'admin' +# +# [*odl_check_url*] +# (optional) The URL used to check ODL is available and ready +# Defaults to 'http://127.0.0.1:8080/restconf/operational/network-topology:network-topology/topology/netvirt:1' +# +# [*odl_ovsdb_iface*] +# (optional) The ODL southbound interface for OVSDB +# Defaults to 'tcp:127.0.0.1:6640' +# +# [*provider_mappings*] +# (optional) bridge mappings required if using VLAN +# tenant type. Example: provider_mappings=br-ex:eth0 +# Defaults to false +# +# [*retry_interval*] +# (optional) The time (in seconds) to wait between ODL availability checks +# Defaults to 60 +# +# [*retry_count*] +# (optional) The number of ODL availability checks to run before failing +# Defaults to 20 +# +class neutron::plugins::ovs::opendaylight ( + $tunnel_ip, + $odl_username = 'admin', + $odl_password = 'admin', + $odl_check_url = 'http://127.0.0.1:8080/restconf/operational/network-topology:network-topology/topology/netvirt:1', + $odl_ovsdb_iface = 'tcp:127.0.0.1:6640', + $provider_mappings = false, + $retry_interval = 60, + $retry_count = 20, +) { + # Handle the case where ODL controller is also on this host + Service<| title == 'opendaylight' |> -> Exec <| title == 'Wait for NetVirt OVSDB to come up' |> + + exec { 'Wait for NetVirt OVSDB to come up': + command => "/bin/curl -o /dev/null --fail --silent --head -u ${odl_username}:${odl_password} ${odl_check_url}", + tries => $retry_count, + try_sleep => $retry_interval, + } -> + # OVS manager + exec { 'Set OVS Manager to OpenDaylight': + command => "/usr/bin/ovs-vsctl set-manager ${odl_ovsdb_iface}", + unless => "/usr/bin/ovs-vsctl show | /usr/bin/grep 'Manager \"${odl_ovsdb_iface}\"'", + } -> + # local ip + exec { 'Set local_ip Other Option': + command => "/usr/bin/ovs-vsctl set Open_vSwitch $(ovs-vsctl get Open_vSwitch . _uuid) other_config:local_ip=${tunnel_ip}", + unless => "/usr/bin/ovs-vsctl list Open_vSwitch | /usr/bin/grep 'local_ip=\"${tunnel_ip}\"'", + } + + # set mappings for VLAN + if $provider_mappings { + exec { 'Set provider_mappings Other Option': + command => "/usr/bin/ovs-vsctl set Open_vSwitch $(ovs-vsctl get Open_vSwitch . _uuid) other_config:provider_mappings=${provider_mappings}", + unless => "/usr/bin/ovs-vsctl list Open_vSwitch | /usr/bin/grep 'provider_mappings' | /usr/bin/grep ${provider_mappings}", + } + } +} diff --git a/spec/classes/neutron_plugins_ml2_opendaylight_spec.rb b/spec/classes/neutron_plugins_ml2_opendaylight_spec.rb new file mode 100644 index 000000000..6eefa6d17 --- /dev/null +++ b/spec/classes/neutron_plugins_ml2_opendaylight_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe 'neutron::plugins::ml2::opendaylight' do + + let :pre_condition do + "class { 'neutron::server': auth_password => 'password'} + class { 'neutron': + rabbit_password => 'passw0rd', + core_plugin => 'neutron.plugins.ml2.plugin.Ml2Plugin' }" + end + + let :default_params do + { + :package_ensure => 'present', + #:odl_username => '', + #:odl_password => '', + #:odl_url => '', + } + end + + let :params do + { + } + end + + let :test_facts do + { + :operatingsystem => 'default', + :operatingsystemrelease => 'default', + } + end + + + shared_examples_for 'neutron plugin opendaylight ml2' do + before do + params.merge!(default_params) + end + + it 'should have' do + is_expected.to contain_package('python-networking-odl').with( + :ensure => params[:package_ensure], + :tag => 'openstack' + ) + end + + it 'configures ml2_odl settings' do + is_expected.to contain_neutron_plugin_ml2('ml2_odl/password').with_ensure('absent') + is_expected.to contain_neutron_plugin_ml2('ml2_odl/username').with_ensure('absent') + is_expected.to contain_neutron_plugin_ml2('ml2_odl/url').with_ensure('absent') + end + end + + context 'on RedHat platforms' do + let :facts do + test_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '7' + }) + end + + it_configures 'neutron plugin opendaylight ml2' + end + + context 'on Debian platforms' do + let :facts do + test_facts.merge({ + :osfamily => 'Debian', + }) + end + + it_configures 'neutron plugin opendaylight ml2' + end +end diff --git a/spec/classes/neutron_plugins_ovs_opendaylight_spec.rb b/spec/classes/neutron_plugins_ovs_opendaylight_spec.rb new file mode 100644 index 000000000..10dd7082f --- /dev/null +++ b/spec/classes/neutron_plugins_ovs_opendaylight_spec.rb @@ -0,0 +1,88 @@ +describe 'neutron::plugins::ovs::opendaylight' do + + let :pre_condition do + "class { 'neutron::server': auth_password => 'password'} + class { 'neutron': + rabbit_password => 'passw0rd', + core_plugin => 'neutron.plugins.ml2.plugin.Ml2Plugin' }" + end + + let :default_params do + { + :odl_username => 'admin', + :odl_password => 'admin', + :odl_check_url => 'http://127.0.0.1:8080/restconf/operational/network-topology:network-topology/topology/netvirt:1', + :odl_ovsdb_iface => 'tcp:127.0.0.1:6640', + :provider_mappings => false, + :retry_interval => 60, + :retry_count => 20, + } + end + + let :params do + { + :tunnel_ip => '127.0.0.1', + } + end + + let :test_facts do + { + :operatingsystem => 'default', + :operatingsystemrelease => 'default', + } + end + + + shared_examples_for 'neutron plugin opendaylight ovs' do + before do + params.merge!(default_params) + end + + context 'with provider mappings' do + before do + params.merge!({ :provider_mappings => true }) + end + it_configures 'with provider mappings' + end + it_configures 'with default parameters' + end + + shared_examples_for 'with default parameters' do + it 'configures OVS for ODL' do + is_expected.to contain_exec('Wait for NetVirt OVSDB to come up') + is_expected.to contain_exec('Set OVS Manager to OpenDaylight') + is_expected.to contain_exec('Set local_ip Other Option') + is_expected.not_to contain_exec('Set provider_mappings Other Option') + end + end + + shared_examples_for 'with provider mappings' do + it 'configures OVS for ODL' do + is_expected.to contain_exec('Wait for NetVirt OVSDB to come up') + is_expected.to contain_exec('Set OVS Manager to OpenDaylight') + is_expected.to contain_exec('Set local_ip Other Option') + is_expected.to contain_exec('Set provider_mappings Other Option') + end + end + + context 'on RedHat platforms' do + let :facts do + test_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '7' + }) + end + + it_configures 'neutron plugin opendaylight ovs' + end + + context 'on Debian platforms' do + let :facts do + test_facts.merge({ + :osfamily => 'Debian' + }) + end + + it_configures 'neutron plugin opendaylight ovs' + end +end