From 1ee19568b04d71ffaa97aef682ad1bcbc4f6fd23 Mon Sep 17 00:00:00 2001
From: Pierre Riteau <pierre@stackhpc.com>
Date: Tue, 3 Mar 2020 20:46:32 +0000
Subject: [PATCH] Add support for configuring Cumulus switches with NCLU

This extends the physical network configuration in Kayobe to configure
Cumulus physical switches using the nclu Ansible module.

Change-Id: I960027ead301c5793a0ada1959a23549a71bdbfb
---
 ansible/physical-network.yml                  | 11 +++
 ansible/roles/nclu-switch/README.md           | 75 +++++++++++++++++++
 ansible/roles/nclu-switch/defaults/main.yml   |  9 +++
 ansible/roles/nclu-switch/tasks/main.yml      |  5 ++
 .../nclu-switch/templates/nclu-config.j2      | 13 ++++
 doc/source/configuration/physical-network.rst | 21 +++++-
 .../cumulus-switch-baf554118ef23afe.yaml      |  7 ++
 7 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 ansible/roles/nclu-switch/README.md
 create mode 100644 ansible/roles/nclu-switch/defaults/main.yml
 create mode 100644 ansible/roles/nclu-switch/tasks/main.yml
 create mode 100644 ansible/roles/nclu-switch/templates/nclu-config.j2
 create mode 100644 releasenotes/notes/cumulus-switch-baf554118ef23afe.yaml

diff --git a/ansible/physical-network.yml b/ansible/physical-network.yml
index ec038faa..4c65abb0 100644
--- a/ansible/physical-network.yml
+++ b/ansible/physical-network.yml
@@ -30,6 +30,7 @@
       - dell-powerconnect
       - junos
       - mellanox
+      - nclu
       - openvswitch
   tasks:
     - name: Fail if both interface name and description limits are specified
@@ -155,3 +156,13 @@
       mellanox_switch_provider: "{{ switch_mellanox_provider }}"
       mellanox_switch_config: "{{ switch_config }}"
       mellanox_switch_interface_config: "{{ switch_interface_config }}"
