Create a Mesh of qdrouterd links for messaging high availability
authorJohn Eckersberg <jeckersb@redhat.com>
Tue, 21 Mar 2017 14:05:17 +0000 (10:05 -0400)
committerAndrew Smith <ansmith@redhat.com>
Sun, 16 Jul 2017 23:57:04 +0000 (19:57 -0400)
For multi-node deployments of the dispatch router, a mesh of
inter-router links is created. Note that bi-directional links must
not be configured.

Example: For nodes A, B, C
  Node    Inter-Router Link
   A:           []
   B:           [A]
   C:           [A,B]

Change-Id: If43beea7a53c1f8f1dff062341c7ea81751c3122

manifests/profile/base/qdr.pp
spec/classes/tripleo_profile_base_qdr_spec.rb [new file with mode: 0644]

index 37cf9e5..577f3d5 100644 (file)
 # === Parameters
 #
 # [*qdr_username*]
-#   Username for the qrouter daemon
+#   Username for the qdrouter daemon
 #   Defaults to undef
 #
 # [*qdr_password*]
-#   Password for the qrouter daemon
+#   Password for the qdrouter daemon
 #   Defaults to undef
 #
 # [*qdr_listener_port*]
-#   Port for the listener (not that we do not use qdr::listener_port
+#   Port for the listener (note that we do not use qdr::listener_port
 #   directly because it requires a string and we have a number.
 #   Defaults to hiera('tripleo::profile::base::qdr::qdr_listener_port', 5672)
 #
+# [*qdr_node_names*]
+#   Set of nodes for qdr mesh deployment setup
+#   Defaults to hiera('rabbitmq_node_names')
+#
 # [*step*]
 #   (Optional) The current step in deployment. See tripleo-heat-templates
 #   for more details.
