From b9e1243d7d206588cf712751980a38f1902725c8 Mon Sep 17 00:00:00 2001
From: Mark Goddard <mark@stackhpc.com>
Date: Thu, 3 Aug 2017 15:11:44 +0100
Subject: [PATCH] Add support for configuration of Juniper switches

Support for Juniper switches is added via the Ansible junos_* modules.
This affects the following command:

kayobe physical network configure
---
 ansible/group_vars/switches/junos             | 12 +++
 ansible/physical-network.yml                  | 13 ++++
 ansible/roles/juniper-switch/README.md        | 76 +++++++++++++++++++
 .../roles/juniper-switch/defaults/main.yml    | 14 ++++
 ansible/roles/juniper-switch/tasks/main.yml   |  6 ++
 .../juniper-switch/templates/junos-config.j2  | 18 +++++
 6 files changed, 139 insertions(+)
 create mode 100644 ansible/group_vars/switches/junos
 create mode 100644 ansible/roles/juniper-switch/README.md
 create mode 100644 ansible/roles/juniper-switch/defaults/main.yml
 create mode 100644 ansible/roles/juniper-switch/tasks/main.yml
 create mode 100644 ansible/roles/juniper-switch/templates/junos-config.j2

diff --git a/ansible/group_vars/switches/junos b/ansible/group_vars/switches/junos
new file mode 100644
index 000000000..ad2df5672
--- /dev/null
+++ b/ansible/group_vars/switches/junos
@@ -0,0 +1,12 @@
+---
+# Switch configuration.
+
+###############################################################################
+# Authentication configuration.
+
+# For Juniper switches, this defines a 'provider' argument to the junos_*
+# modules.
+switch_junos_provider:
+  host: "{{ ansible_host }}"
+  username: "{{ ansible_user }}"
+  password: "{{ ansible_ssh_pass }}"
diff --git a/ansible/physical-network.yml b/ansible/physical-network.yml
index 928339b76..0f5c98719 100644
--- a/ansible/physical-network.yml
+++ b/ansible/physical-network.yml
@@ -31,3 +31,16 @@
       dell_switch_provider: "{{ switch_dellos_provider }}"
       dell_switch_config: "{{ switch_config }}"
       dell_switch_interface_config: "{{ switch_interface_config }}"
+
+- name: Ensure Juniper physical switches are configured
+  hosts: switches_of_type_junos
+  gather_facts: no
+  roles:
+    - role: ssh-known-host
+
+    - role: juniper-switch
+      juniper_switch_delegate_to: localhost
+      juniper_switch_type: "{{ switch_type }}"
+      juniper_switch_provider: "{{ switch_juniper_provider }}"
+      juniper_switch_config: "{{ switch_config }}"
+      juniper_switch_interface_config: "{{ switch_interface_config }}"
diff --git a/ansible/roles/juniper-switch/README.md b/ansible/roles/juniper-switch/README.md
new file mode 100644
index 000000000..aa94ff4bd
--- /dev/null
+++ b/ansible/roles/juniper-switch/README.md
@@ -0,0 +1,76 @@
+Juniper Switch
+==============
+
+This role configures Juniper switches using the `junos` Ansible modules.  It
+provides a fairly minimal abstraction of the configuration interface provided
+by the `junos` modules, allowing for application of arbitrary switch
+configuration options.
+
+Requirements
+------------
+
+The switches should be configured to allow SSH access.
+
+Role Variables
+--------------
+
+`juniper_switch_delegate_to` is the host on which to execute the `junos` Ansible
+modules.
+
+`juniper_switch_provider` is authentication provider information passed as the
+`provider` argument to the `junos` modules.
+
+`juniper_switch_config` is a list of configuration lines to apply to the switch,
+and defaults to an empty list.
+
+`juniper_switch_interface_config` contains interface configuration. It is a dict
+mapping switch interface names to configuration dicts. Each dict may contain
+the following items:
+
+- `description` - a description to apply to the interface.
+- `config` - a list of per-interface configuration.
+
+Dependencies
+------------
+
+None
+
+Example Playbook
+----------------
+
+The following playbook configures hosts in the `junos-switches` group.
+It assumes host variables for each switch holding the host, username and
+passwords.  It applies global configuration for LLDP, and enables two
+10G ethernet interfaces.
+
+    ---
+    - name: Ensure Junos switches are configured
+      hosts: junos-switches
+      gather_facts: no
+      roles:
+        - role: juniper-switch
+          juniper_switch_delegate_to: localhost
+          juniper_switch_provider:
+            host: "{{ switch_host }}"
+            username: "{{ switch_user }}"
+            password: "{{ switch_password }}"
+          juniper_switch_config:
+            - "protocols {"
+            - "    lldp {"
+            - "        interface all;"
+            - "    }"
+            - "}"
+          juniper_switch_interface_config:
+            xe-1/1/1:
+              description: server-1
+              config:
+                - "enable"
+            xe-1/1/2:
+              description: server-2
+              config:
+                - "enable"
+
+Author Information
+------------------
+
+- Mark Goddard (<mark@stackhpc.com>)
diff --git a/ansible/roles/juniper-switch/defaults/main.yml b/ansible/roles/juniper-switch/defaults/main.yml
new file mode 100644
index 000000000..ca3990b0f
--- /dev/null
+++ b/ansible/roles/juniper-switch/defaults/main.yml
@@ -0,0 +1,14 @@
+---
+# Host on which to execute Junos Ansible modules.
+junos_switch_delegate_to:
+
+# Authentication provider information.
+junos_switch_provider:
+
+# List of configuration lines to apply to the switch.
+junos_switch_config: []
+
+# Interface configuration. Dict mapping switch interface names to configuration
+# dicts. Each dict contains a 'description' item and a 'config' item which
+# should contain a list of per-interface configuration.
+junos_switch_interface_config: {}
diff --git a/ansible/roles/juniper-switch/tasks/main.yml b/ansible/roles/juniper-switch/tasks/main.yml
new file mode 100644
index 000000000..c828363be
--- /dev/null
+++ b/ansible/roles/juniper-switch/tasks/main.yml
@@ -0,0 +1,6 @@
+---
+- name: Ensure Juniper switches are configured
+  junos_config:
+    provider: "{{ juniper_switch_provider }}"
+    src: junos-config.j2
+  delegate_to: "{{ juniper_switch_delegate_to }}"
diff --git a/ansible/roles/juniper-switch/templates/junos-config.j2 b/ansible/roles/juniper-switch/templates/junos-config.j2
new file mode 100644
index 000000000..82c6da51f
--- /dev/null
+++ b/ansible/roles/juniper-switch/templates/junos-config.j2
@@ -0,0 +1,18 @@
+#jinja2: trim_blocks: True,lstrip_blocks: True
+
+{% for line in juniper_switch_config %}
+{{ line }}
+{% endfor %}
+
+interfaces {
+{% for interface, config in juniper_switch_interface_config.items() %}
+    {{ interface }} {
+{% if config.description is defined %}
+        description "{{ config.description }}";
+{% endif %}
+{% for line in config.config %}
+{{ line }}
+{% endfor %}
+    }
+{% endfor %}
+}