+
+- name: Ensure Cumulus physical switches are configured with NCLU
+  hosts: switches_of_type_nclu:&switches_in_display_mode_False
+  gather_facts: no
+  roles:
+    - role: ssh-known-host
+
+    - role: nclu-switch
+      nclu_switch_config: "{{ switch_config }}"
+      nclu_switch_interface_config: "{{ switch_interface_config }}"
diff --git a/ansible/roles/nclu-switch/README.md b/ansible/roles/nclu-switch/README.md
new file mode 100644
index 00000000..0a6c9086
--- /dev/null
+++ b/ansible/roles/nclu-switch/README.md
@@ -0,0 +1,75 @@
+NCLU Switch
+===========
+
+This role configures Cumulus switches using the `nclu` Ansible module. It
+provides a fairly minimal abstraction of the configuration interface provided
+by the `nclu` module, allowing for application of arbitrary switch
+configuration options.
+
+Requirements
+------------
+
+The switches should be configured to allow SSH access.
+
+Role Variables
+--------------
+
+`nclu_switch_config` is a list of NCLU commands to apply to the switch, and
+defaults to an empty list. Commands must be formatted without the `net` prefix,
+which is added by the `nclu` module before execution on the switch.
+
+`nclu_switch_interface_config` contains interface configuration. It is a dict
+mapping switch interface names to configuration dicts. Interfaces can be switch
+physical interfaces, but also special interfaces such as bridges or bonds. Each
+dict may contain the following items:
+
+- `description` - a description to apply to the interface.
+- `config` - a list of per-interface configuration, each applied with a `net
+  add <type> <interface-name>` prefix.
+- `type` - type of interface, e.g. `bond` or `bridge`. If this field is absent,
+  the `interface` keyword is used.
+
+Dependencies
+------------
+
+None
+
+Example Playbook
+----------------
+
+The following playbook configures hosts in the `nclu-switches` group. It
+applies global configuration to configure a BGP AS and add two EBGP neighbors
+using BGP Unnumbered, enables two host interfaces with jumbo frames, and
+attaches them to a traditional bridge called `bridge1` configured with an IP
+address.
+
+    ---
+    - name: Ensure Cumulus switches are configured with NCLU
+      hosts: nclu-switches
+      gather_facts: no
+      roles:
+        - role: nclu-switch
+          nclu_switch_config:
+            - "add bgp autonomous-system 65000"
+            - "add bgp neighbor swp51 interface remote-as external"
+            - "add bgp neighbor swp52 interface remote-as external"
+          nclu_switch_interface_config:
+            swp1:
+              description: server1
+              config:
+                - "mtu 9000"
+            swp2:
+              description: server2
+              config:
+                - "mtu 9000"
+            bridge1:
+              type: bridge
+              config:
+                - "ip address 10.100.100.1/24"
+                - "ports swp1"
+                - "ports swp2"
+
+Author Information
+------------------
+
+- Pierre Riteau (<pierre@stackhpc.com>)
diff --git a/ansible/roles/nclu-switch/defaults/main.yml b/ansible/roles/nclu-switch/defaults/main.yml
new file mode 100644
index 00000000..d826d8af
--- /dev/null
+++ b/ansible/roles/nclu-switch/defaults/main.yml
@@ -0,0 +1,9 @@
+---
+# List of configuration lines to apply to the switch.
+nclu_switch_config: []
+
+# Interface configuration. Dict mapping switch interface names to configuration
+# dicts. Each dict contains a 'description' item, an optional 'type' item
+# (default is 'interface'), and a 'config' item which should contain a list of
+# per-interface configuration.
+nclu_switch_interface_config: {}
diff --git a/ansible/roles/nclu-switch/tasks/main.yml b/ansible/roles/nclu-switch/tasks/main.yml
new file mode 100644
index 00000000..6c336f39
--- /dev/null
+++ b/ansible/roles/nclu-switch/tasks/main.yml
@@ -0,0 +1,5 @@
+---
+- name: Ensure Cumulus switches are configured with NCLU
+  nclu:
+    template: "{{ lookup('template', 'nclu-config.j2') }}"
+    atomic: true
diff --git a/ansible/roles/nclu-switch/templates/nclu-config.j2 b/ansible/roles/nclu-switch/templates/nclu-config.j2
new file mode 100644
index 00000000..8177e892
--- /dev/null
+++ b/ansible/roles/nclu-switch/templates/nclu-config.j2
@@ -0,0 +1,13 @@
+#jinja2: trim_blocks: True,lstrip_blocks: True
+{% for line in nclu_switch_config %}
+{{ line }}
+{% endfor %}
+
+{% for interface, config in nclu_switch_interface_config.items() %}
+{% if config.description is defined %}
+add {{ config.type | default("interface") }} {{ interface }} alias {{ config.description }}
+{% endif %}
+{% for line in config.config %}
+add {{ config.type | default("interface") }} {{ interface }} {{ line }}
+{% endfor %}
+{% endfor %}
diff --git a/doc/source/configuration/physical-network.rst b/doc/source/configuration/physical-network.rst
index f21d62dd..6e27d950 100644
--- a/doc/source/configuration/physical-network.rst
+++ b/doc/source/configuration/physical-network.rst
@@ -12,8 +12,10 @@ Devices are added to the Ansible inventory, and configured using Ansible's
 networking modules.  Configuration is applied via the ``kayobe physical network
 configure`` command.  See :ref:`physical-network` for details.
 
-The following switches are currently supported:
+The following switch operating systems are currently supported:
 
+* Cumulus Linux (via `Network Command Line Utility (NCLU)
+  <https://docs.cumulusnetworks.com/display/DOCS/Network+Command+Line+Utility+-+NCLU>`__)
 * Dell OS 6
 * Dell OS 9
 * Dell PowerConnect
@@ -173,6 +175,23 @@ example:
 Device-specific Configuration Variables
 =======================================
 
+Cumulus Linux (with NCLU)
+-------------------------
+
+Configuration for these devices is applied using the ``nclu`` Ansible module.
+
+``switch_type`` should be set to ``nclu``.
+
+SSH configuration
+^^^^^^^^^^^^^^^^^
+
+As with any non-switch host in the inventory, the ``nclu`` module relies on the
+default connection parameters used by Ansible:
+
+* ``ansible_host`` is the hostname or IP address.  Optional.
+
+* ``ansible_user`` is the SSH username.
+
 Dell OS6 and OS9
 ----------------
 
diff --git a/releasenotes/notes/cumulus-switch-baf554118ef23afe.yaml b/releasenotes/notes/cumulus-switch-baf554118ef23afe.yaml
new file mode 100644
index 00000000..08a6a7fb
--- /dev/null
+++ b/releasenotes/notes/cumulus-switch-baf554118ef23afe.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Adds support for configuring Cumulus switches using the `Network Command
+    Line Utility (NCLU)
+    <https://docs.cumulusnetworks.com/display/DOCS/Network+Command+Line+Utility+-+NCLU>`__.
+    This is integrated with the ``kayobe physical network configure`` command.
-- 
GitLab