@@ -41,11 +45,69 @@ class tripleo::profile::base::qdr (
   $qdr_password      = undef,
   $qdr_listener_port = hiera('tripleo::profile::base::qdr::qdr_listener_port', 5672),
   $step              = Integer(hiera('step')),
+  $qdr_node_names    = pick(hiera('qdr_node_names',undef),hiera('rabbitmq_node_names')),
 ) {
   if $step >= 1 {
+    # For multi-node deployments of the dispatch router, a mesh of
+    # inter-router links is created. Bi-directional links must
+    # not be configured.
+    #
+    # Example: For nodes A, B, C
+    #    Node      Inter-Router Link
+    #     A:             []
+    #     B:             [A]
+    #     C:             [A,B]
+    #
+    # NB: puppet 4.8 introduces break(), which would be favord to
+    # the following
+    $connectors = $qdr_node_names.reduce([]) |$memo, $node| {
+      if $::hostname in $node {
+        $memo + true
+      } else {
+        if true in $memo {
+          $memo
+        } else {
+          $memo + [{'host' => $node,
+                    'role' => 'inter-router',
+                    'port' => '25672'}]
+        }
+      }
+    } - true
+
+    $router_mode = size($qdr_node_names) ? {
+      1       => 'standalone',
+      default => 'interior',
+    }
+
+    $extra_listeners = size($qdr_node_names) ? {
+      1       => [],
+      default => [{'host' => '0.0.0.0',
+                  'port' => '25672',
+                  'role' => 'inter-router'}],
+    }
+
+    $extra_addresses = [{'prefix'       => 'openstack.org/om/rpc/multicast',
+                        'distribution' => 'multicast'},
+                        {'prefix'       => 'openstack.org/om/rpc/unicast',
+                        'distribution' => 'closest'},
+                        {'prefix'       => 'openstack.org/om/rpc/anycast',
+                        'distribution' => 'balanced'},
+                        {'prefix'       => 'openstack.org/om/notify/multicast',
+                        'distribution' => 'multicast'},
+                        {'prefix'       => 'openstack.org/om/notify/unicast',
+                        'distribution' => 'closest'},
+                        {'prefix'       => 'openstack.org/om/notify/anycast',
+                        'distribution' => 'balanced'}]
+
     class { '::qdr':
-      listener_port => "${qdr_listener_port}",
-    } ->
+      listener_addr   => '0.0.0.0',
+      listener_port   => "${qdr_listener_port}",
+      router_mode     => $router_mode,
+      connectors      => $connectors,
+      extra_listeners => $extra_listeners,
+      extra_addresses => $extra_addresses,
+    }
+
     qdr_user { $qdr_username:
       ensure   => present,
       password => $qdr_password,
diff --git a/spec/classes/tripleo_profile_base_qdr_spec.rb b/spec/classes/tripleo_profile_base_qdr_spec.rb
new file mode 100644 (file)
index 0000000..550f5be
--- /dev/null
@@ -0,0 +1,119 @@
+#
+# 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::qdr' do
+
+  let :params do
+    {
+      :step => 3,
+      :qdr_username   => 'openstack',
+      :qdr_password   => 'bigsecret',
+    }
+  end
+
+  shared_examples_for 'tripleo::profile::base::qdr' do
+
+    context 'with step 3 on single node' do
+      before do
+        facts.merge!({
+          :hostname => 'node.example.com',
+        })
+        params.merge!({
+          :qdr_node_names => ['node.example.com'],
+        })
+      end
+
+      it 'should setup standalone' do
+        is_expected.to contain_class('qdr').with(
+          :router_mode     => 'standalone',
+          :extra_listeners => [],
+          :connectors => [],
+        )
+      end
+    end
+
+    context 'with step 3 on node1 of multinode' do
+      before do
+        facts.merge!({
+          :hostname => 'node1.example.com',
+        })
+        params.merge!({
+          :qdr_node_names => ['node1.example.com','node2.example.com','node3.example.com'],
+        })
+      end
+
+      it 'should set interior listener and no connectors' do
+        is_expected.to contain_class('qdr').with(
+          :router_mode     => 'interior',
+          :extra_listeners => [{'host' => '0.0.0.0','port' => '25672','role' => 'inter-router'}],
+          :connectors => [],
+        )
+      end
+    end
+
+    context 'with step 3 on node2 of multinode' do
+      before do
+        facts.merge!({
+          :hostname => 'node2.example.com',
+        })
+        params.merge!({
+          :qdr_node_names => ['node1.example.com','node2.example.com','node3.example.com'],
+        })
+      end
+
+      it 'should set up interior listener and one connector' do
+        is_expected.to contain_class('qdr').with(
+          :router_mode     => 'interior',
+          :extra_listeners => [{'host' => '0.0.0.0','port' => '25672','role' => 'inter-router'}],
+          :connectors => [{"host"=>"node1.example.com", "role"=>"inter-router", "port"=>"25672"}],
+        )
+      end
+    end
+
+    context 'with step 3 on node3 of multinode' do
+      before do
+        facts.merge!({
+          :hostname => 'node3.example.com',
+        })
+        params.merge!({
+          :qdr_node_names => ['node1.example.com','node2.example.com','node3.example.com'],
+        })
+      end
+
+      it 'should set up interior listener and two connectors' do
+        is_expected.to contain_class('qdr').with(
+          :router_mode     => 'interior',
+          :extra_listeners => [{'host' => '0.0.0.0','port' => '25672','role' => 'inter-router'}],
+          :connectors => [
+            {"host"=>"node1.example.com", "role"=>"inter-router", "port"=>"25672"},
+            {"host"=>"node2.example.com", "role"=>"inter-router", "port"=>"25672"}],
+        )
+      end
+    end
+  end
+
+  on_supported_os.each do |os, facts|
+    context "on #{os}" do
+      let(:facts) do
+        facts.merge({ })
+      end
+
+      it_behaves_like 'tripleo::profile::base::qdr'
+    end
+  end
+end