Enables OpenDaylight Clustering in HA deployments
authorTim Rozet <trozet@redhat.com>
Wed, 25 Jan 2017 20:09:32 +0000 (15:09 -0500)
committerTim Rozet <trozet@redhat.com>
Thu, 16 Mar 2017 20:13:10 +0000 (16:13 -0400)
Previously ODL was restricted to only running on the first node in an
tripleO HA deployment.  This patches enables clustering for ODL and
allows multiple ODL instances (minimum 3 for HA).

Partially-implements: blueprint opendaylight-ha

Change-Id: Ic9a955a1c2afc040b2f9c6fb86573c04a60f9f31
Signed-off-by: Tim Rozet <trozet@redhat.com>
Puppetfile_extras
manifests/profile/base/neutron/opendaylight.pp
manifests/profile/base/neutron/plugins/ml2/opendaylight.pp
manifests/profile/base/neutron/plugins/ovs/opendaylight.pp
releasenotes/notes/add-opendaylight-ha-47a40c03917faf9c.yaml [new file with mode: 0644]
spec/classes/tripleo_profile_base_neutron_opendaylight_spec.rb [new file with mode: 0644]

index e21e63f..0b617b9 100644 (file)
@@ -44,3 +44,7 @@ mod 'ntp',
 mod 'systemd',
   :git => 'https://github.com/camptocamp/puppet-systemd',
   :ref => 'master'
+
+mod 'opendaylight',
+  :git => 'https://github.com/dfarrell07/puppet-opendaylight',
+  :ref => 'master'
index 556fe63..b5e6d11 100644 (file)
 #   (Optional) The current step of the deployment
 #   Defaults to hiera('step')
 #
-# [*primary_node*]
-#   (Optional) The hostname of the first node of this role type
-#   Defaults to hiera('bootstrap_nodeid', undef)
+# [*odl_api_ips*]
+#   (Optional) List of OpenStack Controller IPs for ODL API
+#   Defaults to hiera('opendaylight_api_node_ips')
+#
+# [*node_name*]
+#   (Optional) The short hostname of node
+#   Defaults to hiera('bootstack_nodeid')
 #
 class tripleo::profile::base::neutron::opendaylight (
   $step         = hiera('step'),
-  $primary_node = hiera('bootstrap_nodeid', undef),
+  $odl_api_ips  = hiera('opendaylight_api_node_ips'),
+  $node_name    = hiera('bootstack_nodeid')
 ) {
 
   if $step >= 1 {
-    # Configure ODL only on first node of the role where this service is
-    # applied
-    if $primary_node == downcase($::hostname) {
+    validate_array($odl_api_ips)
+    if empty($odl_api_ips) {
+      fail('No IPs assigned to OpenDaylight Api Service')
+    } elsif size($odl_api_ips) == 2 {
+      fail('2 node OpenDaylight deployments are unsupported.  Use 1 or greater than 2')
+    } elsif size($odl_api_ips) > 2 {
+      $node_string = split($node_name, '-')
+      $ha_node_index = $node_string[-1] + 1
+      class { '::opendaylight':
+        enable_ha     => true,
+        ha_node_ips   => $odl_api_ips,
+        ha_node_index => $ha_node_index,
+      }
+    } else {
       include ::opendaylight
     }
   }
index c120931..2618d4f 100644 (file)
 #   (Optional) Password to configure for OpenDaylight
 #   Defaults to 'admin'
 #
+# [*odl_url_ip*]
+#   (Optional) Virtual IP address for ODL Api Service
+#   Defaults to hiera('opendaylight_api_vip')
+#
 # [*conn_proto*]
 #   (Optional) Protocol to use to for ODL REST access
 #   Defaults to hiera('opendaylight::nb_connection_protocol')
@@ -43,14 +47,13 @@ class tripleo::profile::base::neutron::plugins::ml2::opendaylight (
   $odl_port     = hiera('opendaylight::odl_rest_port'),
   $odl_username = hiera('opendaylight::username'),
   $odl_password = hiera('opendaylight::password'),
+  $odl_url_ip   = hiera('opendaylight_api_vip'),
   $conn_proto   = hiera('opendaylight::nb_connection_protocol'),
   $step         = hiera('step'),
 ) {
 
   if $step >= 4 {
-    $odl_url_ip = hiera('opendaylight_api_vip')
-
-    if ! $odl_url_ip { fail('OpenDaylight Controller IP/VIP is Empty') }
+    if ! $odl_url_ip { fail('OpenDaylight API VIP is Empty') }
 
     class { '::neutron::plugins::ml2::opendaylight':
       odl_username => $odl_username,
index 91c5168..4da8df9 100644 (file)
 #   (Optional) List of OpenStack Controller IPs for ODL API
 #   Defaults to hiera('opendaylight_api_node_ips')
 #
+# [*odl_url_ip*]
+#   (Optional) Virtual IP address for ODL Api Service
+#   Defaults to hiera('opendaylight_api_vip')
+#
 # [*conn_proto*]
 #   (Optional) Protocol to use to for ODL REST access
 #   Defaults to hiera('opendaylight::nb_connection_protocol')
@@ -43,25 +47,25 @@ class tripleo::profile::base::neutron::plugins::ovs::opendaylight (
   $odl_port      = hiera('opendaylight::odl_rest_port'),
   $odl_check_url = hiera('opendaylight_check_url'),
   $odl_api_ips   = hiera('opendaylight_api_node_ips'),
+  $odl_url_ip    = hiera('opendaylight_api_vip'),
   $conn_proto    = hiera('opendaylight::nb_connection_protocol'),
   $step          = hiera('step'),
 ) {
 
   if $step >= 4 {
-    $opendaylight_controller_ip = $odl_api_ips[0]
-    $odl_url_ip = hiera('opendaylight_api_vip')
-
-    if ! $opendaylight_controller_ip { fail('OpenDaylight Controller IP is Empty') }
+    if empty($odl_api_ips) { fail('No IPs assigned to OpenDaylight Api Service') }
 
     if ! $odl_url_ip { fail('OpenDaylight API VIP is Empty') }
 
     # Build URL to check if ODL is up before connecting OVS
     $opendaylight_url = "${conn_proto}://${odl_url_ip}:${odl_port}/${odl_check_url}"
 
+    $odl_ovsdb_str = join(regsubst($odl_api_ips, '.+', 'tcp:\0:6640'), ' ')
+
     class { '::neutron::plugins::ovs::opendaylight':
       tunnel_ip       => hiera('neutron::agents::ml2::ovs::local_ip'),
       odl_check_url   => $opendaylight_url,
-      odl_ovsdb_iface => "tcp:${opendaylight_controller_ip}:6640",
+      odl_ovsdb_iface => $odl_ovsdb_str,
     }
   }
 }
diff --git a/releasenotes/notes/add-opendaylight-ha-47a40c03917faf9c.yaml b/releasenotes/notes/add-opendaylight-ha-47a40c03917faf9c.yaml
new file mode 100644 (file)
index 0000000..e0a6d35
--- /dev/null
@@ -0,0 +1,5 @@
+---
+features:
+  - Adds OpenDaylight HA support.  Now when ODL is applied to three or
+    more nodes ODL will be deployed as a cluster in HA, rather than
+    the previous behavior of only running on the first node.
diff --git a/spec/classes/tripleo_profile_base_neutron_opendaylight_spec.rb b/spec/classes/tripleo_profile_base_neutron_opendaylight_spec.rb
new file mode 100644 (file)
index 0000000..1eb79ae
--- /dev/null
@@ -0,0 +1,88 @@
+#
+# 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::opendaylight' do
+  let :params do
+    { :step                    => 1,
+      :node_name   => 'overcloud-controller-0',
+    }
+  end
+  shared_examples_for 'tripleo::profile::base::neutron::opendaylight' do
+    before :each do
+      facts.merge!({ :step => params[:step] })
+    end
+
+    context 'with noha' do
+      before do
+        params.merge!({
+          :odl_api_ips => ['192.0.2.5']
+        })
+      end
+      it 'should install and configure opendaylight' do
+        is_expected.to contain_class('opendaylight')
+      end
+    end
+
+    context 'with empty OpenDaylight API IPs' do
+      before do
+        params.merge!({
+          :odl_api_ips => []
+        })
+      end
+      it 'should fail to install OpenDaylight' do
+        is_expected.to compile.and_raise_error(/No IPs assigned to OpenDaylight Api Service/)
+      end
+    end
+
+    context 'with 2 OpenDaylight API IPs' do
+      before do
+        params.merge!({
+          :odl_api_ips => ['192.0.2.5', '192.0.2.6']
+        })
+      end
+      it 'should fail to install OpenDaylight' do
+        is_expected.to compile.and_raise_error(/2 node OpenDaylight deployments are unsupported.  Use 1 or greater than 2/)
+      end
+    end
+
+    context 'with HA and 3 OpenDaylight API IPs' do
+      before do
+        params.merge!({
+          :odl_api_ips => ['192.0.2.5', '192.0.2.6', '192.0.2.7']
+        })
+      end
+      it 'should install and configure OpenDaylight in HA' do
+        is_expected.to contain_class('opendaylight').with(
+          :enable_ha     => true,
+          :ha_node_ips   => params[:odl_api_ips],
+          :ha_node_index => '1',
+        )
+      end
+    end
+  end
+
+  on_supported_os.each do |os, facts|
+    context "on #{os}" do
+      let(:facts) do
+        facts.merge({ :hostname => 'node.example.com' })
+      end
+
+      it_behaves_like 'tripleo::profile::base::neutron::opendaylight'
+    end
+  end
+end