From 724f78527abda3e41bcab7084d55f4c39e25374a Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Wed, 30 Oct 2024 11:01:06 +0000
Subject: [PATCH 01/46] Add geant_ip and fw_filters roles

---
 .../playbooks/manage_geant_ip.yaml            |   5 +
 geant/gap_ansible/roles/fw_filters/README.md  |  38 +++
 .../roles/fw_filters/defaults/main.yml        |   2 +
 .../roles/fw_filters/handlers/main.yml        |   2 +
 .../roles/fw_filters/meta/main.yml            |  34 +++
 .../roles/fw_filters/tasks/compile.yaml       |  24 ++
 .../roles/fw_filters/tasks/main.yml           |   4 +
 .../templates/filters/cpm_filters.j2          |  12 +
 .../templates/filters/fw_filters.j2           | 273 ++++++++++++++++++
 .../templates/filters/gen_filters.j2          |  16 +
 .../filters/port_list_definitions.j2          |  66 +++++
 .../templates/filters/port_list_entries.j2    |  48 +++
 .../filters/protocol_list_definitions.j2      |  19 ++
 .../roles/fw_filters/vars/main.yml            |   2 +
 geant/gap_ansible/roles/geant_ip/README.md    |  38 +++
 .../roles/geant_ip/defaults/main.yml          |   2 +
 .../roles/geant_ip/handlers/main.yml          |   2 +
 .../gap_ansible/roles/geant_ip/meta/main.yml  |  38 +++
 .../roles/geant_ip/tasks/compile.yaml         |  24 ++
 .../gap_ansible/roles/geant_ip/tasks/main.yml |  23 ++
 .../roles/geant_ip/tasks/standard_tasks.yaml  |  44 +++
 .../geant_ip/templates/nokia/l3/deploy_sbp.j2 |  48 +++
 .../gap_ansible/roles/geant_ip/vars/main.yml  |  15 +
 23 files changed, 779 insertions(+)
 create mode 100644 geant/gap_ansible/playbooks/manage_geant_ip.yaml
 create mode 100644 geant/gap_ansible/roles/fw_filters/README.md
 create mode 100644 geant/gap_ansible/roles/fw_filters/defaults/main.yml
 create mode 100644 geant/gap_ansible/roles/fw_filters/handlers/main.yml
 create mode 100644 geant/gap_ansible/roles/fw_filters/meta/main.yml
 create mode 100644 geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
 create mode 100644 geant/gap_ansible/roles/fw_filters/tasks/main.yml
 create mode 100644 geant/gap_ansible/roles/fw_filters/templates/filters/cpm_filters.j2
 create mode 100644 geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
 create mode 100644 geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
 create mode 100644 geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
 create mode 100644 geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
 create mode 100644 geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
 create mode 100644 geant/gap_ansible/roles/fw_filters/vars/main.yml
 create mode 100644 geant/gap_ansible/roles/geant_ip/README.md
 create mode 100644 geant/gap_ansible/roles/geant_ip/defaults/main.yml
 create mode 100644 geant/gap_ansible/roles/geant_ip/handlers/main.yml
 create mode 100644 geant/gap_ansible/roles/geant_ip/meta/main.yml
 create mode 100644 geant/gap_ansible/roles/geant_ip/tasks/compile.yaml
 create mode 100644 geant/gap_ansible/roles/geant_ip/tasks/main.yml
 create mode 100644 geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml
 create mode 100644 geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2
 create mode 100644 geant/gap_ansible/roles/geant_ip/vars/main.yml

diff --git a/geant/gap_ansible/playbooks/manage_geant_ip.yaml b/geant/gap_ansible/playbooks/manage_geant_ip.yaml
new file mode 100644
index 00000000..eaa05b1b
--- /dev/null
+++ b/geant/gap_ansible/playbooks/manage_geant_ip.yaml
@@ -0,0 +1,5 @@
+- name: Manage GEANT IP instance
+  hosts: all
+  gather_facts: false
+  roles:
+    - ../roles/geant_ip
diff --git a/geant/gap_ansible/roles/fw_filters/README.md b/geant/gap_ansible/roles/fw_filters/README.md
new file mode 100644
index 00000000..225dd44b
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/fw_filters/defaults/main.yml b/geant/gap_ansible/roles/fw_filters/defaults/main.yml
new file mode 100644
index 00000000..79fb8886
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for fw_filters
diff --git a/geant/gap_ansible/roles/fw_filters/handlers/main.yml b/geant/gap_ansible/roles/fw_filters/handlers/main.yml
new file mode 100644
index 00000000..5d927097
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for fw_filters
diff --git a/geant/gap_ansible/roles/fw_filters/meta/main.yml b/geant/gap_ansible/roles/fw_filters/meta/main.yml
new file mode 100644
index 00000000..ea68190c
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/meta/main.yml
@@ -0,0 +1,34 @@
+galaxy_info:
+  author: your name
+  description: your role description
+  company: your company (optional)
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: license (GPL-2.0-or-later, MIT, etc)
+
+  min_ansible_version: 2.1
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  galaxy_tags: []
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
new file mode 100644
index 00000000..d6ee0f6c
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
@@ -0,0 +1,24 @@
+---
+- name: Set ansible host to localhost to compile config when router is offline
+  when:
+    item.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Create a folder for all the things
+  ansible.builtin.file:
+    path: "/var/tmp/ansible_run_{{ opid }}"
+    state: directory
+    mode: '0755'
+  delegate_to: localhost
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/gen_filters.conf"
+  when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "filters/gen_filters.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/gen_filters.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/main.yml b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
new file mode 100644
index 00000000..6e818e84
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
@@ -0,0 +1,4 @@
+---
+# tasks file for fw_filters
+- name: Include filter compilation
+  ansible.builtin.include_tasks: compile.yaml
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/cpm_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/cpm_filters.j2
new file mode 100644
index 00000000..f7a35874
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/cpm_filters.j2
@@ -0,0 +1,12 @@
+{% with is_cpm_filter=true, filters=cpm_filters %}
+{% include "filters/port_list_definitions.j2" %}
+
+<system>
+  <security>
+    <cpm-filter xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+      <default-action>{{ cpm_filter_policy.default_action }}</default-action>
+        {% include "filters/fw_filters.j2" %}
+    </cpm-filter>
+{% endwith %}
+  </security>
+</system>
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
new file mode 100644
index 00000000..29383100
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
@@ -0,0 +1,273 @@
+{# Template is meant to be called from either gen_filters.j2 or cmp_filters.j2 #}
+{% for filter in filters %}
+  {% if filter.family == "ipv4" %}
+        <ip-filter alu:operation="replace">
+  {% elif filter.family == "ipv6" %}
+        <ipv6-filter alu:operation="replace">
+  {% endif %}
+  {% if not is_cpm_filter %}
+        <filter-name>{{ filter.name }}</filter-name>
+      {% if filter.scope is defined %}
+        <scope>{{ filter.scope }}</scope>
+      {% endif %}
+      {% if filter.default_action is defined %}
+        <default-action>{{ filter.default_action }}</default-action>
+      {% endif %}
+  {% endif %}
+  {% if filter.offset is defined %}
+    {% set ns3 = namespace(entry_id = filter.offset | int) %}
+  {% else %}
+    {% set ns3 = namespace(entry_id = 10 | int) %}
+  {% endif %}
+  {% if is_cpm_filter %}
+        <admin-state>{{ filter.admin_state }}</admin-state>
+  {% endif %}
+  {% for term in filter.terms %}
+    {% if term.offset is defined %}
+      {% set ns3 = namespace(entry_id = term.offset | int) %}
+    {% endif %}
+    {% if term.from is not defined %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <action>
+                <{{term.action}}></{{term.action}}>
+            </action>
+          </entry>
+    {% endif %}
+
+    {% if term.from is defined %}
+      {# Special cases where from.protocol is defined #}
+      {% if term.from.protocol is defined %}
+        {# This is the case for TCP_ESTABLISHED #}
+        {% if term.from.protocol == "tcp" and term.from.tcp_flag is defined %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+              {% if filter.family == "ipv4" %}
+              <protocol>{{ term.from.protocol }}</protocol>
+              {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+              {% endif %}
+              <tcp-flags>
+                <{{ term.from.tcp_flag }}>true</{{ term.from.tcp_flag }}>
+              </tcp-flags>
+            </match>
+            <action>
+              <{{ term.action }}></{{ term.action }}>
+            </action>
+          </entry>
+          {% set ns3.entry_id = ns3.entry_id + 10 %}
+        {% endif %}
+        {# Generic ICMP filters with ICMP types #}
+        {% if (term.from.protocol == "icmp" or term.from.protocol == "ipv6-icmp") %}
+          {% if term.from.icmp_types is defined %}
+            {% for icmp_type in term.from.icmp_types %}
+            <entry>
+              <entry-id>{{ ns3.entry_id }}</entry-id>
+              <description>{{ term.name }}</description>
+              {% if term.log is defined %}
+              <log>{{ term.log }}</log>
+              {% endif %}
+              <match>
+                    {% if filter.family == "ipv4" %}
+                <protocol>{{ term.from.protocol }}</protocol>
+                    {% else %}
+                <next-header>{{ term.from.protocol }}</next-header>
+                    {% endif %}
+                  <icmp>
+                    <type>{{ icmp_type }}</type>
+                  </icmp>
+              </match>
+              <action>
+                <{{ term.action }}></{{ term.action }}>
+              </action>
+            </entry>
+          {% set ns3.entry_id = ns3.entry_id + 10 %}
+            {% endfor %}
+          {% endif %}
+        {% endif %}
+        {# Case when only need to match on protocol, e.g. PIM #}
+        {% if term.from.protocol in ['pim', '58'] %}
+            <entry>
+              <entry-id>{{ ns3.entry_id }}</entry-id>
+              <description>{{ term.name }}</description>
+              {% if term.log is defined %}
+              <log>{{ term.log }}</log>
+              {% endif %}
+              <match>
+                    {% if filter.family == "ipv4" %}
+                <protocol>{{ term.from.protocol }}</protocol>
+                    {% else %}
+                <next-header>{{ term.from.protocol }}</next-header>
+                    {% endif %}
+              </match>
+              <action>
+                <{{ term.action }}></{{ term.action }}>
+              </action>
+            </entry>
+          {% set ns3.entry_id = ns3.entry_id + 10 %}
+        {% endif %}
+      {% endif %}
+      {# Case when both src_prefix_list and dst_prefix_list are defined #}
+      {% if term.from.src_prefix_list is defined %}
+        {% for src_prefix_list_item in term.from.src_prefix_list%}
+          {% set src_index = loop.index0 %}
+          {% if term.from.dst_prefix_list is defined %}
+            {% for dst_prefix_list_item in term.from.dst_prefix_list %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+              {% if term.from.protocol is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol>{{term.from.protocol}}</protocol>
+                {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                {% endif %}
+              {% elif term.from.protocol_list is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
+                {% else %}
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
+                {% endif %}
+              {% endif %}
+            {% include 'filters/port_list_entries.j2' %}
+              <src-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.src_prefix_list[src_index]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.src_prefix_list[src_index]}}</ipv6-prefix-list>
+                {% endif %}
+              </src-ip>
+              <dst-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ipv6-prefix-list>
+                {% endif %}
+              </dst-ip>
+            </match>
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+            <action>
+                <{{term.action}}></{{term.action}}>
+            </action>
+          </entry>
+            {% endfor %}
+          {% else %}
+            {# src_prefix_list is defined, dst_prefix_list is not #}
+          <entry>
+            <entry-id> {{ ns3.entry_id }} </entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+            {% if term.from.protocol is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol>{{term.from.protocol}}</protocol>
+                {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                {% endif %}
+            {% elif term.from.protocol_list is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
+                {% else %}
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
+                {% endif %}
+            {% endif %}
+            {% include 'filters/port_list_entries.j2' %}
+              <src-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.src_prefix_list[src_index]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.src_prefix_list[src_index]}}</ipv6-prefix-list>
+                {% endif %}
+              </src-ip>
+            </match>
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+            <action>
+                <{{term.action}}></{{term.action}}>
+            </action>
+          </entry>
+          {% endif %}
+        {% endfor %}
+      {# Case where only DST prefix list is defined #}
+      {% elif term.from.dst_prefix_list is defined %}
+        {% for dst_prefix_list_item in term.from.dst_prefix_list %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+              {% if term.from.protocol is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol>{{term.from.protocol}}</protocol>
+                {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                {% endif %}
+              {% elif term.from.protocol_list is defined %}
+                {% if filter.family == "ipv4" %}
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
+                {% else %}
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
+                {% endif %}
+              {% endif %}
+            {% include 'filters/port_list_entries.j2' %}
+              <dst-ip>
+                {% if filter.family == "ipv4" %}
+                <ip-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ip-prefix-list>
+                {% else %}
+                <ipv6-prefix-list>{{term.from.dst_prefix_list[loop.index0]}}</ipv6-prefix-list>
+                {% endif %}
+              </dst-ip>
+            </match>
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+            <action>
+                <{{term.action}}></{{term.action}}>
+            </action>
+          </entry>
+        {% endfor %}
+      {# term.from.protocol and ports are defined, but not SRC or DST prefix list - e.g. IPv4 traceroute #}
+      {% elif term.from.protocol is defined and term.from.protocol in ['udp'] %}
+          <entry>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
+            <description>{{ term.name }}</description>
+            {% if term.log is defined %}
+            <log>{{ term.log }}</log>
+            {% endif %}
+            <match>
+                  {% if filter.family == "ipv4" %}
+              <protocol>{{ term.from.protocol }}</protocol>
+                  {% else %}
+              <next-header>{{ term.from.protocol }}</next-header>
+                  {% endif %}
+            {% include 'filters/port_list_entries.j2' %}
+            </match>
+            <action>
+              <{{ term.action }}></{{ term.action }}>
+            </action>
+          </entry>
+          {% set ns3.entry_id = ns3.entry_id + 10 %}
+      {% endif %}
+    {% endif %}
+  {% endfor %}
+  {# Terms end #}
+  {% if filter.family == "ipv4" %}
+        </ip-filter>
+  {% elif filter.family == "ipv6" %}
+        </ipv6-filter>
+  {% endif %}
+{% endfor %}
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
new file mode 100644
index 00000000..8eb97df2
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
@@ -0,0 +1,16 @@
+<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
+
+{% with is_cpm_filter=False, filters=gen_filters %}
+
+  {% include "filters/port_list_definitions.j2" %}
+  {% include "filters/protocol_list_definitions.j2" %}
+  <filter xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+    {% include "filters/fw_filters.j2" %}
+  </filter>
+
+{% endwith %}
+
+   </configure>
+</config>
+
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
new file mode 100644
index 00000000..34c35ad8
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
@@ -0,0 +1,66 @@
+{# This template takes care of configuring connectors and breakouts #}
+<filter xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+  <match-list>
+  {% for filter in filters %}
+    {% for term in filter.terms %}
+    {% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
+    <port-list>
+      <port-list-name>{{filter.name}}-{{term.name}}-PORTS</port-list-name>
+      {%for port in term.from.port %}
+        <port>
+            <value>{{port}}</value>
+        </port>
+      {% endfor %}
+    </port-list>
+    {% endif %}
+    {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
+    <port-list>
+      <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list-name>
+      {%for port in term.from.src_port %}
+        <port>
+          <value>{{port}}</value>
+        </port>
+      {% endfor %}
+    </port-list>
+    {% endif %}
+    {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
+    <port-list>
+      <port-list-name>{{filter.name}}-{{term.name}}-DST_PORTS</port-list-name>
+      {%for port in term.from.dst_port %}
+        <port>
+          <value>{{port}}</value>
+        </port>
+      {% endfor %}
+      </port-list>
+    {% endif %}
+    {% if term.from.port_range is defined %}
+    <port-list>
+      <port-list-name>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list-name>
+      <range>
+        <start>{{ term.from.port_range.start }}</start>
+        <end>{{ term.from.port_range.end }}</end>
+      </range>
+    </port-list>
+    {% endif %}
+    {% if term.from.src_port_range is defined %}
+    <port-list>
+      <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list-name>
+      <range>
+        <start>{{ term.from.src_port_range.start }}</start>
+        <end>{{ term.from.src_port_range.end }}</end>
+      </range>
+    </port-list>
+    {% endif %}
+    {% if term.from.dst_port_range is defined %}
+    <port-list>
+      <port-list-name>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list-name>
+      <range>
+        <start>{{ term.from.dst_port_range.start }}</start>
+        <end>{{ term.from.dst_port_range.end }}</end>
+      </range>
+    </port-list>
+    {% endif %}
+    {% endfor %}
+  {% endfor %}
+  </match-list>
+</filter>
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
new file mode 100644
index 00000000..4f335265
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
@@ -0,0 +1,48 @@
+{#This is the case it's a port-list #}
+{% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
+  <port>
+      <port-list>{{filter.name}}-{{term.name}}-PORTS</port-list>
+  </port>
+{% endif %}
+{% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
+  <src-port>
+      <port-list>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list>
+  </src-port>
+{% endif %}
+{% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
+  <dst-port>
+      <port-list>{{filter.name}}-{{term.name}}-DST_PORTS</port-list>
+  </dst-port>
+{% endif %}
+{#This is the case it's a single port #}
+{% if term.from.port is defined and term.from.port.__class__.__name__ != 'list'%}
+  <port>
+      <eq>{{term.from.port}}</eq>
+  </port>
+{% endif %}
+{% if term.from.src_port is defined and term.from.src_port.__class__.__name__ != 'list'%}
+  <src-port>
+      <eq>{{term.from.src_port}}</eq>
+  </src-port>
+{% endif %}
+{% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ != 'list'%}
+  <dst-port>
+    <eq>{{term.from.dst_port}}</eq>
+  </dst-port>
+{% endif %}
+ {# Port range #}
+ {% if term.from.port_range is defined %}
+  <port>
+      <port-list>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list>
+  </port>
+{% endif %}
+{% if term.from.src_port_range is defined %}
+  <src-port>
+      <port-list>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list>
+  </src-port>
+{% endif %}
+{% if term.from.dst_port_range is defined %}
+  <dst-port>
+      <port-list>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list>
+  </dst-port>
+{% endif %}
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
new file mode 100644
index 00000000..ef31e9fa
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
@@ -0,0 +1,19 @@
+{# This template takes care of configuring connectors and breakouts #}
+<filter xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+  <match-list>
+  {% for filter in filters %}
+    {% for term in filter.terms %}
+      {% if term.from.protocol_list is defined and term.from.protocol_list.__class__.__name__ == 'list' %}
+    <protocol-list>
+      <protocol-list-name>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list-name>
+        {%for protocol in term.from.protocol_list %}
+        <protocol>
+            <protocol-id>{{ protocol }}</protocol-id>
+        </protocol>
+        {% endfor %}
+    </protocol-list>
+      {% endif %}
+    {% endfor %}
+  {% endfor %}
+  </match-list>
+</filter>
diff --git a/geant/gap_ansible/roles/fw_filters/vars/main.yml b/geant/gap_ansible/roles/fw_filters/vars/main.yml
new file mode 100644
index 00000000..944de332
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for fw_filters
diff --git a/geant/gap_ansible/roles/geant_ip/README.md b/geant/gap_ansible/roles/geant_ip/README.md
new file mode 100644
index 00000000..225dd44b
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/geant_ip/defaults/main.yml b/geant/gap_ansible/roles/geant_ip/defaults/main.yml
new file mode 100644
index 00000000..1b65cb38
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for geant_ip
diff --git a/geant/gap_ansible/roles/geant_ip/handlers/main.yml b/geant/gap_ansible/roles/geant_ip/handlers/main.yml
new file mode 100644
index 00000000..3c8caf87
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for geant_ip
diff --git a/geant/gap_ansible/roles/geant_ip/meta/main.yml b/geant/gap_ansible/roles/geant_ip/meta/main.yml
new file mode 100644
index 00000000..dde461cc
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/meta/main.yml
@@ -0,0 +1,38 @@
+galaxy_info:
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  company: GEANT
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: MIT
+
+  min_ansible_version: '2.10'
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  galaxy_tags:
+    - network
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
+
+collections:
+  - geant.gap_ansible
diff --git a/geant/gap_ansible/roles/geant_ip/tasks/compile.yaml b/geant/gap_ansible/roles/geant_ip/tasks/compile.yaml
new file mode 100644
index 00000000..c185a7e5
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/tasks/compile.yaml
@@ -0,0 +1,24 @@
+---
+- name: Set ansible host to localhost to compile config when router is offline
+  when:
+    router.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Create a folder for all the things
+  ansible.builtin.file:
+    path: "/var/tmp/ansible_run_{{ opid }}"
+    state: directory
+    mode: '0755'
+  delegate_to: localhost
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ verb }}_{{ object }}.conf"
+  when: verb == "create"
+  ansible.builtin.template:
+    src: "{{ item.sbp.edge_port.node.vendor }}/{{ item.sbp.sbp_type }}/{{ verb }}_{{ object }}.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ verb }}_{{ object }}.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/geant_ip/tasks/main.yml b/geant/gap_ansible/roles/geant_ip/tasks/main.yml
new file mode 100644
index 00000000..296b5291
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/tasks/main.yml
@@ -0,0 +1,23 @@
+---
+# tasks file for geant_ip
+- name: Include Standard role tasks
+  ansible.builtin.include_tasks: standard_tasks.yaml
+
+- name: Include Filter role
+  ansible.builtin.include_role:
+    name: fw_filters
+  vars:
+    gen_filters: "{{ IPV4_EDGE_IN }}"
+  loop: "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+
+- name: Include templates compilation for SBP
+  when: verb in verbs and object in ["sbp"]
+  ansible.builtin.include_tasks: compile.yaml
+  loop: "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+
+- name: Include set connection tasks
+  ansible.builtin.include_tasks: connection_tasks.yaml
+
+- name: Include deploy tasks
+  when: verb in verbs
+  ansible.builtin.include_tasks: deploy.yaml
diff --git a/geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml b/geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml
new file mode 100644
index 00000000..f1db3834
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml
@@ -0,0 +1,44 @@
+---
+- name: Print the usage
+  when: (verb is not defined) or (verb not in verbs) or (object is not defined) or (object not in objects)
+  ansible.builtin.debug:
+    msg:
+      - "'verb' and 'object' keywords are mandatory. Usage: -e verb=$verb -e object=$object"
+
+- name: Print defined verbs
+  when: (verb is not defined) or (verb not in verbs)
+  ansible.builtin.debug:
+    msg:
+      - "Allowed verb: {{ item }}"
+  loop: "{{ verbs }}"
+
+- name: Print defined objects
+  when: (object is not defined) or (object not in objects)
+  ansible.builtin.debug:
+    msg:
+      - "Allowed object: {{ item }}"
+  loop: "{{ objects }}"
+
+- name: Stop if arguments are incorrect
+  when: (verb is not defined) or (verb not in verbs) or (object is not defined) or (object not in objects)
+  ansible.builtin.meta: end_play
+
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Import standard variables for {{ subscription.product.name }}
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/geant_services/{{ subscription.product.product_type }}
+
+- name: Import partner specific variables for "{{ partner_name }}"
+  ansible.builtin.include_vars:
+    file: /opt/ansible_inventory/geant_partners/{{ partner_name | lower }}.yaml
+
+- name: Generate an ID for this run
+  ansible.builtin.set_fact:
+    opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
+
+- name: Print the ID
+  ansible.builtin.debug:
+    msg: "{{ opid }}"
diff --git a/geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2 b/geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2
new file mode 100644
index 00000000..d2ba5293
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2
@@ -0,0 +1,48 @@
+{% set sbp = item.sbp %}
+{% set lag_name = sbp.edge_port.edge_port_name %}
+
+<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
+        <service xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+            <ies xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+                <interface alu:operation="replace">
+                    <interface-name>{{ lag_name }}.{{ sbp.vlan_id }}</interface-name>
+                    <description>SRV_GLOBAL CUSTOMER {{ partner_name }} #{{ partner_name }}-{{ sbp.ap_type }} ${{ sbp.geant_sid }} | ASN{{ asn }} | </description>
+                    <ip-mtu>{{ sbp_params.ip_mtu }}</ip-mtu>
+                    <sap>
+                        <sap-id>{{ lag_name }}:{{ sbp.vlan_id }}</sap-id>
+                        <admin-state>enable</admin-state>
+                    </sap>
+                    <ipv4>
+                      {% if sbp.ipv4_bfd %}
+                        <bfd>
+                            <admin-state>enable</admin-state>
+                            <transmit-interval>{{ sbp_params.bfd.ipv4.trasmit }}</transmit-interval>
+                            <receive>{{ sbp_params.bfd.ipv4.receive }}</receive>
+                            <multiplier>{{ sbp_params.bfd.ipv4.multiplier | default(3) }}</multiplier>
+                        </bfd>
+                      {% endif %}
+                        <primary>
+                            <address>{{ sbp.ipv4_address }}</address>
+                            <prefix-length>{{ sbp.ipv4_mask }}</prefix-length>
+                        </primary>
+                    </ipv4>
+                    <ipv6>
+                      {% if sbp.ipv6_bfd %}
+                        <bfd>
+                            <admin-state>enable</admin-state>
+                            <transmit-interval>{{ sbp_params.bfd.ipv6.trasmit }}</transmit-interval>
+                            <receive>{{ sbp_params.bfd.ipv6.receive }}</receive>
+                            <multiplier>{{ sbp_params.bfd.ipv6.multiplier | default(3) }}</multiplier>
+                        </bfd>
+                      {% endif %}
+                        <address>
+                            <ipv6-address>{{ sbp.ipv6_address }}</ipv6-address>
+                            <prefix-length>{{ sbp.ipv6_mask }}</prefix-length>
+                        </address>
+                    </ipv6>
+                </interface>
+            </ies>
+        </service>
+   </configure>
+</config>
diff --git a/geant/gap_ansible/roles/geant_ip/vars/main.yml b/geant/gap_ansible/roles/geant_ip/vars/main.yml
new file mode 100644
index 00000000..dd2f35bc
--- /dev/null
+++ b/geant/gap_ansible/roles/geant_ip/vars/main.yml
@@ -0,0 +1,15 @@
+---
+# vars file for geant_ip
+
+dry_run: true
+is_verification_workflow: false
+
+verbs:
+  - deploy
+  - check
+  - update
+  - terminate
+
+objects:
+  - sbp
+  - bgp
-- 
GitLab


From b484ff66cf5706ffda1a3d1d85a9bb19b012b099 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Wed, 30 Oct 2024 23:27:52 +0000
Subject: [PATCH 02/46] FW filter role for NREN L3 service

---
 .../playbooks/manage_geant_ip.yaml            | 44 ++++++++++++++-
 .../roles/fw_filters/tasks/compile.yaml       | 25 ++++-----
 .../roles/fw_filters/tasks/main.yml           | 13 +++++
 .../templates/filters/fw_filters.j2           | 22 +++++++-
 .../templates/filters/gen_filters.j2          |  4 +-
 .../filters/port_list_definitions.j2          |  4 +-
 .../templates/filters/port_list_entries.j2    | 54 +++++++++----------
 .../filters/protocol_list_definitions.j2      |  4 +-
 8 files changed, 122 insertions(+), 48 deletions(-)

diff --git a/geant/gap_ansible/playbooks/manage_geant_ip.yaml b/geant/gap_ansible/playbooks/manage_geant_ip.yaml
index eaa05b1b..29efc720 100644
--- a/geant/gap_ansible/playbooks/manage_geant_ip.yaml
+++ b/geant/gap_ansible/playbooks/manage_geant_ip.yaml
@@ -1,5 +1,45 @@
 - name: Manage GEANT IP instance
   hosts: all
   gather_facts: false
-  roles:
-    - ../roles/geant_ip
+  # roles:
+  #   - ../roles/geant_ip
+  tasks:
+    - name: Generate an ID for this run
+      ansible.builtin.set_fact:
+        opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
+
+    - name: Print the ID
+      ansible.builtin.debug:
+        msg: "{{ opid }}"
+
+    - name: Create a folder for all compiled output
+      ansible.builtin.file:
+        path: "/var/tmp/ansible_run_{{ opid }}"
+        state: directory
+        mode: '0755'
+      delegate_to: localhost
+
+    - name: Import standard variables for {{ subscription.product.name }}
+      ansible.builtin.include_vars:
+        dir: /opt/ansible_inventory/geant_services/{{ subscription.product.product_type }}
+
+    - name: Import partner specific variables for "{{ partner_name }}"
+      ansible.builtin.include_vars:
+        dir: /opt/ansible_inventory/geant_partners/{{ partner_name | lower }}
+
+    - name: Compile Firewall filters
+      block:
+        - name: Merge Edge filters
+          ansible.builtin.set_fact:
+            edge_fw: "{{ lookup('community.general.merge_variables', 'edgefw__to_merge') }}"
+
+        - name: Include Filter role
+          ansible.builtin.include_role:
+            name: fw_filters
+          vars:
+            gen_filters: "{{ edge_fw }}"
+          # loop:
+          #   - "{{ IPV4_EDGE_IN }}"
+          #   - "{{ JISC_EDGE_IN }}"
+          # loop_control:
+          #   loop_var: gen_filters
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
index d6ee0f6c..933fd024 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
@@ -1,23 +1,24 @@
 ---
-- name: Set ansible host to localhost to compile config when router is offline
-  when:
-    item.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+- name: Set ansible host to localhost to compile template
+  # when:
+  #   item.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
   ansible.builtin.set_fact:
     ansible_host: "localhost"
     ansible_connection: local
 
-- name: Create a folder for all the things
-  ansible.builtin.file:
-    path: "/var/tmp/ansible_run_{{ opid }}"
-    state: directory
-    mode: '0755'
-  delegate_to: localhost
+# - name: Create a folder for all the things
+#   ansible.builtin.file:
+#     path: "/var/tmp/ansible_run_{{ opid }}"
+#     state: directory
+#     mode: '0755'
 
-- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/gen_filters.conf"
-  when: verb in ["deploy", "update", "terminate"]
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/filters_{{ gen_filters[0].name }}.conf"
+  # when: verb in ["deploy", "update", "terminate"]
   ansible.builtin.template:
+  # ansible.builtin.blockinfile:
     src: "filters/gen_filters.j2"
-    dest: "/var/tmp/ansible_run_{{ opid }}/gen_filters.conf"
+    # block: "{{ lookup('ansible.builtin.template', 'filters/gen_filters.j2') }}"
+    dest: "/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf"
     lstrip_blocks: true
     trim_blocks: true
     mode: '0755'
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/main.yml b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
index 6e818e84..cbbc75d1 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/main.yml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
@@ -2,3 +2,16 @@
 # tasks file for fw_filters
 - name: Include filter compilation
   ansible.builtin.include_tasks: compile.yaml
+
+# - name: Touch output file
+#   ansible.builtin.file:
+#     path: "/var/tmp/ansible_run_{{ opid }}/filters.conf"
+#     state: touch
+#     mode: '0755'
+#     modification_time: preserve
+#     access_time: preserve
+
+# - name: Assemble all FW files
+#   ansible.builtin.assemble:
+#     src: "/var/tmp/ansible_run_{{ opid }}"
+#     dest: "/var/tmp/filters.conf"
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
index 29383100..ff3fd96e 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
@@ -13,6 +13,26 @@
       {% if filter.default_action is defined %}
         <default-action>{{ filter.default_action }}</default-action>
       {% endif %}
+      {% if filter.chain_to_system_filter is defined %}
+        <chain-to-system-filter>{{ filter.chain_to_system_filter }}</chain-to-system-filter>
+      {% endif %}
+      {% if filter.embed is defined %}
+        <embed>
+         {% for embed in filter.embed %}
+            {% if embed.type == 'filter' %}
+            <filter>
+                <name>{{ embed.name }}</name>
+                <offset>{{ embed.offset }}</offset>
+            </filter>
+            {% elif embed.type == 'flowspec' %}
+            <flowspec>
+                <offset>{{ embed.offset }}</offset>
+                <router-instance>{{ embed.router_instance }}</router-instance>
+            </flowspec>
+            {% endif %}
+         {% endfor %}
+        </embed>
+      {% endif %}
   {% endif %}
   {% if filter.offset is defined %}
     {% set ns3 = namespace(entry_id = filter.offset | int) %}
@@ -142,7 +162,7 @@
               <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
                 {% endif %}
               {% endif %}
-            {% include 'filters/port_list_entries.j2' %}
+              {% include 'filters/port_list_entries.j2' %}
               <src-ip>
                 {% if filter.family == "ipv4" %}
                 <ip-prefix-list>{{term.from.src_prefix_list[src_index]}}</ip-prefix-list>
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
index 8eb97df2..5ec27751 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
@@ -3,9 +3,9 @@
 
 {% with is_cpm_filter=False, filters=gen_filters %}
 
-  {% include "filters/port_list_definitions.j2" %}
-  {% include "filters/protocol_list_definitions.j2" %}
   <filter xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+    {% include "filters/port_list_definitions.j2" %}
+    {% include "filters/protocol_list_definitions.j2" %}
     {% include "filters/fw_filters.j2" %}
   </filter>
 
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
index 34c35ad8..4e1cdc7b 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
@@ -1,5 +1,5 @@
 {# This template takes care of configuring connectors and breakouts #}
-<filter xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+
   <match-list>
   {% for filter in filters %}
     {% for term in filter.terms %}
@@ -63,4 +63,4 @@
     {% endfor %}
   {% endfor %}
   </match-list>
-</filter>
+
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
index 4f335265..a6702ba9 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
@@ -1,48 +1,48 @@
 {#This is the case it's a port-list #}
 {% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
-  <port>
-      <port-list>{{filter.name}}-{{term.name}}-PORTS</port-list>
-  </port>
+        <port>
+            <port-list>{{filter.name}}-{{term.name}}-PORTS</port-list>
+        </port>
 {% endif %}
 {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
-  <src-port>
-      <port-list>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list>
-  </src-port>
+        <src-port>
+            <port-list>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list>
+        </src-port>
 {% endif %}
 {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
-  <dst-port>
-      <port-list>{{filter.name}}-{{term.name}}-DST_PORTS</port-list>
-  </dst-port>
+        <dst-port>
+            <port-list>{{filter.name}}-{{term.name}}-DST_PORTS</port-list>
+        </dst-port>
 {% endif %}
 {#This is the case it's a single port #}
 {% if term.from.port is defined and term.from.port.__class__.__name__ != 'list'%}
-  <port>
-      <eq>{{term.from.port}}</eq>
-  </port>
+        <port>
+            <eq>{{term.from.port}}</eq>
+        </port>
 {% endif %}
 {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ != 'list'%}
-  <src-port>
-      <eq>{{term.from.src_port}}</eq>
-  </src-port>
+        <src-port>
+            <eq>{{term.from.src_port}}</eq>
+        </src-port>
 {% endif %}
 {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ != 'list'%}
-  <dst-port>
-    <eq>{{term.from.dst_port}}</eq>
-  </dst-port>
+        <dst-port>
+          <eq>{{term.from.dst_port}}</eq>
+        </dst-port>
 {% endif %}
  {# Port range #}
  {% if term.from.port_range is defined %}
-  <port>
-      <port-list>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list>
-  </port>
+        <port>
+            <port-list>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list>
+        </port>
 {% endif %}
 {% if term.from.src_port_range is defined %}
-  <src-port>
-      <port-list>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list>
-  </src-port>
+        <src-port>
+            <port-list>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list>
+        </src-port>
 {% endif %}
 {% if term.from.dst_port_range is defined %}
-  <dst-port>
-      <port-list>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list>
-  </dst-port>
+        <dst-port>
+            <port-list>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list>
+        </dst-port>
 {% endif %}
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
index ef31e9fa..b5fa3c9a 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
@@ -1,5 +1,5 @@
 {# This template takes care of configuring connectors and breakouts #}
-<filter xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+
   <match-list>
   {% for filter in filters %}
     {% for term in filter.terms %}
@@ -16,4 +16,4 @@
     {% endfor %}
   {% endfor %}
   </match-list>
-</filter>
+
-- 
GitLab


From 4e86736f32eee531c4e31d79ca63cabd7e093aa4 Mon Sep 17 00:00:00 2001
From: Simone Spinelli <simone.spinelli@GA0503-SSPINELLI.local>
Date: Thu, 31 Oct 2024 10:58:51 +0100
Subject: [PATCH 03/46] Rename play to match gso product name and creating
 placeholders for all the roles

---
 .../gap_ansible/roles/prefix_lists/README.md  | 38 +++++++++++++++++++
 .../roles/prefix_lists/defaults/main.yml      |  2 +
 .../roles/prefix_lists/handlers/main.yml      |  2 +
 .../roles/prefix_lists/meta/main.yml          | 34 +++++++++++++++++
 .../roles/prefix_lists/tasks/main.yml         |  2 +
 .../roles/prefix_lists/tests/inventory        |  2 +
 .../roles/prefix_lists/tests/test.yml         |  5 +++
 .../roles/prefix_lists/vars/main.yml          |  2 +
 8 files changed, 87 insertions(+)
 create mode 100644 geant/gap_ansible/roles/prefix_lists/README.md
 create mode 100644 geant/gap_ansible/roles/prefix_lists/defaults/main.yml
 create mode 100644 geant/gap_ansible/roles/prefix_lists/handlers/main.yml
 create mode 100644 geant/gap_ansible/roles/prefix_lists/meta/main.yml
 create mode 100644 geant/gap_ansible/roles/prefix_lists/tasks/main.yml
 create mode 100644 geant/gap_ansible/roles/prefix_lists/tests/inventory
 create mode 100644 geant/gap_ansible/roles/prefix_lists/tests/test.yml
 create mode 100644 geant/gap_ansible/roles/prefix_lists/vars/main.yml

diff --git a/geant/gap_ansible/roles/prefix_lists/README.md b/geant/gap_ansible/roles/prefix_lists/README.md
new file mode 100644
index 00000000..225dd44b
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/prefix_lists/defaults/main.yml b/geant/gap_ansible/roles/prefix_lists/defaults/main.yml
new file mode 100644
index 00000000..c35214fe
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for prefix_lists
diff --git a/geant/gap_ansible/roles/prefix_lists/handlers/main.yml b/geant/gap_ansible/roles/prefix_lists/handlers/main.yml
new file mode 100644
index 00000000..678e7dfe
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for prefix_lists
diff --git a/geant/gap_ansible/roles/prefix_lists/meta/main.yml b/geant/gap_ansible/roles/prefix_lists/meta/main.yml
new file mode 100644
index 00000000..ea68190c
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/meta/main.yml
@@ -0,0 +1,34 @@
+galaxy_info:
+  author: your name
+  description: your role description
+  company: your company (optional)
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: license (GPL-2.0-or-later, MIT, etc)
+
+  min_ansible_version: 2.1
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  galaxy_tags: []
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
diff --git a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
new file mode 100644
index 00000000..070212a3
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+# tasks file for prefix_lists
diff --git a/geant/gap_ansible/roles/prefix_lists/tests/inventory b/geant/gap_ansible/roles/prefix_lists/tests/inventory
new file mode 100644
index 00000000..878877b0
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/tests/inventory
@@ -0,0 +1,2 @@
+localhost
+
diff --git a/geant/gap_ansible/roles/prefix_lists/tests/test.yml b/geant/gap_ansible/roles/prefix_lists/tests/test.yml
new file mode 100644
index 00000000..1d01839a
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/tests/test.yml
@@ -0,0 +1,5 @@
+---
+- hosts: localhost
+  remote_user: root
+  roles:
+    - prefix_lists
diff --git a/geant/gap_ansible/roles/prefix_lists/vars/main.yml b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
new file mode 100644
index 00000000..2d520ad3
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for prefix_lists
-- 
GitLab


From 179b4a8301524960b15daa7eb8f21d4afff84223 Mon Sep 17 00:00:00 2001
From: Simone Spinelli <simone.spinelli@GA0503-SSPINELLI.local>
Date: Thu, 31 Oct 2024 11:04:25 +0100
Subject: [PATCH 04/46] More structure and roles

---
 geant/gap_ansible/roles/bgp_config/README.md  | 38 +++++++++++++++++++
 .../roles/bgp_config/defaults/main.yml        |  2 +
 .../roles/bgp_config/handlers/main.yml        |  2 +
 .../roles/bgp_config/meta/main.yml            | 34 +++++++++++++++++
 .../roles/bgp_config/tasks/main.yml           |  2 +
 .../roles/bgp_config/tests/inventory          |  2 +
 .../roles/bgp_config/tests/test.yml           |  5 +++
 .../roles/bgp_config/vars/main.yml            |  2 +
 .../roles/deploy_service_config/README.md     | 38 +++++++++++++++++++
 .../deploy_service_config/defaults/main.yml   |  2 +
 .../deploy_service_config/handlers/main.yml   |  2 +
 .../roles/deploy_service_config/meta/main.yml | 34 +++++++++++++++++
 .../deploy_service_config/tasks/main.yml      |  2 +
 .../deploy_service_config/tests/inventory     |  2 +
 .../deploy_service_config/tests/test.yml      |  5 +++
 .../roles/deploy_service_config/vars/main.yml |  2 +
 .../roles/policy_options/README.md            | 38 +++++++++++++++++++
 .../roles/policy_options/defaults/main.yml    |  2 +
 .../roles/policy_options/handlers/main.yml    |  2 +
 .../roles/policy_options/meta/main.yml        | 34 +++++++++++++++++
 .../roles/policy_options/tasks/main.yml       |  2 +
 .../roles/policy_options/tests/inventory      |  2 +
 .../roles/policy_options/tests/test.yml       |  5 +++
 .../roles/policy_options/vars/main.yml        |  2 +
 geant/gap_ansible/roles/sbp/README.md         | 38 +++++++++++++++++++
 geant/gap_ansible/roles/sbp/defaults/main.yml |  2 +
 geant/gap_ansible/roles/sbp/handlers/main.yml |  2 +
 geant/gap_ansible/roles/sbp/meta/main.yml     | 34 +++++++++++++++++
 geant/gap_ansible/roles/sbp/tasks/main.yml    |  2 +
 geant/gap_ansible/roles/sbp/tests/inventory   |  2 +
 geant/gap_ansible/roles/sbp/tests/test.yml    |  5 +++
 geant/gap_ansible/roles/sbp/vars/main.yml     |  2 +
 32 files changed, 348 insertions(+)
 create mode 100644 geant/gap_ansible/roles/bgp_config/README.md
 create mode 100644 geant/gap_ansible/roles/bgp_config/defaults/main.yml
 create mode 100644 geant/gap_ansible/roles/bgp_config/handlers/main.yml
 create mode 100644 geant/gap_ansible/roles/bgp_config/meta/main.yml
 create mode 100644 geant/gap_ansible/roles/bgp_config/tasks/main.yml
 create mode 100644 geant/gap_ansible/roles/bgp_config/tests/inventory
 create mode 100644 geant/gap_ansible/roles/bgp_config/tests/test.yml
 create mode 100644 geant/gap_ansible/roles/bgp_config/vars/main.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/README.md
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/defaults/main.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/handlers/main.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/meta/main.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/inventory
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/test.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/vars/main.yml
 create mode 100644 geant/gap_ansible/roles/policy_options/README.md
 create mode 100644 geant/gap_ansible/roles/policy_options/defaults/main.yml
 create mode 100644 geant/gap_ansible/roles/policy_options/handlers/main.yml
 create mode 100644 geant/gap_ansible/roles/policy_options/meta/main.yml
 create mode 100644 geant/gap_ansible/roles/policy_options/tasks/main.yml
 create mode 100644 geant/gap_ansible/roles/policy_options/tests/inventory
 create mode 100644 geant/gap_ansible/roles/policy_options/tests/test.yml
 create mode 100644 geant/gap_ansible/roles/policy_options/vars/main.yml
 create mode 100644 geant/gap_ansible/roles/sbp/README.md
 create mode 100644 geant/gap_ansible/roles/sbp/defaults/main.yml
 create mode 100644 geant/gap_ansible/roles/sbp/handlers/main.yml
 create mode 100644 geant/gap_ansible/roles/sbp/meta/main.yml
 create mode 100644 geant/gap_ansible/roles/sbp/tasks/main.yml
 create mode 100644 geant/gap_ansible/roles/sbp/tests/inventory
 create mode 100644 geant/gap_ansible/roles/sbp/tests/test.yml
 create mode 100644 geant/gap_ansible/roles/sbp/vars/main.yml

diff --git a/geant/gap_ansible/roles/bgp_config/README.md b/geant/gap_ansible/roles/bgp_config/README.md
new file mode 100644
index 00000000..225dd44b
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/bgp_config/defaults/main.yml b/geant/gap_ansible/roles/bgp_config/defaults/main.yml
new file mode 100644
index 00000000..41a48461
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for bgp_config
diff --git a/geant/gap_ansible/roles/bgp_config/handlers/main.yml b/geant/gap_ansible/roles/bgp_config/handlers/main.yml
new file mode 100644
index 00000000..e488bebc
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for bgp_config
diff --git a/geant/gap_ansible/roles/bgp_config/meta/main.yml b/geant/gap_ansible/roles/bgp_config/meta/main.yml
new file mode 100644
index 00000000..ea68190c
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/meta/main.yml
@@ -0,0 +1,34 @@
+galaxy_info:
+  author: your name
+  description: your role description
+  company: your company (optional)
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: license (GPL-2.0-or-later, MIT, etc)
+
+  min_ansible_version: 2.1
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  galaxy_tags: []
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/main.yml b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
new file mode 100644
index 00000000..0edcfb6b
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+# tasks file for bgp_config
diff --git a/geant/gap_ansible/roles/bgp_config/tests/inventory b/geant/gap_ansible/roles/bgp_config/tests/inventory
new file mode 100644
index 00000000..878877b0
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tests/inventory
@@ -0,0 +1,2 @@
+localhost
+
diff --git a/geant/gap_ansible/roles/bgp_config/tests/test.yml b/geant/gap_ansible/roles/bgp_config/tests/test.yml
new file mode 100644
index 00000000..d3de857b
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tests/test.yml
@@ -0,0 +1,5 @@
+---
+- hosts: localhost
+  remote_user: root
+  roles:
+    - bgp_config
diff --git a/geant/gap_ansible/roles/bgp_config/vars/main.yml b/geant/gap_ansible/roles/bgp_config/vars/main.yml
new file mode 100644
index 00000000..260a92d9
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for bgp_config
diff --git a/geant/gap_ansible/roles/deploy_service_config/README.md b/geant/gap_ansible/roles/deploy_service_config/README.md
new file mode 100644
index 00000000..225dd44b
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/deploy_service_config/defaults/main.yml b/geant/gap_ansible/roles/deploy_service_config/defaults/main.yml
new file mode 100644
index 00000000..224547ba
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for deploy_service_config
diff --git a/geant/gap_ansible/roles/deploy_service_config/handlers/main.yml b/geant/gap_ansible/roles/deploy_service_config/handlers/main.yml
new file mode 100644
index 00000000..f5d286b3
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for deploy_service_config
diff --git a/geant/gap_ansible/roles/deploy_service_config/meta/main.yml b/geant/gap_ansible/roles/deploy_service_config/meta/main.yml
new file mode 100644
index 00000000..ea68190c
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/meta/main.yml
@@ -0,0 +1,34 @@
+galaxy_info:
+  author: your name
+  description: your role description
+  company: your company (optional)
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: license (GPL-2.0-or-later, MIT, etc)
+
+  min_ansible_version: 2.1
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  galaxy_tags: []
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
new file mode 100644
index 00000000..c78cb095
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+# tasks file for deploy_service_config
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/inventory b/geant/gap_ansible/roles/deploy_service_config/tests/inventory
new file mode 100644
index 00000000..878877b0
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tests/inventory
@@ -0,0 +1,2 @@
+localhost
+
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/test.yml b/geant/gap_ansible/roles/deploy_service_config/tests/test.yml
new file mode 100644
index 00000000..1ff3af01
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tests/test.yml
@@ -0,0 +1,5 @@
+---
+- hosts: localhost
+  remote_user: root
+  roles:
+    - deploy_service_config
diff --git a/geant/gap_ansible/roles/deploy_service_config/vars/main.yml b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
new file mode 100644
index 00000000..0a9af9d9
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for deploy_service_config
diff --git a/geant/gap_ansible/roles/policy_options/README.md b/geant/gap_ansible/roles/policy_options/README.md
new file mode 100644
index 00000000..225dd44b
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/policy_options/defaults/main.yml b/geant/gap_ansible/roles/policy_options/defaults/main.yml
new file mode 100644
index 00000000..9304af02
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for policy_options
diff --git a/geant/gap_ansible/roles/policy_options/handlers/main.yml b/geant/gap_ansible/roles/policy_options/handlers/main.yml
new file mode 100644
index 00000000..144f2424
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for policy_options
diff --git a/geant/gap_ansible/roles/policy_options/meta/main.yml b/geant/gap_ansible/roles/policy_options/meta/main.yml
new file mode 100644
index 00000000..ea68190c
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/meta/main.yml
@@ -0,0 +1,34 @@
+galaxy_info:
+  author: your name
+  description: your role description
+  company: your company (optional)
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: license (GPL-2.0-or-later, MIT, etc)
+
+  min_ansible_version: 2.1
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  galaxy_tags: []
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
diff --git a/geant/gap_ansible/roles/policy_options/tasks/main.yml b/geant/gap_ansible/roles/policy_options/tasks/main.yml
new file mode 100644
index 00000000..f6e914bb
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+# tasks file for policy_options
diff --git a/geant/gap_ansible/roles/policy_options/tests/inventory b/geant/gap_ansible/roles/policy_options/tests/inventory
new file mode 100644
index 00000000..878877b0
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tests/inventory
@@ -0,0 +1,2 @@
+localhost
+
diff --git a/geant/gap_ansible/roles/policy_options/tests/test.yml b/geant/gap_ansible/roles/policy_options/tests/test.yml
new file mode 100644
index 00000000..e0a0d30c
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tests/test.yml
@@ -0,0 +1,5 @@
+---
+- hosts: localhost
+  remote_user: root
+  roles:
+    - policy_options
diff --git a/geant/gap_ansible/roles/policy_options/vars/main.yml b/geant/gap_ansible/roles/policy_options/vars/main.yml
new file mode 100644
index 00000000..9dd8b4cc
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for policy_options
diff --git a/geant/gap_ansible/roles/sbp/README.md b/geant/gap_ansible/roles/sbp/README.md
new file mode 100644
index 00000000..225dd44b
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/README.md
@@ -0,0 +1,38 @@
+Role Name
+=========
+
+A brief description of the role goes here.
+
+Requirements
+------------
+
+Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+
+Role Variables
+--------------
+
+A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+
+Dependencies
+------------
+
+A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+
+Example Playbook
+----------------
+
+Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
+
+    - hosts: servers
+      roles:
+         - { role: username.rolename, x: 42 }
+
+License
+-------
+
+BSD
+
+Author Information
+------------------
+
+An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/sbp/defaults/main.yml b/geant/gap_ansible/roles/sbp/defaults/main.yml
new file mode 100644
index 00000000..1f4c6c4e
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for sbp
diff --git a/geant/gap_ansible/roles/sbp/handlers/main.yml b/geant/gap_ansible/roles/sbp/handlers/main.yml
new file mode 100644
index 00000000..21997a5b
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for sbp
diff --git a/geant/gap_ansible/roles/sbp/meta/main.yml b/geant/gap_ansible/roles/sbp/meta/main.yml
new file mode 100644
index 00000000..ea68190c
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/meta/main.yml
@@ -0,0 +1,34 @@
+galaxy_info:
+  author: your name
+  description: your role description
+  company: your company (optional)
+
+  # If the issue tracker for your role is not on github, uncomment the
+  # next line and provide a value
+  # issue_tracker_url: http://example.com/issue/tracker
+
+  # Choose a valid license ID from https://spdx.org - some suggested licenses:
+  # - BSD-3-Clause (default)
+  # - MIT
+  # - GPL-2.0-or-later
+  # - GPL-3.0-only
+  # - Apache-2.0
+  # - CC-BY-4.0
+  license: license (GPL-2.0-or-later, MIT, etc)
+
+  min_ansible_version: 2.1
+
+  # If this a Container Enabled role, provide the minimum Ansible Container version.
+  # min_ansible_container_version:
+
+  galaxy_tags: []
+    # List tags for your role here, one per line. A tag is a keyword that describes
+    # and categorizes the role. Users find roles by searching for tags. Be sure to
+    # remove the '[]' above, if you add tags to this list.
+    #
+    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
+    #       Maximum 20 tags per role.
+
+dependencies: []
+  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
+  # if you add dependencies to this list.
diff --git a/geant/gap_ansible/roles/sbp/tasks/main.yml b/geant/gap_ansible/roles/sbp/tasks/main.yml
new file mode 100644
index 00000000..a36a1f3e
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/main.yml
@@ -0,0 +1,2 @@
+---
+# tasks file for sbp
diff --git a/geant/gap_ansible/roles/sbp/tests/inventory b/geant/gap_ansible/roles/sbp/tests/inventory
new file mode 100644
index 00000000..878877b0
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tests/inventory
@@ -0,0 +1,2 @@
+localhost
+
diff --git a/geant/gap_ansible/roles/sbp/tests/test.yml b/geant/gap_ansible/roles/sbp/tests/test.yml
new file mode 100644
index 00000000..028d1ad2
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tests/test.yml
@@ -0,0 +1,5 @@
+---
+- hosts: localhost
+  remote_user: root
+  roles:
+    - sbp
diff --git a/geant/gap_ansible/roles/sbp/vars/main.yml b/geant/gap_ansible/roles/sbp/vars/main.yml
new file mode 100644
index 00000000..f4cfafe7
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/vars/main.yml
@@ -0,0 +1,2 @@
+---
+# vars file for sbp
-- 
GitLab


From 924dafdbbd8de645c523a2be43bb96a24f4c5a2a Mon Sep 17 00:00:00 2001
From: Simone Spinelli <simone.spinelli@GA0503-SSPINELLI.local>
Date: Thu, 31 Oct 2024 12:25:59 +0100
Subject: [PATCH 05/46] Renaming playbooks and add ansible to requirements.txt

---
 ...eant_ip.yaml => nren_l3_core_service.yaml} | 31 +++++++++++++++++++
 requirements.txt                              |  4 ++-
 2 files changed, 34 insertions(+), 1 deletion(-)
 rename geant/gap_ansible/playbooks/{manage_geant_ip.yaml => nren_l3_core_service.yaml} (65%)

diff --git a/geant/gap_ansible/playbooks/manage_geant_ip.yaml b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
similarity index 65%
rename from geant/gap_ansible/playbooks/manage_geant_ip.yaml
rename to geant/gap_ansible/playbooks/nren_l3_core_service.yaml
index 29efc720..0b3163a5 100644
--- a/geant/gap_ansible/playbooks/manage_geant_ip.yaml
+++ b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
@@ -27,6 +27,12 @@
       ansible.builtin.include_vars:
         dir: /opt/ansible_inventory/geant_partners/{{ partner_name | lower }}
 
+    - name: Compile Prefix Lists
+      block:
+        - name: Include Prefix-list role
+          ansible.builtin.include_role:
+            name: prefix_lists
+
     - name: Compile Firewall filters
       block:
         - name: Merge Edge filters
@@ -43,3 +49,28 @@
           #   - "{{ JISC_EDGE_IN }}"
           # loop_control:
           #   loop_var: gen_filters
+
+    - name: Compile SBP config
+      block:
+        - name: Include SBP role
+          ansible.builtin.include_role:
+            name: sbp
+
+    - name: Compile BGP policies
+      block:
+        - name: Include BGP policies
+          ansible.builtin.include_role:
+            name: policy_options
+
+    - name: Compile BGP sesssions config
+      block:
+        - name: Include BGP session
+          ansible.builtin.include_role:
+            name: bgp_config
+
+    - name: Deploy
+      block:
+        - name: Include deployment role
+          ansible.builtin.include_role:
+            name: deploy_service_config
+      when: verb == deploy  
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 08f36aa2..691676c8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1 +1,3 @@
-ncclient
\ No newline at end of file
+ncclient
+ansible
+ansible-lint
\ No newline at end of file
-- 
GitLab


From 052a2f2ad7b6ed7e0ed23c4643ca167a7aef7400 Mon Sep 17 00:00:00 2001
From: Simone Spinelli <simone.spinelli@GA0503-SSPINELLI.local>
Date: Fri, 1 Nov 2024 15:44:21 +0100
Subject: [PATCH 06/46] README for deploy template

---
 geant/gap_ansible/roles/deploy_service_config/README.md      | 5 ++++-
 .../roles/prefix_lists/templates/juniper/prefix-lists.j2     | 0
 .../roles/prefix_lists/templates/nokia/prefix-lists.j2       | 0
 3 files changed, 4 insertions(+), 1 deletion(-)
 create mode 100644 geant/gap_ansible/roles/prefix_lists/templates/juniper/prefix-lists.j2
 create mode 100644 geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix-lists.j2

diff --git a/geant/gap_ansible/roles/deploy_service_config/README.md b/geant/gap_ansible/roles/deploy_service_config/README.md
index 225dd44b..f4038c76 100644
--- a/geant/gap_ansible/roles/deploy_service_config/README.md
+++ b/geant/gap_ansible/roles/deploy_service_config/README.md
@@ -1,7 +1,10 @@
 Role Name
 =========
 
-A brief description of the role goes here.
+The role identifies the vendor of the target walking through the subscription that it receives as an extra-var. The position in the subscription of this information dependes by the product type. 
+If nokia, then nokia netconf and nokia config modules, the same goes for Juniper. 
+First of all it should collect all the config files contained in the /var/tmp/$ops_id directory and assemble a single configuration file. 
+Then it should do a dry run and finally, when dry_run is false, a commit run .
 
 Requirements
 ------------
diff --git a/geant/gap_ansible/roles/prefix_lists/templates/juniper/prefix-lists.j2 b/geant/gap_ansible/roles/prefix_lists/templates/juniper/prefix-lists.j2
new file mode 100644
index 00000000..e69de29b
diff --git a/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix-lists.j2 b/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix-lists.j2
new file mode 100644
index 00000000..e69de29b
-- 
GitLab


From 7e3e36661b5b76d19e4883fb154bc913e51af2b3 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Mon, 4 Nov 2024 22:10:15 +0000
Subject: [PATCH 07/46] FW filters role

---
 .../roles/fw_filters/tasks/compile.yaml       |   2 +-
 .../roles/fw_filters/tasks/main.yml           |  21 +--
 .../fw_filters/tasks/merge_variables.yaml     |  30 +++
 .../templates/filters/fw_filters.j2           | 172 +++++++++---------
 .../templates/filters/gen_filters.j2          |   4 +
 .../filters/port_list_definitions.j2          | 126 ++++++-------
 .../templates/filters/port_list_entries.j2    |  54 +++---
 .../filters/protocol_list_definitions.j2      |  22 ++-
 .../templates/filters/term_action.j2          |  15 ++
 .../roles/fw_filters/vars/main.yml            |   1 +
 10 files changed, 249 insertions(+), 198 deletions(-)
 create mode 100644 geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
 create mode 100644 geant/gap_ansible/roles/fw_filters/templates/filters/term_action.j2

diff --git a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
index 933fd024..cb4208bd 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
@@ -12,7 +12,7 @@
 #     state: directory
 #     mode: '0755'
 
-- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/filters_{{ gen_filters[0].name }}.conf"
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf"
   # when: verb in ["deploy", "update", "terminate"]
   ansible.builtin.template:
   # ansible.builtin.blockinfile:
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/main.yml b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
index cbbc75d1..ffef215d 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/main.yml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
@@ -1,17 +1,12 @@
 ---
 # tasks file for fw_filters
-- name: Include filter compilation
-  ansible.builtin.include_tasks: compile.yaml
 
-# - name: Touch output file
-#   ansible.builtin.file:
-#     path: "/var/tmp/ansible_run_{{ opid }}/filters.conf"
-#     state: touch
-#     mode: '0755'
-#     modification_time: preserve
-#     access_time: preserve
+- name: Include preparation of FW vars
+  ansible.builtin.include_tasks: merge_variables.yaml
+
+- name: Print out gen_filters
+  ansible.builtin.debug:
+    var: gen_filters
 
-# - name: Assemble all FW files
-#   ansible.builtin.assemble:
-#     src: "/var/tmp/ansible_run_{{ opid }}"
-#     dest: "/var/tmp/filters.conf"
+- name: Include filter compilation
+  ansible.builtin.include_tasks: compile.yaml
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
new file mode 100644
index 00000000..335e27c5
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
@@ -0,0 +1,30 @@
+---
+# Prepare FW vars depending on the "service_type" and "custom_filters"
+- name: Prepare FW vars for NREN L3 Core Service with custom filters
+  when: >-
+    subscription.product.product_type == "NRENL3CoreService"
+    and
+    fw_sbp.sbp.custom_firewall_filters | ansible.builtin.bool
+  block:
+    - name: Merge NREN custom filters if selected
+      ansible.builtin.set_fact:
+        custom_edge_fw: "{{ [STANDARD_NREN_FW__to_merge, CUSTOM_NREN_FW] | community.general.lists_mergeby('name',
+                                                                            recursive=true, list_merge='append') }}"
+
+    - name: Debug custom_edge_fw
+      ansible.builtin.debug:
+        var: custom_edge_fw
+
+    - name: Combine Custom and standard EDGE filters
+      ansible.builtin.set_fact:
+        gen_filters: "{{ [STANDARD_EDGE_FW__to_merge, custom_edge_fw] | community.general.lists_mergeby('name') }}"
+
+- name: Prepare FW vars for NREN L3 Core Service with custom filters
+  when: >-
+    subscription.product.product_type == "NRENL3CoreService"
+    and
+    not fw_sbp.sbp.custom_firewall_filters | ansible.builtin.bool
+  block:
+    - name: Merge NREN custom filters if selected
+      ansible.builtin.set_fact:
+        gen_filters: "{{ lookup('community.general.merge_variables', 'FW__to_merge', pattern_type='suffix') }}"
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
index ff3fd96e..fe4c57f0 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
@@ -42,28 +42,28 @@
   {% if is_cpm_filter %}
         <admin-state>{{ filter.admin_state }}</admin-state>
   {% endif %}
-  {% for term in filter.terms %}
-    {% if term.offset is defined %}
-      {% set ns3 = namespace(entry_id = term.offset | int) %}
-    {% endif %}
-    {% if term.from is not defined %}
+  {# Filter can be without terms, but with embedded items #}
+  {% if filter.terms is defined %}
+    {% for term in filter.terms %}
+      {% if term.offset is defined %}
+        {% set ns3 = namespace(entry_id = term.offset | int) %}
+      {% endif %}
+      {% if term.from is not defined %}
           <entry>
             <entry-id>{{ ns3.entry_id }}</entry-id>
             <description>{{ term.name }}</description>
             {% if term.log is defined %}
             <log>{{ term.log }}</log>
             {% endif %}
-            <action>
-                <{{term.action}}></{{term.action}}>
-            </action>
+            {% include 'filters/term_action.j2' if term.action is defined %}
           </entry>
-    {% endif %}
+      {% endif %}
 
-    {% if term.from is defined %}
-      {# Special cases where from.protocol is defined #}
-      {% if term.from.protocol is defined %}
-        {# This is the case for TCP_ESTABLISHED #}
-        {% if term.from.protocol == "tcp" and term.from.tcp_flag is defined %}
+      {% if term.from is defined %}
+        {# Special cases where from.protocol is defined #}
+        {% if term.from.protocol is defined %}
+          {# This is the case for TCP_ESTABLISHED #}
+          {% if term.from.protocol == "tcp" and term.from.tcp_flag is defined %}
           <entry>
             <entry-id>{{ ns3.entry_id }}</entry-id>
             <description>{{ term.name }}</description>
@@ -80,22 +80,22 @@
                 <{{ term.from.tcp_flag }}>true</{{ term.from.tcp_flag }}>
               </tcp-flags>
             </match>
-            <action>
-              <{{ term.action }}></{{ term.action }}>
-            </action>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
           </entry>
-          {% set ns3.entry_id = ns3.entry_id + 10 %}
-        {% endif %}
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+          {% endif %}
         {# Generic ICMP filters with ICMP types #}
-        {% if (term.from.protocol == "icmp" or term.from.protocol == "ipv6-icmp") %}
-          {% if term.from.icmp_types is defined %}
-            {% for icmp_type in term.from.icmp_types %}
+          {% if (term.from.protocol == "icmp" or term.from.protocol == "ipv6-icmp") %}
+            {% if term.from.icmp_types is defined %}
+              {% for icmp_type in term.from.icmp_types %}
             <entry>
               <entry-id>{{ ns3.entry_id }}</entry-id>
               <description>{{ term.name }}</description>
-              {% if term.log is defined %}
+                {% if term.log is defined %}
               <log>{{ term.log }}</log>
-              {% endif %}
+                {% endif %}
               <match>
                     {% if filter.family == "ipv4" %}
                 <protocol>{{ term.from.protocol }}</protocol>
@@ -106,16 +106,16 @@
                     <type>{{ icmp_type }}</type>
                   </icmp>
               </match>
-              <action>
-                <{{ term.action }}></{{ term.action }}>
-              </action>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
             </entry>
           {% set ns3.entry_id = ns3.entry_id + 10 %}
-            {% endfor %}
+              {% endfor %}
+            {% endif %}
           {% endif %}
-        {% endif %}
         {# Case when only need to match on protocol, e.g. PIM #}
-        {% if term.from.protocol in ['pim', '58'] %}
+          {% if term.from.protocol in ['pim', '58'] %}
             <entry>
               <entry-id>{{ ns3.entry_id }}</entry-id>
               <description>{{ term.name }}</description>
@@ -129,39 +129,39 @@
                 <next-header>{{ term.from.protocol }}</next-header>
                     {% endif %}
               </match>
-              <action>
-                <{{ term.action }}></{{ term.action }}>
-              </action>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
             </entry>
-          {% set ns3.entry_id = ns3.entry_id + 10 %}
+            {% set ns3.entry_id = ns3.entry_id + 10 %}
+          {% endif %}
         {% endif %}
-      {% endif %}
       {# Case when both src_prefix_list and dst_prefix_list are defined #}
-      {% if term.from.src_prefix_list is defined %}
-        {% for src_prefix_list_item in term.from.src_prefix_list%}
-          {% set src_index = loop.index0 %}
-          {% if term.from.dst_prefix_list is defined %}
-            {% for dst_prefix_list_item in term.from.dst_prefix_list %}
+        {% if term.from.src_prefix_list is defined %}
+          {% for src_prefix_list_item in term.from.src_prefix_list%}
+            {% set src_index = loop.index0 %}
+            {% if term.from.dst_prefix_list is defined %}
+              {% for dst_prefix_list_item in term.from.dst_prefix_list %}
           <entry>
             <entry-id>{{ ns3.entry_id }}</entry-id>
             <description>{{ term.name }}</description>
-            {% if term.log is defined %}
+                {% if term.log is defined %}
             <log>{{ term.log }}</log>
-            {% endif %}
+                {% endif %}
             <match>
-              {% if term.from.protocol is defined %}
-                {% if filter.family == "ipv4" %}
+                {% if term.from.protocol is defined %}
+                  {% if filter.family == "ipv4" %}
               <protocol>{{term.from.protocol}}</protocol>
-                {% else %}
+                  {% else %}
               <next-header>{{ term.from.protocol }}</next-header>
-                {% endif %}
-              {% elif term.from.protocol_list is defined %}
-                {% if filter.family == "ipv4" %}
+                  {% endif %}
+                {% elif term.from.protocol_list is defined %}
+                  {% if filter.family == "ipv4" %}
               <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
-                {% else %}
+                  {% else %}
               <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
+                  {% endif %}
                 {% endif %}
-              {% endif %}
               {% include 'filters/port_list_entries.j2' %}
               <src-ip>
                 {% if filter.family == "ipv4" %}
@@ -178,34 +178,34 @@
                 {% endif %}
               </dst-ip>
             </match>
-            {% set ns3.entry_id = ns3.entry_id + 10 %}
-            <action>
-                <{{term.action}}></{{term.action}}>
-            </action>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+              {% set ns3.entry_id = ns3.entry_id + 10 %}
           </entry>
-            {% endfor %}
-          {% else %}
+              {% endfor %}
+            {% else %}
             {# src_prefix_list is defined, dst_prefix_list is not #}
           <entry>
-            <entry-id> {{ ns3.entry_id }} </entry-id>
+            <entry-id>{{ ns3.entry_id }}</entry-id>
             <description>{{ term.name }}</description>
-            {% if term.log is defined %}
+              {% if term.log is defined %}
             <log>{{ term.log }}</log>
-            {% endif %}
+              {% endif %}
             <match>
-            {% if term.from.protocol is defined %}
-                {% if filter.family == "ipv4" %}
+              {% if term.from.protocol is defined %}
+                  {% if filter.family == "ipv4" %}
               <protocol>{{term.from.protocol}}</protocol>
-                {% else %}
+                  {% else %}
               <next-header>{{ term.from.protocol }}</next-header>
-                {% endif %}
-            {% elif term.from.protocol_list is defined %}
-                {% if filter.family == "ipv4" %}
+                  {% endif %}
+              {% elif term.from.protocol_list is defined %}
+                  {% if filter.family == "ipv4" %}
               <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
-                {% else %}
+                  {% else %}
               <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
-                {% endif %}
-            {% endif %}
+                  {% endif %}
+              {% endif %}
             {% include 'filters/port_list_entries.j2' %}
               <src-ip>
                 {% if filter.family == "ipv4" %}
@@ -215,16 +215,16 @@
                 {% endif %}
               </src-ip>
             </match>
-            {% set ns3.entry_id = ns3.entry_id + 10 %}
-            <action>
-                <{{term.action}}></{{term.action}}>
-            </action>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
+              {% set ns3.entry_id = ns3.entry_id + 10 %}
           </entry>
-          {% endif %}
-        {% endfor %}
+            {% endif %}
+          {% endfor %}
       {# Case where only DST prefix list is defined #}
-      {% elif term.from.dst_prefix_list is defined %}
-        {% for dst_prefix_list_item in term.from.dst_prefix_list %}
+        {% elif term.from.dst_prefix_list is defined %}
+          {% for dst_prefix_list_item in term.from.dst_prefix_list %}
           <entry>
             <entry-id>{{ ns3.entry_id }}</entry-id>
             <description>{{ term.name }}</description>
@@ -254,14 +254,14 @@
                 {% endif %}
               </dst-ip>
             </match>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
             {% set ns3.entry_id = ns3.entry_id + 10 %}
-            <action>
-                <{{term.action}}></{{term.action}}>
-            </action>
           </entry>
-        {% endfor %}
+          {% endfor %}
       {# term.from.protocol and ports are defined, but not SRC or DST prefix list - e.g. IPv4 traceroute #}
-      {% elif term.from.protocol is defined and term.from.protocol in ['udp'] %}
+        {% elif term.from.protocol is defined and term.from.protocol in ['udp'] %}
           <entry>
             <entry-id>{{ ns3.entry_id }}</entry-id>
             <description>{{ term.name }}</description>
@@ -276,14 +276,16 @@
                   {% endif %}
             {% include 'filters/port_list_entries.j2' %}
             </match>
-            <action>
-              <{{ term.action }}></{{ term.action }}>
+            {% if term.action is defined %}
+            {% include 'filters/term_action.j2' %}
+            {% endif %}
             </action>
           </entry>
           {% set ns3.entry_id = ns3.entry_id + 10 %}
+        {% endif %}
       {% endif %}
-    {% endif %}
-  {% endfor %}
+    {% endfor %}
+  {% endif %}
   {# Terms end #}
   {% if filter.family == "ipv4" %}
         </ip-filter>
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
index 5ec27751..e4b84c31 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/gen_filters.j2
@@ -1,5 +1,7 @@
+{% if is_standalone_run %}
 <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
     <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
+{% endif %}
 
 {% with is_cpm_filter=False, filters=gen_filters %}
 
@@ -11,6 +13,8 @@
 
 {% endwith %}
 
+{% if is_standalone_run %}
    </configure>
 </config>
+{% endif %}
 
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
index 4e1cdc7b..dad8d8f8 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_definitions.j2
@@ -1,66 +1,68 @@
-{# This template takes care of configuring connectors and breakouts #}
+{# Goes through the list of terms in a filter and configures port-lists #}
 
-  <match-list>
-  {% for filter in filters %}
+    <match-list>
+{% for filter in filters %}
+  {% if filter.terms is defined %}
     {% for term in filter.terms %}
-    {% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
-    <port-list>
-      <port-list-name>{{filter.name}}-{{term.name}}-PORTS</port-list-name>
-      {%for port in term.from.port %}
-        <port>
-            <value>{{port}}</value>
-        </port>
-      {% endfor %}
-    </port-list>
-    {% endif %}
-    {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
-    <port-list>
-      <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list-name>
-      {%for port in term.from.src_port %}
-        <port>
-          <value>{{port}}</value>
-        </port>
-      {% endfor %}
-    </port-list>
-    {% endif %}
-    {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
-    <port-list>
-      <port-list-name>{{filter.name}}-{{term.name}}-DST_PORTS</port-list-name>
-      {%for port in term.from.dst_port %}
-        <port>
-          <value>{{port}}</value>
-        </port>
-      {% endfor %}
-      </port-list>
-    {% endif %}
-    {% if term.from.port_range is defined %}
-    <port-list>
-      <port-list-name>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list-name>
-      <range>
-        <start>{{ term.from.port_range.start }}</start>
-        <end>{{ term.from.port_range.end }}</end>
-      </range>
-    </port-list>
-    {% endif %}
-    {% if term.from.src_port_range is defined %}
-    <port-list>
-      <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list-name>
-      <range>
-        <start>{{ term.from.src_port_range.start }}</start>
-        <end>{{ term.from.src_port_range.end }}</end>
-      </range>
-    </port-list>
-    {% endif %}
-    {% if term.from.dst_port_range is defined %}
-    <port-list>
-      <port-list-name>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list-name>
-      <range>
-        <start>{{ term.from.dst_port_range.start }}</start>
-        <end>{{ term.from.dst_port_range.end }}</end>
-      </range>
-    </port-list>
-    {% endif %}
+      {% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-PORTS</port-list-name>
+        {%for port in term.from.port %}
+            <port>
+                <value>{{port}}</value>
+            </port>
+        {% endfor %}
+        </port-list>
+      {% endif %}
+      {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list-name>
+        {%for port in term.from.src_port %}
+            <port>
+                <value>{{port}}</value>
+            </port>
+        {% endfor %}
+        </port-list>
+      {% endif %}
+      {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-DST_PORTS</port-list-name>
+        {%for port in term.from.dst_port %}
+            <port>
+                <value>{{port}}</value>
+            </port>
+        {% endfor %}
+          </port-list>
+      {% endif %}
+      {% if term.from.port_range is defined %}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list-name>
+            <range>
+                <start>{{ term.from.port_range.start }}</start>
+                <end>{{ term.from.port_range.end }}</end>
+            </range>
+        </port-list>
+      {% endif %}
+      {% if term.from.src_port_range is defined %}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list-name>
+            <range>
+                <start>{{ term.from.src_port_range.start }}</start>
+                <end>{{ term.from.src_port_range.end }}</end>
+            </range>
+        </port-list>
+      {% endif %}
+      {% if term.from.dst_port_range is defined %}
+        <port-list>
+            <port-list-name>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list-name>
+            <range>
+                <start>{{ term.from.dst_port_range.start }}</start>
+                <end>{{ term.from.dst_port_range.end }}</end>
+            </range>
+        </port-list>
+      {% endif %}
     {% endfor %}
-  {% endfor %}
-  </match-list>
+  {% endif %}
+{% endfor %}
+    </match-list>
 
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
index a6702ba9..48c50c70 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/port_list_entries.j2
@@ -1,48 +1,48 @@
 {#This is the case it's a port-list #}
 {% if term.from.port is defined and term.from.port.__class__.__name__ == 'list'%}
-        <port>
-            <port-list>{{filter.name}}-{{term.name}}-PORTS</port-list>
-        </port>
+            <port>
+                <port-list>{{filter.name}}-{{term.name}}-PORTS</port-list>
+            </port>
 {% endif %}
 {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ == 'list'%}
-        <src-port>
-            <port-list>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list>
-        </src-port>
+            <src-port>
+                <port-list>{{filter.name}}-{{term.name}}-SRC_PORTS</port-list>
+            </src-port>
 {% endif %}
 {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ == 'list'%}
-        <dst-port>
-            <port-list>{{filter.name}}-{{term.name}}-DST_PORTS</port-list>
-        </dst-port>
+            <dst-port>
+                <port-list>{{filter.name}}-{{term.name}}-DST_PORTS</port-list>
+            </dst-port>
 {% endif %}
 {#This is the case it's a single port #}
 {% if term.from.port is defined and term.from.port.__class__.__name__ != 'list'%}
-        <port>
-            <eq>{{term.from.port}}</eq>
-        </port>
+            <port>
+                <eq>{{term.from.port}}</eq>
+            </port>
 {% endif %}
 {% if term.from.src_port is defined and term.from.src_port.__class__.__name__ != 'list'%}
-        <src-port>
-            <eq>{{term.from.src_port}}</eq>
-        </src-port>
+            <src-port>
+                <eq>{{term.from.src_port}}</eq>
+            </src-port>
 {% endif %}
 {% if term.from.dst_port is defined and term.from.dst_port.__class__.__name__ != 'list'%}
-        <dst-port>
-          <eq>{{term.from.dst_port}}</eq>
-        </dst-port>
+            <dst-port>
+                <eq>{{term.from.dst_port}}</eq>
+            </dst-port>
 {% endif %}
  {# Port range #}
  {% if term.from.port_range is defined %}
-        <port>
-            <port-list>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list>
-        </port>
+            <port>
+                <port-list>{{filter.name}}-{{term.name}}-PORT_RANGE</port-list>
+            </port>
 {% endif %}
 {% if term.from.src_port_range is defined %}
-        <src-port>
-            <port-list>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list>
-        </src-port>
+            <src-port>
+                <port-list>{{filter.name}}-{{term.name}}-SRC_PORT_RANGE</port-list>
+            </src-port>
 {% endif %}
 {% if term.from.dst_port_range is defined %}
-        <dst-port>
-            <port-list>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list>
-        </dst-port>
+            <dst-port>
+                <port-list>{{filter.name}}-{{term.name}}-DST_PORT_RANGE</port-list>
+            </dst-port>
 {% endif %}
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
index b5fa3c9a..1cbfac33 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
@@ -1,19 +1,21 @@
 {# This template takes care of configuring connectors and breakouts #}
 
-  <match-list>
-  {% for filter in filters %}
+    <match-list>
+{% for filter in filters %}
+  {% if filter.terms is defined %}
     {% for term in filter.terms %}
       {% if term.from.protocol_list is defined and term.from.protocol_list.__class__.__name__ == 'list' %}
-    <protocol-list>
-      <protocol-list-name>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list-name>
+        <protocol-list>
+            <protocol-list-name>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list-name>
         {%for protocol in term.from.protocol_list %}
-        <protocol>
-            <protocol-id>{{ protocol }}</protocol-id>
-        </protocol>
+            <protocol>
+                <protocol-id>{{ protocol }}</protocol-id>
+            </protocol>
         {% endfor %}
-    </protocol-list>
+        </protocol-list>
       {% endif %}
     {% endfor %}
-  {% endfor %}
-  </match-list>
+  {% endif %}
+{% endfor %}
+    </match-list>
 
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/term_action.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/term_action.j2
new file mode 100644
index 00000000..e9c2d024
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/term_action.j2
@@ -0,0 +1,15 @@
+            <action>
+                <{{term.action}}></{{term.action}}>
+                {% if term.action_context is defined %}
+                  {% for act in term.action_context %}
+                    {% if act.type in ['rate-limit'] %}
+                <{{ act.type }}>
+                    {% for kind, kind_val in act.kinds.items() %}
+                      <{{ kind }}>{{ kind_val }}</{{ kind }}>
+                    {% endfor %}
+                </{{ act.type }}>
+                    {% endif %}
+                  {% endfor %}
+                {% endif %}
+            </action>
+
diff --git a/geant/gap_ansible/roles/fw_filters/vars/main.yml b/geant/gap_ansible/roles/fw_filters/vars/main.yml
index 944de332..2b4e499d 100644
--- a/geant/gap_ansible/roles/fw_filters/vars/main.yml
+++ b/geant/gap_ansible/roles/fw_filters/vars/main.yml
@@ -1,2 +1,3 @@
 ---
 # vars file for fw_filters
+is_standalone_run: false
-- 
GitLab


From 914f98a462d676d223883a3c7d7ddc25c83b01eb Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Tue, 5 Nov 2024 10:58:13 +0000
Subject: [PATCH 08/46] FW role finishing

- Added `deploy_fw` for testing. It will kick off if `is_standalone_run`
var is set to `true` in role vars.
- Protocol-lists: SROS name limit to 32 chars.
- General cleanup
---
 .../playbooks/nren_l3_core_service.yaml       | 27 +++++-------
 .../roles/fw_filters/tasks/compile.yaml       | 10 -----
 .../roles/fw_filters/tasks/deploy_fw.yaml     | 41 +++++++++++++++++++
 .../roles/fw_filters/tasks/main.yml           |  8 ++--
 .../fw_filters/tasks/merge_variables.yaml     |  4 +-
 .../templates/filters/fw_filters.j2           | 14 +++----
 .../filters/protocol_list_definitions.j2      |  2 +-
 7 files changed, 65 insertions(+), 41 deletions(-)
 create mode 100644 geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml

diff --git a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
index 0b3163a5..d8cd8a10 100644
--- a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
+++ b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
@@ -27,28 +27,21 @@
       ansible.builtin.include_vars:
         dir: /opt/ansible_inventory/geant_partners/{{ partner_name | lower }}
 
-    - name: Compile Prefix Lists
-      block:
-        - name: Include Prefix-list role
-          ansible.builtin.include_role:
-            name: prefix_lists
+    # - name: Compile Prefix Lists
+    #   block:
+    #     - name: Include Prefix-list role
+    #       ansible.builtin.include_role:
+    #         name: prefix_lists
 
     - name: Compile Firewall filters
       block:
-        - name: Merge Edge filters
-          ansible.builtin.set_fact:
-            edge_fw: "{{ lookup('community.general.merge_variables', 'edgefw__to_merge') }}"
-
         - name: Include Filter role
           ansible.builtin.include_role:
             name: fw_filters
-          vars:
-            gen_filters: "{{ edge_fw }}"
-          # loop:
-          #   - "{{ IPV4_EDGE_IN }}"
-          #   - "{{ JISC_EDGE_IN }}"
-          # loop_control:
-          #   loop_var: gen_filters
+          loop:
+            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+          loop_control:
+            loop_var: fw_sbp
 
     - name: Compile SBP config
       block:
@@ -69,8 +62,8 @@
             name: bgp_config
 
     - name: Deploy
+      when: verb == deploy
       block:
         - name: Include deployment role
           ansible.builtin.include_role:
             name: deploy_service_config
-      when: verb == deploy  
\ No newline at end of file
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
index cb4208bd..6393b382 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
@@ -1,23 +1,13 @@
 ---
 - name: Set ansible host to localhost to compile template
-  # when:
-  #   item.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
   ansible.builtin.set_fact:
     ansible_host: "localhost"
     ansible_connection: local
 
-# - name: Create a folder for all the things
-#   ansible.builtin.file:
-#     path: "/var/tmp/ansible_run_{{ opid }}"
-#     state: directory
-#     mode: '0755'
-
 - name: Print the template in "/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf"
   # when: verb in ["deploy", "update", "terminate"]
   ansible.builtin.template:
-  # ansible.builtin.blockinfile:
     src: "filters/gen_filters.j2"
-    # block: "{{ lookup('ansible.builtin.template', 'filters/gen_filters.j2') }}"
     dest: "/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf"
     lstrip_blocks: true
     trim_blocks: true
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
new file mode 100644
index 00000000..ee4b59fd
--- /dev/null
+++ b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: fw_sbp.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ fw_sbp.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ fw_sbp.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[fw_sbp.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[fw_sbp.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/main.yml b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
index ffef215d..15281b51 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/main.yml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/main.yml
@@ -4,9 +4,9 @@
 - name: Include preparation of FW vars
   ansible.builtin.include_tasks: merge_variables.yaml
 
-- name: Print out gen_filters
-  ansible.builtin.debug:
-    var: gen_filters
-
 - name: Include filter compilation
   ansible.builtin.include_tasks: compile.yaml
+
+- name: Include filter compilation
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_fw.yaml
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
index 335e27c5..f525dc01 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
@@ -19,12 +19,12 @@
       ansible.builtin.set_fact:
         gen_filters: "{{ [STANDARD_EDGE_FW__to_merge, custom_edge_fw] | community.general.lists_mergeby('name') }}"
 
-- name: Prepare FW vars for NREN L3 Core Service with custom filters
+- name: Prepare FW vars for NREN L3 Core Service with standard filters
   when: >-
     subscription.product.product_type == "NRENL3CoreService"
     and
     not fw_sbp.sbp.custom_firewall_filters | ansible.builtin.bool
   block:
-    - name: Merge NREN custom filters if selected
+    - name: Merge NREN standard filters
       ansible.builtin.set_fact:
         gen_filters: "{{ lookup('community.general.merge_variables', 'FW__to_merge', pattern_type='suffix') }}"
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
index fe4c57f0..3396d8a5 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/fw_filters.j2
@@ -14,7 +14,7 @@
         <default-action>{{ filter.default_action }}</default-action>
       {% endif %}
       {% if filter.chain_to_system_filter is defined %}
-        <chain-to-system-filter>{{ filter.chain_to_system_filter }}</chain-to-system-filter>
+        <chain-to-system-filter>{{ filter.chain_to_system_filter | lower }}</chain-to-system-filter>
       {% endif %}
       {% if filter.embed is defined %}
         <embed>
@@ -157,9 +157,9 @@
                   {% endif %}
                 {% elif term.from.protocol_list is defined %}
                   {% if filter.family == "ipv4" %}
-              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list>
                   {% else %}
-              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTO</next-header-list>
                   {% endif %}
                 {% endif %}
               {% include 'filters/port_list_entries.j2' %}
@@ -201,9 +201,9 @@
                   {% endif %}
               {% elif term.from.protocol_list is defined %}
                   {% if filter.family == "ipv4" %}
-              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list>
                   {% else %}
-              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTO</next-header-list>
                   {% endif %}
               {% endif %}
             {% include 'filters/port_list_entries.j2' %}
@@ -240,9 +240,9 @@
                 {% endif %}
               {% elif term.from.protocol_list is defined %}
                 {% if filter.family == "ipv4" %}
-              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list>
+              <protocol-list>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list>
                 {% else %}
-              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTOCOLS</next-header-list>
+              <next-header-list>{{ filter.name }}-{{ term.name }}-PROTO</next-header-list>
                 {% endif %}
               {% endif %}
             {% include 'filters/port_list_entries.j2' %}
diff --git a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2 b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
index 1cbfac33..2c985ecc 100644
--- a/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
+++ b/geant/gap_ansible/roles/fw_filters/templates/filters/protocol_list_definitions.j2
@@ -6,7 +6,7 @@
     {% for term in filter.terms %}
       {% if term.from.protocol_list is defined and term.from.protocol_list.__class__.__name__ == 'list' %}
         <protocol-list>
-            <protocol-list-name>{{ filter.name }}-{{ term.name }}-PROTOCOLS</protocol-list-name>
+            <protocol-list-name>{{ filter.name }}-{{ term.name }}-PROTO</protocol-list-name>
         {%for protocol in term.from.protocol_list %}
             <protocol>
                 <protocol-id>{{ protocol }}</protocol-id>
-- 
GitLab


From b8ba16469539a0cfd41721510cfeea778cc7f3ec Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 8 Nov 2024 15:49:26 +0000
Subject: [PATCH 09/46] FW filters role and SBP initial work

---
 .../playbooks/nren_l3_core_service.yaml       |  6 +-
 .../roles/fw_filters/meta/main.yml            | 13 +++--
 .../roles/fw_filters/tasks/deploy_fw.yaml     | 10 ++--
 .../fw_filters/tasks/merge_variables.yaml     |  8 +--
 .../roles/fw_filters/vars/main.yml            |  2 +-
 geant/gap_ansible/roles/sbp/meta/main.yml     | 13 +++--
 .../gap_ansible/roles/sbp/tasks/compile.yaml  | 15 +++++
 .../roles/sbp/tasks/deploy_sbp.yaml           | 41 ++++++++++++++
 geant/gap_ansible/roles/sbp/tasks/main.yml    |  7 +++
 .../roles/sbp/tempates/deploy_sbp.j2          | 55 +++++++++++++++++++
 geant/gap_ansible/roles/sbp/tests/inventory   |  2 -
 geant/gap_ansible/roles/sbp/tests/test.yml    |  5 --
 geant/gap_ansible/roles/sbp/vars/main.yml     |  3 +
 13 files changed, 148 insertions(+), 32 deletions(-)
 create mode 100644 geant/gap_ansible/roles/sbp/tasks/compile.yaml
 create mode 100644 geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
 create mode 100644 geant/gap_ansible/roles/sbp/tempates/deploy_sbp.j2
 delete mode 100644 geant/gap_ansible/roles/sbp/tests/inventory
 delete mode 100644 geant/gap_ansible/roles/sbp/tests/test.yml

diff --git a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
index d8cd8a10..081584b8 100644
--- a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
+++ b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
@@ -41,13 +41,17 @@
           loop:
             "{{ subscription.nren_l3_core_service.nren_ap_list }}"
           loop_control:
-            loop_var: fw_sbp
+            loop_var: ap
 
     - name: Compile SBP config
       block:
         - name: Include SBP role
           ansible.builtin.include_role:
             name: sbp
+          loop:
+            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+          loop_control:
+            loop_var: ap
 
     - name: Compile BGP policies
       block:
diff --git a/geant/gap_ansible/roles/fw_filters/meta/main.yml b/geant/gap_ansible/roles/fw_filters/meta/main.yml
index ea68190c..36d899dd 100644
--- a/geant/gap_ansible/roles/fw_filters/meta/main.yml
+++ b/geant/gap_ansible/roles/fw_filters/meta/main.yml
@@ -1,7 +1,7 @@
 galaxy_info:
-  author: your name
-  description: your role description
-  company: your company (optional)
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  company: GEANT
 
   # If the issue tracker for your role is not on github, uncomment the
   # next line and provide a value
@@ -14,14 +14,15 @@ galaxy_info:
   # - GPL-3.0-only
   # - Apache-2.0
   # - CC-BY-4.0
-  license: license (GPL-2.0-or-later, MIT, etc)
+  license: MIT
 
-  min_ansible_version: 2.1
+  min_ansible_version: '2.10'
 
   # If this a Container Enabled role, provide the minimum Ansible Container version.
   # min_ansible_container_version:
 
-  galaxy_tags: []
+  galaxy_tags:
+    - network
     # List tags for your role here, one per line. A tag is a keyword that describes
     # and categorizes the role. Users find roles by searching for tags. Be sure to
     # remove the '[]' above, if you add tags to this list.
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
index ee4b59fd..27e4357c 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
@@ -4,15 +4,15 @@
     dir: /opt/ansible_inventory/group_vars/all
 
 - name: Set ansible_host to terminal server when router is offline
-  when: fw_sbp.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
   ansible.builtin.set_fact:
-    ansible_host: "{{ fw_sbp.sbp.edge_port.node.router_site.site_ts_address }}"
-    ansible_port: "{{ fw_sbp.sbp.edge_port.node.router_ts_port }}"
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
 
 - name: Load netconf connection config
   ansible.builtin.set_fact:
-    ansible_connection: "{{ netconf_access[fw_sbp.sbp.edge_port.node.vendor].ansible_connection }}"
-    ansible_network_os: "{{ netconf_access[fw_sbp.sbp.edge_port.node.vendor].ansible_network_os }}"
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
 
 - name: Deploy FW config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
   when: dry_run | ansible.builtin.bool
diff --git a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
index f525dc01..16062a4e 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
@@ -4,17 +4,13 @@
   when: >-
     subscription.product.product_type == "NRENL3CoreService"
     and
-    fw_sbp.sbp.custom_firewall_filters | ansible.builtin.bool
+    ap.sbp.custom_firewall_filters | ansible.builtin.bool
   block:
     - name: Merge NREN custom filters if selected
       ansible.builtin.set_fact:
         custom_edge_fw: "{{ [STANDARD_NREN_FW__to_merge, CUSTOM_NREN_FW] | community.general.lists_mergeby('name',
                                                                             recursive=true, list_merge='append') }}"
 
-    - name: Debug custom_edge_fw
-      ansible.builtin.debug:
-        var: custom_edge_fw
-
     - name: Combine Custom and standard EDGE filters
       ansible.builtin.set_fact:
         gen_filters: "{{ [STANDARD_EDGE_FW__to_merge, custom_edge_fw] | community.general.lists_mergeby('name') }}"
@@ -23,7 +19,7 @@
   when: >-
     subscription.product.product_type == "NRENL3CoreService"
     and
-    not fw_sbp.sbp.custom_firewall_filters | ansible.builtin.bool
+    not ap.sbp.custom_firewall_filters | ansible.builtin.bool
   block:
     - name: Merge NREN standard filters
       ansible.builtin.set_fact:
diff --git a/geant/gap_ansible/roles/fw_filters/vars/main.yml b/geant/gap_ansible/roles/fw_filters/vars/main.yml
index 2b4e499d..161f1549 100644
--- a/geant/gap_ansible/roles/fw_filters/vars/main.yml
+++ b/geant/gap_ansible/roles/fw_filters/vars/main.yml
@@ -1,3 +1,3 @@
 ---
 # vars file for fw_filters
-is_standalone_run: false
+is_standalone_run: true
diff --git a/geant/gap_ansible/roles/sbp/meta/main.yml b/geant/gap_ansible/roles/sbp/meta/main.yml
index ea68190c..36d899dd 100644
--- a/geant/gap_ansible/roles/sbp/meta/main.yml
+++ b/geant/gap_ansible/roles/sbp/meta/main.yml
@@ -1,7 +1,7 @@
 galaxy_info:
-  author: your name
-  description: your role description
-  company: your company (optional)
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  company: GEANT
 
   # If the issue tracker for your role is not on github, uncomment the
   # next line and provide a value
@@ -14,14 +14,15 @@ galaxy_info:
   # - GPL-3.0-only
   # - Apache-2.0
   # - CC-BY-4.0
-  license: license (GPL-2.0-or-later, MIT, etc)
+  license: MIT
 
-  min_ansible_version: 2.1
+  min_ansible_version: '2.10'
 
   # If this a Container Enabled role, provide the minimum Ansible Container version.
   # min_ansible_container_version:
 
-  galaxy_tags: []
+  galaxy_tags:
+    - network
     # List tags for your role here, one per line. A tag is a keyword that describes
     # and categorizes the role. Users find roles by searching for tags. Be sure to
     # remove the '[]' above, if you add tags to this list.
diff --git a/geant/gap_ansible/roles/sbp/tasks/compile.yaml b/geant/gap_ansible/roles/sbp/tasks/compile.yaml
new file mode 100644
index 00000000..4cc1de30
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/compile.yaml
@@ -0,0 +1,15 @@
+---
+- name: Set ansible host to localhost to compile template
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf"
+  # when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "{{ verb }}_sbp.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml b/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
new file mode 100644
index 00000000..07814136
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/sbp/tasks/main.yml b/geant/gap_ansible/roles/sbp/tasks/main.yml
index a36a1f3e..d28e0a8c 100644
--- a/geant/gap_ansible/roles/sbp/tasks/main.yml
+++ b/geant/gap_ansible/roles/sbp/tasks/main.yml
@@ -1,2 +1,9 @@
 ---
 # tasks file for sbp
+
+- name: Include filter compilation
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Include filter compilation
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_sbp.yaml
diff --git a/geant/gap_ansible/roles/sbp/tempates/deploy_sbp.j2 b/geant/gap_ansible/roles/sbp/tempates/deploy_sbp.j2
new file mode 100644
index 00000000..08b6a312
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tempates/deploy_sbp.j2
@@ -0,0 +1,55 @@
+{% if is_standalone_run %}
+<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
+{% endif %}
+
+        <service xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+            <ies xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+                <interface alu:operation="replace">
+                    <interface-name>{{ lag_name }}.{{ ap.sbp.vlan_id }}</interface-name>
+                    <description>SRV_GLOBAL CUSTOMER {{ partner_name }} #{{ partner_name }}-{{ ap.sbp.ap_type }} ${{ ap.sbp.geant_sid }} | ASN{{ asn }} | </description>
+                    <ip-mtu>{{ sbp_params.ip_mtu }}</ip-mtu>
+                    <sap>
+                      {% if ap.sbp.is_tagged %}
+                        <sap-id>{{ lag_name }}:{{ ap.sbp.vlan_id }}</sap-id>
+                      {% else %}
+                        <sap-id>{{ lag_name }}</sap-id>
+                      {% endif %}
+                        <admin-state>enable</admin-state>
+                    </sap>
+                    <ipv4>
+                      {% if ap.sbp.ipv4_bfd %}
+                        <bfd>
+                            <admin-state>enable</admin-state>
+                            <transmit-interval>{{ sbp_params.bfd.ipv4.trasmit }}</transmit-interval>
+                            <receive>{{ sbp_params.bfd.ipv4.receive }}</receive>
+                            <multiplier>{{ sbp_params.bfd.ipv4.multiplier | default(3) }}</multiplier>
+                        </bfd>
+                      {% endif %}
+                        <primary>
+                            <address>{{ ap.sbp.ipv4_address }}</address>
+                            <prefix-length>{{ ap.sbp.ipv4_mask }}</prefix-length>
+                        </primary>
+                    </ipv4>
+                    <ipv6>
+                      {% if ap.sbp.ipv6_bfd %}
+                        <bfd>
+                            <admin-state>enable</admin-state>
+                            <transmit-interval>{{ sbp_params.bfd.ipv6.trasmit }}</transmit-interval>
+                            <receive>{{ sbp_params.bfd.ipv6.receive }}</receive>
+                            <multiplier>{{ sbp_params.bfd.ipv6.multiplier | default(3) }}</multiplier>
+                        </bfd>
+                      {% endif %}
+                        <address>
+                            <ipv6-address>{{ ap.sbp.ipv6_address }}</ipv6-address>
+                            <prefix-length>{{ ap.sbp.ipv6_mask }}</prefix-length>
+                        </address>
+                    </ipv6>
+                </interface>
+            </ies>
+        </service>
+
+{% if is_standalone_run %}
+   </configure>
+</config>
+{% endif %}
diff --git a/geant/gap_ansible/roles/sbp/tests/inventory b/geant/gap_ansible/roles/sbp/tests/inventory
deleted file mode 100644
index 878877b0..00000000
--- a/geant/gap_ansible/roles/sbp/tests/inventory
+++ /dev/null
@@ -1,2 +0,0 @@
-localhost
-
diff --git a/geant/gap_ansible/roles/sbp/tests/test.yml b/geant/gap_ansible/roles/sbp/tests/test.yml
deleted file mode 100644
index 028d1ad2..00000000
--- a/geant/gap_ansible/roles/sbp/tests/test.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- hosts: localhost
-  remote_user: root
-  roles:
-    - sbp
diff --git a/geant/gap_ansible/roles/sbp/vars/main.yml b/geant/gap_ansible/roles/sbp/vars/main.yml
index f4cfafe7..cdd9bee2 100644
--- a/geant/gap_ansible/roles/sbp/vars/main.yml
+++ b/geant/gap_ansible/roles/sbp/vars/main.yml
@@ -1,2 +1,5 @@
 ---
 # vars file for sbp
+is_standalone_run: true
+
+lag_name: ap.sbp.edge_port.edge_port_name
-- 
GitLab


From 721a4d10a81f9376740c85207ecda1711f1228da Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Tue, 12 Nov 2024 09:15:35 +0000
Subject: [PATCH 10/46] snapshot

---
 .../playbooks/nren_l3_core_service.yaml       |  4 ++
 geant/gap_ansible/roles/fw_filters/README.md  | 20 +++---
 .../roles/policy_options/README.md            | 20 +++---
 .../roles/policy_options/meta/main.yml        | 13 ++--
 .../roles/policy_options/tasks/compile.yaml   | 15 ++++
 .../roles/policy_options/tasks/main.yml       |  5 ++
 .../policy_options/tasks/merge_vars.yaml      |  8 +++
 .../policy_options/templates/as_paths.j2      |  6 ++
 .../policy_options/templates/communities.j2   |  8 +++
 .../templates/policy_options.j2               | 32 +++++++++
 .../templates/policy_statements.j2            | 71 +++++++++++++++++++
 .../policy_options/templates/prefix_lists.j2  | 15 ++++
 .../roles/policy_options/tests/inventory      |  2 -
 .../roles/policy_options/tests/test.yml       |  5 --
 14 files changed, 189 insertions(+), 35 deletions(-)
 create mode 100644 geant/gap_ansible/roles/policy_options/tasks/compile.yaml
 create mode 100644 geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
 create mode 100644 geant/gap_ansible/roles/policy_options/templates/as_paths.j2
 create mode 100644 geant/gap_ansible/roles/policy_options/templates/communities.j2
 create mode 100644 geant/gap_ansible/roles/policy_options/templates/policy_options.j2
 create mode 100644 geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
 create mode 100644 geant/gap_ansible/roles/policy_options/templates/prefix_lists.j2
 delete mode 100644 geant/gap_ansible/roles/policy_options/tests/inventory
 delete mode 100644 geant/gap_ansible/roles/policy_options/tests/test.yml

diff --git a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
index 081584b8..4d9e9d67 100644
--- a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
+++ b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
@@ -58,6 +58,10 @@
         - name: Include BGP policies
           ansible.builtin.include_role:
             name: policy_options
+          loop:
+            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+          loop_control:
+            loop_var: ap
 
     - name: Compile BGP sesssions config
       block:
diff --git a/geant/gap_ansible/roles/fw_filters/README.md b/geant/gap_ansible/roles/fw_filters/README.md
index 225dd44b..d5e73d98 100644
--- a/geant/gap_ansible/roles/fw_filters/README.md
+++ b/geant/gap_ansible/roles/fw_filters/README.md
@@ -1,38 +1,36 @@
 Role Name
 =========
 
-A brief description of the role goes here.
+A role for configuring IP filters in Nokia SROS.
 
 Requirements
 ------------
 
-Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+GEANT custom netconf module with Nokia "commit_comment" and "config_mode" features.
 
 Role Variables
 --------------
 
-A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+- vars/main.yaml
+- external inventory (group_vars)
+- orchestrator (GSO)
 
 Dependencies
 ------------
 
-A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+n/a
 
 Example Playbook
 ----------------
 
-Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
-
-    - hosts: servers
-      roles:
-         - { role: username.rolename, x: 42 }
+Role is supposed to be driven by GSO.
 
 License
 -------
 
-BSD
+MIT
 
 Author Information
 ------------------
 
-An optional section for the role authors to include contact information, or a website (HTML is not allowed).
+A. Kurbatov, S. Spinelli. GEANT Orchestration and Automation Team (GOAT).
diff --git a/geant/gap_ansible/roles/policy_options/README.md b/geant/gap_ansible/roles/policy_options/README.md
index 225dd44b..59f3169b 100644
--- a/geant/gap_ansible/roles/policy_options/README.md
+++ b/geant/gap_ansible/roles/policy_options/README.md
@@ -1,38 +1,36 @@
 Role Name
 =========
 
-A brief description of the role goes here.
+A role for configuring policy options stanza in Nokia SROS.
 
 Requirements
 ------------
 
-Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+GEANT custom netconf module with Nokia "commit_comment" and "config_mode" features.
 
 Role Variables
 --------------
 
-A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+- vars/main.yaml
+- external inventory (group_vars)
+- orchestrator (GSO)
 
 Dependencies
 ------------
 
-A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+n/a
 
 Example Playbook
 ----------------
 
-Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
-
-    - hosts: servers
-      roles:
-         - { role: username.rolename, x: 42 }
+Role is supposed to be driven by GSO.
 
 License
 -------
 
-BSD
+MIT
 
 Author Information
 ------------------
 
-An optional section for the role authors to include contact information, or a website (HTML is not allowed).
+A. Kurbatov, S. Spinelli. GEANT Orchestration and Automation Team (GOAT).
diff --git a/geant/gap_ansible/roles/policy_options/meta/main.yml b/geant/gap_ansible/roles/policy_options/meta/main.yml
index ea68190c..36d899dd 100644
--- a/geant/gap_ansible/roles/policy_options/meta/main.yml
+++ b/geant/gap_ansible/roles/policy_options/meta/main.yml
@@ -1,7 +1,7 @@
 galaxy_info:
-  author: your name
-  description: your role description
-  company: your company (optional)
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  company: GEANT
 
   # If the issue tracker for your role is not on github, uncomment the
   # next line and provide a value
@@ -14,14 +14,15 @@ galaxy_info:
   # - GPL-3.0-only
   # - Apache-2.0
   # - CC-BY-4.0
-  license: license (GPL-2.0-or-later, MIT, etc)
+  license: MIT
 
-  min_ansible_version: 2.1
+  min_ansible_version: '2.10'
 
   # If this a Container Enabled role, provide the minimum Ansible Container version.
   # min_ansible_container_version:
 
-  galaxy_tags: []
+  galaxy_tags:
+    - network
     # List tags for your role here, one per line. A tag is a keyword that describes
     # and categorizes the role. Users find roles by searching for tags. Be sure to
     # remove the '[]' above, if you add tags to this list.
diff --git a/geant/gap_ansible/roles/policy_options/tasks/compile.yaml b/geant/gap_ansible/roles/policy_options/tasks/compile.yaml
new file mode 100644
index 00000000..6414d2ba
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/compile.yaml
@@ -0,0 +1,15 @@
+---
+- name: Set ansible host to localhost to compile template
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf"
+  # when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "policy_options.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/policy_options/tasks/main.yml b/geant/gap_ansible/roles/policy_options/tasks/main.yml
index f6e914bb..6ec08279 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/main.yml
+++ b/geant/gap_ansible/roles/policy_options/tasks/main.yml
@@ -1,2 +1,7 @@
 ---
 # tasks file for policy_options
+- name: Load Standard Policy Statements vars
+  ansible.builtin.include_tasks: merge_vars.yaml
+ 
+- name: Compile templates
+  ansible.builtin.include_tasks: compile.yaml
diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
new file mode 100644
index 00000000..18dc993d
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -0,0 +1,8 @@
+---
+- name: Prepare Policy vars for NREN L3 Core Service with standard filters
+  when: >-
+    subscription.product.product_type == "NRENL3CoreService"
+  block:
+    - name: Merge NREN standard filters
+      ansible.builtin.set_fact:
+        standard_nren_policies: "{{ lookup('community.general.merge_variables', 'STANDARD_PO_POL_STATEMENTS') }}"
diff --git a/geant/gap_ansible/roles/policy_options/templates/as_paths.j2 b/geant/gap_ansible/roles/policy_options/templates/as_paths.j2
new file mode 100644
index 00000000..fadb9c5b
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/as_paths.j2
@@ -0,0 +1,6 @@
+    {% for as_path in as_paths_obj %}
+    <as-path alu:operation="replace">
+      <name>{{ as_path.name }}</name>
+      <expression>{{ as_path.expression}}</expression>
+    </as-path>
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/communities.j2 b/geant/gap_ansible/roles/policy_options/templates/communities.j2
new file mode 100644
index 00000000..631ddacf
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/communities.j2
@@ -0,0 +1,8 @@
+    {% for community in communities_obj %}
+    <community alu:operation="replace">
+      <name>{{ community.name }}</name>
+        <member>
+          <member>{{ community.member }}</member>
+        </member>
+    </community>
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
new file mode 100644
index 00000000..52ff79a7
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
@@ -0,0 +1,32 @@
+  <policy-options xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+  {#
+    {% if nokia_po_prefix_lists is defined %}
+      {% with prefix_lists_obj=nokia_po_prefix_lists %}
+      {% include 'policy_options/prefix_lists.j2' %}
+      {% endwith %}
+    {% endif %}
+  
+    {# Communities #}
+    {% if nokia_po_communities is defined %}
+      {% with communities_obj=nokia_po_communities %}
+      {% include 'policy_options/communities.j2' %}
+      {% endwith %}
+    {% endif %}
+  
+    {# AS paths #}
+    {% if nokia_po_as_paths is defined %}
+      {% with as_paths_obj=nokia_po_as_paths %}
+      {% include 'policy_options/as_paths.j2' %}
+      {% endwith %}
+    {% endif %}
+  #}
+
+  {# Policy statements #}
+    {% if standard_nren_policies is defined %}
+      {% with policy_obj=standard_nren_policies %}
+      {% include 'policy_options/policy_statements.j2' %}
+      {% endwith %}
+    {% endif %}
+  
+  </policy-options>
+  
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
new file mode 100644
index 00000000..13815441
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
@@ -0,0 +1,71 @@
+    {% for pol in policy_obj %}
+    <policy-statement alu:operation="replace">
+      <name>{{ pol.name }}</name>
+      <entry-type>{{ pol.entry_type }}</entry-type>
+      {% for entry in pol.entries %}
+        {% if pol.entry_type == 'named' %}
+      <named-entry>
+        {% endif %}
+        <entry-name>{{ entry.name }}</entry-name>
+        {% if entry.from is defined %}
+        <from>
+          {% if entry.from.as_path is defined %}
+            <as-path>
+            {% if entry.from.as_path.name is defined %}
+                <name>{{ entry.from.as_path.name }}</name>
+            {% endif %}
+            {% if entry.from.as_path.length is defined %}
+                <length>
+                      <value>{{ entry.from.as_path.length }}</value>
+                </length>
+            {% endif %}
+            </as-path>
+          {% endif %}
+          {% if entry.from.prefix_list is defined %}
+            {% for pl in entry.from.prefix_list %}
+            <prefix-list>{{ pl }}</prefix-list>
+            {% endfor %}
+          {% endif %}
+          {% if entry.from.policy is defined %}
+            <policy>{{ entry.from.policy }}</policy>
+          {% endif %}
+          {% if entry.from.community is defined %}
+            <community>
+                <name>{{ entry.from.community }}</name>
+            </community>
+          {% endif %}
+          {% if entry.from.origin_validation_state is defined %}
+            <origin-validation-state>{{ entry.from.origin_validation_state }}</origin-validation-state>
+          {% endif %}
+          {% if entry.from.protocol is defined %}
+            {% for proto in entry.from.protocol %}
+            <protocol>
+                  <name>{{ proto }}</name>
+            </protocol>
+            {% endfor %}
+          {% endif %}
+        </from>
+        {% endif %}
+        <action>
+            <action-type>{{ entry.action_type }}</action-type>
+          {% if entry.action is defined %}
+            {% for action_item in entry.action %}
+              {% for act_k, act_v in action_item.items() %}
+                {% if act_k == "community_add" %}
+                  {% for community in act_v %}
+            <community>
+                <add>{{ community }}</add>
+            </community>
+                  {% endfor %}
+                {% else %}
+            <{{ act_k | replace("_", "-") }}>{{ act_v }}</{{act_k  | replace("_", "-") }}>
+                {% endif %}
+              {% endfor %}
+            {% endfor %}
+          {% endif %}
+        </action>
+      </named-entry>
+      {% endfor %}
+    </policy-statement>
+
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/prefix_lists.j2 b/geant/gap_ansible/roles/policy_options/templates/prefix_lists.j2
new file mode 100644
index 00000000..507986e6
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/templates/prefix_lists.j2
@@ -0,0 +1,15 @@
+    {% for prefix_list in prefix_lists_obj %}
+    <prefix-list alu:operation="replace">
+        <name>{{ prefix_list.name }}</name>
+        {% for prefix in prefix_list.prefixes %}
+        <prefix>
+          <ip-prefix>{{ prefix.ip }}</ip-prefix>
+          <type>{{ prefix.type }}</type>
+          {% if prefix.type == 'range' %}
+          <start-length>{{ prefix.range_start_length }}</start-length>
+          <end-length>{{ prefix.range_end_length }}</end-length>
+          {% endif %}
+        </prefix>
+        {% endfor %}
+    </prefix-list>
+    {% endfor %}
diff --git a/geant/gap_ansible/roles/policy_options/tests/inventory b/geant/gap_ansible/roles/policy_options/tests/inventory
deleted file mode 100644
index 878877b0..00000000
--- a/geant/gap_ansible/roles/policy_options/tests/inventory
+++ /dev/null
@@ -1,2 +0,0 @@
-localhost
-
diff --git a/geant/gap_ansible/roles/policy_options/tests/test.yml b/geant/gap_ansible/roles/policy_options/tests/test.yml
deleted file mode 100644
index e0a0d30c..00000000
--- a/geant/gap_ansible/roles/policy_options/tests/test.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- hosts: localhost
-  remote_user: root
-  roles:
-    - policy_options
-- 
GitLab


From 01482d5e86667bb0ace700f966e6e504019db7a2 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Wed, 13 Nov 2024 18:47:41 +0000
Subject: [PATCH 11/46] policy_options role

- NREN-specific communities
- NREN policy statements
---
 .../roles/policy_options/tasks/deploy_po.yaml | 41 ++++++++++++++++
 .../roles/policy_options/tasks/main.yml       |  6 ++-
 .../policy_options/tasks/merge_vars.yaml      | 19 ++++++++
 .../templates/policy_options.j2               | 47 +++++++++++--------
 .../templates/policy_statements.j2            |  6 +++
 .../roles/policy_options/vars/main.yml        |  4 ++
 6 files changed, 102 insertions(+), 21 deletions(-)
 create mode 100644 geant/gap_ansible/roles/policy_options/tasks/deploy_po.yaml

diff --git a/geant/gap_ansible/roles/policy_options/tasks/deploy_po.yaml b/geant/gap_ansible/roles/policy_options/tasks/deploy_po.yaml
new file mode 100644
index 00000000..70b027de
--- /dev/null
+++ b/geant/gap_ansible/roles/policy_options/tasks/deploy_po.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy PO config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy PO config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_po.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/policy_options/tasks/main.yml b/geant/gap_ansible/roles/policy_options/tasks/main.yml
index 6ec08279..4fbe967f 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/main.yml
+++ b/geant/gap_ansible/roles/policy_options/tasks/main.yml
@@ -2,6 +2,10 @@
 # tasks file for policy_options
 - name: Load Standard Policy Statements vars
   ansible.builtin.include_tasks: merge_vars.yaml
- 
+
 - name: Compile templates
   ansible.builtin.include_tasks: compile.yaml
+
+- name: Deploy templates if standalone run
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_po.yaml
diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
index 18dc993d..33f69036 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -6,3 +6,22 @@
     - name: Merge NREN standard filters
       ansible.builtin.set_fact:
         standard_nren_policies: "{{ lookup('community.general.merge_variables', 'STANDARD_PO_POL_STATEMENTS') }}"
+
+    - name: Set NREN community name
+      ansible.builtin.set_fact:
+        nren_community_names: ["GEANT_{{ partner_name | upper }}", "GEANT_{{ partner_name | upper }}_BLOCK"]
+
+    - name: Set NREN community value
+      when: (partner_asn | int) < 65536
+      ansible.builtin.set_fact:
+        nren_community_values: ["{{ geant_re_as_number }}:{{ partner_asn }}", "{{ block_community_prefix }}:{{ partner_asn }}"]
+
+    - name: Set NREN community value
+      when: (partner_asn | int) > 65535
+      ansible.builtin.set_fact:
+        nren_community_values: ["origin:{{ partner_asn }}:{{ geant_re_as_number }}", "origin:{{ partner_asn }}:{{ block_community_prefix }}"]
+
+    - name: Create a list of NREN communities
+      ansible.builtin.set_fact:
+        nren_po_communities: "{{ nren_po_communities | default([]) + [ {'name': item.0, 'member': item.1} ] }}"
+      loop: "{{ nren_community_names | zip(nren_community_values) | list }}"
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
index 52ff79a7..d2f49fba 100644
--- a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
@@ -1,32 +1,39 @@
+{% if is_standalone_run %}
+<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
+{% endif %}
+
   <policy-options xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
-  {#
-    {% if nokia_po_prefix_lists is defined %}
-      {% with prefix_lists_obj=nokia_po_prefix_lists %}
-      {% include 'policy_options/prefix_lists.j2' %}
-      {% endwith %}
-    {% endif %}
-  
+  {#  {% if nokia_po_prefix_lists is defined %} #}
+  {#    {% with prefix_lists_obj=nokia_po_prefix_lists %} #}
+  {#    {% include 'policy_options/prefix_lists.j2' %} #}
+  {#    {% endwith %} #}
+  {#  {% endif %} #}
+
     {# Communities #}
-    {% if nokia_po_communities is defined %}
-      {% with communities_obj=nokia_po_communities %}
-      {% include 'policy_options/communities.j2' %}
+    {% if nren_po_communities is defined %}
+      {% with communities_obj=nren_po_communities %}
+      {% include 'communities.j2' %}
       {% endwith %}
     {% endif %}
-  
+
     {# AS paths #}
-    {% if nokia_po_as_paths is defined %}
-      {% with as_paths_obj=nokia_po_as_paths %}
-      {% include 'policy_options/as_paths.j2' %}
-      {% endwith %}
-    {% endif %}
-  #}
+  {#  {% if nokia_po_as_paths is defined %} #}
+  {#    {% with as_paths_obj=nokia_po_as_paths %} #}
+  {#    {% include 'policy_options/as_paths.j2' %} #}
+  {#    {% endwith %} #}
+  {#  {% endif %} #}
 
   {# Policy statements #}
     {% if standard_nren_policies is defined %}
       {% with policy_obj=standard_nren_policies %}
-      {% include 'policy_options/policy_statements.j2' %}
+      {% include 'policy_statements.j2' %}
       {% endwith %}
     {% endif %}
-  
+ 
   </policy-options>
-  
+ 
+{% if is_standalone_run %}
+   </configure>
+</config>
+{% endif %}
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
index 13815441..390cf595 100644
--- a/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
@@ -57,6 +57,12 @@
                 <add>{{ community }}</add>
             </community>
                   {% endfor %}
+                {% elif act_k == "bgp_med" %}
+            <bgp-med>
+                <set>{{ act_v | default(standard_bgp_med[ap_type]) }}</set>
+            </bgp-med>
+                {% elif act_k == "local_preference" %}
+            <local-preference>{{ act_v | default(standard_local_pref[ap_type]) }}</local-preference>
                 {% else %}
             <{{ act_k | replace("_", "-") }}>{{ act_v }}</{{act_k  | replace("_", "-") }}>
                 {% endif %}
diff --git a/geant/gap_ansible/roles/policy_options/vars/main.yml b/geant/gap_ansible/roles/policy_options/vars/main.yml
index 9dd8b4cc..f935f638 100644
--- a/geant/gap_ansible/roles/policy_options/vars/main.yml
+++ b/geant/gap_ansible/roles/policy_options/vars/main.yml
@@ -1,2 +1,6 @@
 ---
 # vars file for policy_options
+is_standalone_run: true
+
+site_name: "{{ ap.sbp.edge_port.node.router_site.site_name }}"
+ap_type: "{{ ap.ap_type }}"
-- 
GitLab


From fa1a42d6d93b4bd77cf1b1e2612b5f4dec8f88f8 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Wed, 13 Nov 2024 19:01:01 +0000
Subject: [PATCH 12/46] policy-options: change in partner.asn var name

---
 .../roles/policy_options/tasks/merge_vars.yaml            | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
index 33f69036..be58b438 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -12,14 +12,14 @@
         nren_community_names: ["GEANT_{{ partner_name | upper }}", "GEANT_{{ partner_name | upper }}_BLOCK"]
 
     - name: Set NREN community value
-      when: (partner_asn | int) < 65536
+      when: (partner.asn | int) < 65536
       ansible.builtin.set_fact:
-        nren_community_values: ["{{ geant_re_as_number }}:{{ partner_asn }}", "{{ block_community_prefix }}:{{ partner_asn }}"]
+        nren_community_values: ["{{ geant_re_as_number }}:{{ partner.asn }}", "{{ block_community_prefix }}:{{ partner.asn }}"]
 
     - name: Set NREN community value
-      when: (partner_asn | int) > 65535
+      when: (partner.asn | int) > 65535
       ansible.builtin.set_fact:
-        nren_community_values: ["origin:{{ partner_asn }}:{{ geant_re_as_number }}", "origin:{{ partner_asn }}:{{ block_community_prefix }}"]
+        nren_community_values: ["origin:{{ partner.asn }}:{{ geant_re_as_number }}", "origin:{{ partner.asn }}:{{ block_community_prefix }}"]
 
     - name: Create a list of NREN communities
       ansible.builtin.set_fact:
-- 
GitLab


From faf7bb5c60fa364c6a589d5d27caa5904148b53d Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 14 Nov 2024 13:05:06 +0000
Subject: [PATCH 13/46] SBP role - WIP

---
 .../gap_ansible/roles/sbp/tasks/compile.yaml  |  4 +-
 .../roles/sbp/tasks/deploy_sbp.yaml           |  4 +-
 geant/gap_ansible/roles/sbp/tasks/main.yml    |  2 +
 .../roles/sbp/tasks/merge_vars.yaml           | 47 +++++++++++++++++++
 .../sbp/{tempates => templates}/deploy_sbp.j2 | 27 ++++++++---
 geant/gap_ansible/roles/sbp/vars/main.yml     |  2 +-
 6 files changed, 74 insertions(+), 12 deletions(-)
 create mode 100644 geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
 rename geant/gap_ansible/roles/sbp/{tempates => templates}/deploy_sbp.j2 (64%)

diff --git a/geant/gap_ansible/roles/sbp/tasks/compile.yaml b/geant/gap_ansible/roles/sbp/tasks/compile.yaml
index 4cc1de30..7fe17094 100644
--- a/geant/gap_ansible/roles/sbp/tasks/compile.yaml
+++ b/geant/gap_ansible/roles/sbp/tasks/compile.yaml
@@ -4,11 +4,11 @@
     ansible_host: "localhost"
     ansible_connection: local
 
-- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf"
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf"
   # when: verb in ["deploy", "update", "terminate"]
   ansible.builtin.template:
     src: "{{ verb }}_sbp.j2"
-    dest: "/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf"
     lstrip_blocks: true
     trim_blocks: true
     mode: '0755'
diff --git a/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml b/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
index 07814136..89bdd754 100644
--- a/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
+++ b/geant/gap_ansible/roles/sbp/tasks/deploy_sbp.yaml
@@ -19,7 +19,7 @@
   geant.gap_ansible.nokia_netconf_config:
     format: xml
     default_operation: merge
-    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf') }}"
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf') }}"
     commit: true
     validate: true
     config_mode: private
@@ -32,7 +32,7 @@
   geant.gap_ansible.nokia_netconf_config:
     format: xml
     default_operation: merge
-    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/sbp_{{ partner_name }}.conf') }}"
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_sbp.conf') }}"
     commit: true
     commit_comment: "{{ commit_comment }}"
     config_mode: private
diff --git a/geant/gap_ansible/roles/sbp/tasks/main.yml b/geant/gap_ansible/roles/sbp/tasks/main.yml
index d28e0a8c..6b1049e7 100644
--- a/geant/gap_ansible/roles/sbp/tasks/main.yml
+++ b/geant/gap_ansible/roles/sbp/tasks/main.yml
@@ -1,5 +1,7 @@
 ---
 # tasks file for sbp
+- name: Merge vars
+  ansible.builtin.include_tasks: merge_vars.yaml
 
 - name: Include filter compilation
   ansible.builtin.include_tasks: compile.yaml
diff --git a/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml b/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
new file mode 100644
index 00000000..af4506b6
--- /dev/null
+++ b/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
@@ -0,0 +1,47 @@
+---
+- name: Set interface v4 BFD values
+  when: ap.sbp.v4_bfd_settings.bfd_enabled | ansible.builtin.bool
+  block:
+    - name: Set v4 BFD interval to GSO value
+      when: ap.sbp.v4_bfd_settings.bfd_interval != None
+      ansible.builtin.set_fact:
+        sbp_v4_bfd_interval: "{{ ap.sbp.v4_bfd_settings.bfd_interval }}"
+
+    - name: Set v4 BFD interval to standard value
+      when: ap.sbp.v4_bfd_settings.bfd_interval == None
+      ansible.builtin.set_fact:
+        sbp_v4_bfd_interval: "{{ sbp_params.bfd.ipv4.transmit }}"
+      # FIX: interval -> transmit + receive
+
+    - name: Set v4 BFD multiplier to GSO value
+      when: ap.sbp.v4_bfd_settings.bfd_multiplier != None
+      ansible.builtin.set_fact:
+        sbp_v4_bfd_multiplier: "{{ ap.sbp.v4_bfd_settings.bfd_multiplier }}"
+
+    - name: Set v4 BFD multiplier to standard value
+      when: ap.sbp.v4_bfd_settings.bfd_multiplier == None
+      ansible.builtin.set_fact:
+        sbp_v4_bfd_multiplier: "{{ sbp_params.bfd.ipv4.multiplier }}"
+
+- name: Set interface v6 BFD values
+  when: ap.sbp.v6_bfd_settings.bfd_enabled | ansible.builtin.bool
+  block:
+    - name: Set v6 BFD interval to GSO value
+      when: ap.sbp.v6_bfd_settings.bfd_interval != None
+      ansible.builtin.set_fact:
+        sbp_v6_bfd_interval: "{{ ap.sbp.v6_bfd_settings.bfd_interval }}"
+
+    - name: Set v6 BFD interval to standard value
+      when: ap.sbp.v6_bfd_settings.bfd_interval == None
+      ansible.builtin.set_fact:
+        sbp_v6_bfd_interval: "{{ sbp_params.bfd.ipv6.transmit }}"
+
+    - name: Set v6 BFD multiplier to GSO value
+      when: ap.sbp.v6_bfd_settings.bfd_multiplier != None
+      ansible.builtin.set_fact:
+        sbp_v6_bfd_multiplier: "{{ ap.sbp.v6_bfd_settings.bfd_multiplier }}"
+
+    - name: Set v6 BFD multiplier to standard value
+      when: ap.sbp.v6_bfd_settings.bfd_multiplier == None
+      ansible.builtin.set_fact:
+        sbp_v6_bfd_multiplier: "{{ sbp_params.bfd.ipv6.multiplier }}"
diff --git a/geant/gap_ansible/roles/sbp/tempates/deploy_sbp.j2 b/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
similarity index 64%
rename from geant/gap_ansible/roles/sbp/tempates/deploy_sbp.j2
rename to geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
index 08b6a312..7a581a43 100644
--- a/geant/gap_ansible/roles/sbp/tempates/deploy_sbp.j2
+++ b/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
@@ -5,9 +5,10 @@
 
         <service xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
             <ies xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+                <service-name>{{ ies_re_name }}</service-name>
                 <interface alu:operation="replace">
                     <interface-name>{{ lag_name }}.{{ ap.sbp.vlan_id }}</interface-name>
-                    <description>SRV_GLOBAL CUSTOMER {{ partner_name }} #{{ partner_name }}-{{ ap.sbp.ap_type }} ${{ ap.sbp.geant_sid }} | ASN{{ asn }} | </description>
+                    <description>SRV_GLOBAL CUSTOMER {{ partner_name }} #{{ partner_name }}-{{ ap.ap_type }} ${{ ap.sbp.geant_sid }} | ASN{{ partner.asn }} | </description>
                     <ip-mtu>{{ sbp_params.ip_mtu }}</ip-mtu>
                     <sap>
                       {% if ap.sbp.is_tagged %}
@@ -16,14 +17,26 @@
                         <sap-id>{{ lag_name }}</sap-id>
                       {% endif %}
                         <admin-state>enable</admin-state>
+                        <ingress>
+                            <filter>
+                                <ip>{{ partner_name | upper }}_EDGE_IN</ip>
+                                <ipv6>{{ partner_name | upper }}_EDGE_IN_V6</ipv6>
+                            </filter>
+                        </ingress>
+                        <egress>
+                            <filter>
+                                <ip>{{ partner_name | upper }}_EDGE_OUT</ip>
+                                <ipv6>{{ partner_name | upper }}_EDGE_OUT_V6</ipv6>
+                            </filter>
+                        </egress>
                     </sap>
                     <ipv4>
-                      {% if ap.sbp.ipv4_bfd %}
+                      {% if ap.sbp.v4_bfd_settings.bfd_enabled %}
                         <bfd>
                             <admin-state>enable</admin-state>
-                            <transmit-interval>{{ sbp_params.bfd.ipv4.trasmit }}</transmit-interval>
+                            <transmit-interval>{{ sbp_v4_bfd_interval }}</transmit-interval>
                             <receive>{{ sbp_params.bfd.ipv4.receive }}</receive>
-                            <multiplier>{{ sbp_params.bfd.ipv4.multiplier | default(3) }}</multiplier>
+                            <multiplier>{{ sbp_v4_bfd_multiplier | default(3) }}</multiplier>
                         </bfd>
                       {% endif %}
                         <primary>
@@ -32,12 +45,12 @@
                         </primary>
                     </ipv4>
                     <ipv6>
-                      {% if ap.sbp.ipv6_bfd %}
+                      {% if ap.sbp.v6_bfd_settings.bfd_enabled %}
                         <bfd>
                             <admin-state>enable</admin-state>
-                            <transmit-interval>{{ sbp_params.bfd.ipv6.trasmit }}</transmit-interval>
+                            <transmit-interval>{{ sbp_v6_bfd_interval }}</transmit-interval>
                             <receive>{{ sbp_params.bfd.ipv6.receive }}</receive>
-                            <multiplier>{{ sbp_params.bfd.ipv6.multiplier | default(3) }}</multiplier>
+                            <multiplier>{{ sbp_v6_bfd_multiplier | default(3) }}</multiplier>
                         </bfd>
                       {% endif %}
                         <address>
diff --git a/geant/gap_ansible/roles/sbp/vars/main.yml b/geant/gap_ansible/roles/sbp/vars/main.yml
index cdd9bee2..2fd01845 100644
--- a/geant/gap_ansible/roles/sbp/vars/main.yml
+++ b/geant/gap_ansible/roles/sbp/vars/main.yml
@@ -2,4 +2,4 @@
 # vars file for sbp
 is_standalone_run: true
 
-lag_name: ap.sbp.edge_port.edge_port_name
+lag_name: "{{ ap.sbp.edge_port.edge_port_name }}"
-- 
GitLab


From 074459783f98f6a7bd33e92dc798607210f74f23 Mon Sep 17 00:00:00 2001
From: Simone Spinelli <simone.spinelli@geant.org>
Date: Thu, 14 Nov 2024 14:24:08 +0100
Subject: [PATCH 14/46] test for prefix lists

---
 .../roles/prefix_lists/tasks/main.yml         | 66 +++++++++++++++++++
 .../roles/prefix_lists/tests/inventory        |  2 -
 .../roles/prefix_lists/tests/test.yml         |  5 --
 3 files changed, 66 insertions(+), 7 deletions(-)
 delete mode 100644 geant/gap_ansible/roles/prefix_lists/tests/inventory
 delete mode 100644 geant/gap_ansible/roles/prefix_lists/tests/test.yml

diff --git a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
index 070212a3..a1269b59 100644
--- a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
@@ -1,2 +1,68 @@
 ---
 # tasks file for prefix_lists
+- name: Collect routes from BGPQ3 [ipv4]
+  ansible.builtin.shell:  bgpq3 -j4 "{{ partner.as_set }}"
+  register: bgpq3_ipv4_routes_in_json
+
+- name: Convert to real json
+  ansible.builtin.set_fact:
+    ipv4_prefix_list_name: "{{partner_name| upper}}_{{partner.type}}_IPV4_PREFIXES"
+    bgpq3_ipv4_routes: []
+    routes: "{{ bgpq3_ipv4_routes_in_json.stdout | from_json }}"
+
+- name: Fail if lenght is too short
+  ansible.builtin.meta: end_play
+  when: "{{ routes.NN|length }} <= 1"
+
+- name: Transform in list
+  ansible.builtin.set_fact:
+    bgpq3_ipv4_routes: "{{ bgpq3_ipv4_routes + [ item.prefix ] }}"
+  loop: "{{routes.NN}}"
+
+- name: Create the prefix_list object
+  ansible.builtin.set_fact:
+    nren_prefix_list: 
+
+- name: Show me the final list
+  ansible.builtin.debug:
+    var: bgpq3_ipv4_routes
+
+- name: Collect routes from BGPQ3 [ipv6]
+  ansible.builtin.shell:  bgpq3 -j6 "{{ partner.as_set }}"
+  register: bgpq3_ipv6_routes_in_json
+
+- name: Convert to real json
+  ansible.builtin.set_fact:
+    ipv6_prefix_list_name: "{{partner_name| upper}}_{{partner.type}}_IPV6_PREFIXES"
+    bgpq3_ipv6_routes: []
+    routes: "{{ bgpq3_ipv6_routes_in_json.stdout | from_json }}"
+
+- name: Fail if lenght is too short
+  ansible.builtin.meta: end_play
+  when: "{{ routes.NN|length }} <= 1"
+
+- name: Transform in list
+  ansible.builtin.set_fact:
+    bgpq3_ipv6_routes: "{{ bgpq3_ipv6_routes + [ item.prefix ] }}"
+  loop: "{{routes.NN}}"
+
+- name: Show me the final list
+  ansible.builtin.debug:
+    var: bgpq3_ipv6_routes
+
+- name: Put everything together
+  ansible.builtin.set_fact:
+    nren_prefix_lists:
+     - name: "{{ipv4_prefix_list_name}}" 
+       prefixes: "{{bgpq3_ipv4_routes}}"
+     - name: "{{ipv6_prefix_list_name}}" 
+       prefixes: "{{bgpq3_ipv6_routes}}"
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/base_config.conf"
+  ansible.builtin.template:
+    src: "prefix-lists.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/prefix_lists.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
\ No newline at end of file
diff --git a/geant/gap_ansible/roles/prefix_lists/tests/inventory b/geant/gap_ansible/roles/prefix_lists/tests/inventory
deleted file mode 100644
index 878877b0..00000000
--- a/geant/gap_ansible/roles/prefix_lists/tests/inventory
+++ /dev/null
@@ -1,2 +0,0 @@
-localhost
-
diff --git a/geant/gap_ansible/roles/prefix_lists/tests/test.yml b/geant/gap_ansible/roles/prefix_lists/tests/test.yml
deleted file mode 100644
index 1d01839a..00000000
--- a/geant/gap_ansible/roles/prefix_lists/tests/test.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- hosts: localhost
-  remote_user: root
-  roles:
-    - prefix_lists
-- 
GitLab


From f3724b2b7482cbc8508d732d5806f310e50bf2b6 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 14 Nov 2024 14:55:07 +0000
Subject: [PATCH 15/46] PO prefix lists role

---
 .../tasks/deploy_prefix_lists.yaml            |  41 ++++++
 .../roles/prefix_lists/tasks/main.yml         | 126 +++++++++---------
 .../templates/nokia/prefix-lists.j2           |   0
 .../templates/nokia/prefix_lists.j2           |  24 ++++
 .../roles/prefix_lists/vars/main.yml          |   1 +
 5 files changed, 126 insertions(+), 66 deletions(-)
 create mode 100644 geant/gap_ansible/roles/prefix_lists/tasks/deploy_prefix_lists.yaml
 delete mode 100644 geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix-lists.j2
 create mode 100644 geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix_lists.j2

diff --git a/geant/gap_ansible/roles/prefix_lists/tasks/deploy_prefix_lists.yaml b/geant/gap_ansible/roles/prefix_lists/tasks/deploy_prefix_lists.yaml
new file mode 100644
index 00000000..0062393f
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/deploy_prefix_lists.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy FW config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
index a1269b59..42c174f4 100644
--- a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
@@ -1,68 +1,62 @@
 ---
 # tasks file for prefix_lists
-- name: Collect routes from BGPQ3 [ipv4]
-  ansible.builtin.shell:  bgpq3 -j4 "{{ partner.as_set }}"
-  register: bgpq3_ipv4_routes_in_json
-
-- name: Convert to real json
-  ansible.builtin.set_fact:
-    ipv4_prefix_list_name: "{{partner_name| upper}}_{{partner.type}}_IPV4_PREFIXES"
-    bgpq3_ipv4_routes: []
-    routes: "{{ bgpq3_ipv4_routes_in_json.stdout | from_json }}"
-
-- name: Fail if lenght is too short
-  ansible.builtin.meta: end_play
-  when: "{{ routes.NN|length }} <= 1"
-
-- name: Transform in list
-  ansible.builtin.set_fact:
-    bgpq3_ipv4_routes: "{{ bgpq3_ipv4_routes + [ item.prefix ] }}"
-  loop: "{{routes.NN}}"
-
-- name: Create the prefix_list object
-  ansible.builtin.set_fact:
-    nren_prefix_list: 
-
-- name: Show me the final list
-  ansible.builtin.debug:
-    var: bgpq3_ipv4_routes
-
-- name: Collect routes from BGPQ3 [ipv6]
-  ansible.builtin.shell:  bgpq3 -j6 "{{ partner.as_set }}"
-  register: bgpq3_ipv6_routes_in_json
-
-- name: Convert to real json
-  ansible.builtin.set_fact:
-    ipv6_prefix_list_name: "{{partner_name| upper}}_{{partner.type}}_IPV6_PREFIXES"
-    bgpq3_ipv6_routes: []
-    routes: "{{ bgpq3_ipv6_routes_in_json.stdout | from_json }}"
-
-- name: Fail if lenght is too short
-  ansible.builtin.meta: end_play
-  when: "{{ routes.NN|length }} <= 1"
-
-- name: Transform in list
-  ansible.builtin.set_fact:
-    bgpq3_ipv6_routes: "{{ bgpq3_ipv6_routes + [ item.prefix ] }}"
-  loop: "{{routes.NN}}"
-
-- name: Show me the final list
-  ansible.builtin.debug:
-    var: bgpq3_ipv6_routes
-
-- name: Put everything together
-  ansible.builtin.set_fact:
-    nren_prefix_lists:
-     - name: "{{ipv4_prefix_list_name}}" 
-       prefixes: "{{bgpq3_ipv4_routes}}"
-     - name: "{{ipv6_prefix_list_name}}" 
-       prefixes: "{{bgpq3_ipv6_routes}}"
-
-- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/base_config.conf"
-  ansible.builtin.template:
-    src: "prefix-lists.j2"
-    dest: "/var/tmp/ansible_run_{{ opid }}/prefix_lists.conf"
-    lstrip_blocks: true
-    trim_blocks: true
-    mode: '0755'
-  delegate_to: localhost
\ No newline at end of file
+- name: Big block
+  delegate_to: localhost
+  block:
+    - name: Collect IPV4 routes from bgpq4
+      ansible.builtin.shell: bgpq4 -j4 "{{ partner.as_set }}"
+      register: bgpq4_ipv4_routes_in_json
+
+    - name: Convert IPV4 output to real json
+      ansible.builtin.set_fact:
+        ipv4_prefix_list_name: "{{ partner_name | upper }}_{{ partner.type }}_PREFIXES_IPV4"
+        routes: "{{ bgpq4_ipv4_routes_in_json.stdout | from_json }}"
+
+    - name: Fail if IPV4 routes list lenght is too short
+      when: routes.NN | length  <= 1
+      ansible.builtin.meta: end_play
+
+    - name: Form IPV4 route object
+      ansible.builtin.set_fact:
+        bgpq4_ipv4_routes: "{{ bgpq4_ipv4_routes | default([]) + [item.prefix] }}"
+      loop: "{{ routes.NN }}"
+
+
+    - name: Collect IPV6 routes from bgpq4
+      ansible.builtin.shell: bgpq4 -j6 "{{ partner.as_set }}"
+      register: bgpq4_ipv6_routes_in_json
+
+    - name: Convert IPV6 outeput to real json
+      ansible.builtin.set_fact:
+        ipv6_prefix_list_name: "{{ partner_name | upper }}_{{ partner.type }}_PREFIXES_IPV6"
+        routes: "{{ bgpq4_ipv6_routes_in_json.stdout | from_json }}"
+
+    - name: Fail if IPV6 routes list lenght is too short
+      when: routes.NN | length  <= 1
+      ansible.builtin.meta: end_play
+
+    - name: Form IPV6 route object
+      ansible.builtin.set_fact:
+        bgpq4_ipv6_routes: "{{ bgpq4_ipv6_routes | default([]) + [item.prefix] }}"
+      loop: "{{ routes.NN }}"
+
+    - name: Put everything together
+      ansible.builtin.set_fact:
+        nren_prefix_lists: "{{ nren_prefix_lists | default([]) + [ {'name': ipv4_prefix_list_name, 'prefixes': bgpq4_ipv4_routes},
+                                                                  {'name': ipv6_prefix_list_name, 'prefixes': bgpq4_ipv6_routes} ] }}"
+
+    - name: Debug nren_prefix_lists
+      ansible.builtin.debug:
+        var: nren_prefix_lists
+
+    - name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf"
+      ansible.builtin.template:
+        src: "nokia/prefix_lists.j2"
+        dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf"
+        lstrip_blocks: true
+        trim_blocks: true
+        mode: '0755'
+
+- name: Include deploy if standalone run
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_prefix_lists.yaml
diff --git a/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix-lists.j2 b/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix-lists.j2
deleted file mode 100644
index e69de29b..00000000
diff --git a/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix_lists.j2 b/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix_lists.j2
new file mode 100644
index 00000000..030fe1e1
--- /dev/null
+++ b/geant/gap_ansible/roles/prefix_lists/templates/nokia/prefix_lists.j2
@@ -0,0 +1,24 @@
+{% if is_standalone_run %}
+<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
+{% endif %}
+
+  <policy-options xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+    {% for prefix_list in nren_prefix_lists %}
+    <prefix-list alu:operation="replace">
+        <name>{{ prefix_list.name }}</name>
+        {% for prefix in prefix_list.prefixes %}
+        <prefix>
+          <ip-prefix>{{ prefix }}</ip-prefix>
+          <type>exact</type>
+        </prefix>
+        {% endfor %}
+    </prefix-list>
+    {% endfor %}
+
+  </policy-options>
+  
+{% if is_standalone_run %}
+   </configure>
+</config>
+{% endif %}
diff --git a/geant/gap_ansible/roles/prefix_lists/vars/main.yml b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
index 2d520ad3..cdbd2909 100644
--- a/geant/gap_ansible/roles/prefix_lists/vars/main.yml
+++ b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
@@ -1,2 +1,3 @@
 ---
 # vars file for prefix_lists
+is_standalone_run: true
-- 
GitLab


From 24e4638703ae2d1d1482acef5286bb8c3b99b00a Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 10:51:38 +0000
Subject: [PATCH 16/46] BGP role draft

---
 .../roles/bgp_config/meta/main.yml            | 13 ++++---
 .../roles/bgp_config/tasks/compile.yaml       | 15 ++++++++
 .../roles/bgp_config/tasks/main.yml           | 13 +++++++
 .../roles/bgp_config/tasks/merge_vars.yaml    |  7 ++++
 .../roles/bgp_config/templates/bgp.j2         | 21 ++++++++++
 .../bgp_config/templates/bgp_neighbor.j2      | 38 +++++++++++++++++++
 .../roles/bgp_config/tests/inventory          |  2 -
 .../roles/bgp_config/tests/test.yml           |  5 ---
 .../roles/bgp_config/vars/main.yml            |  3 ++
 9 files changed, 104 insertions(+), 13 deletions(-)
 create mode 100644 geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
 create mode 100644 geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
 create mode 100644 geant/gap_ansible/roles/bgp_config/templates/bgp.j2
 create mode 100644 geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
 delete mode 100644 geant/gap_ansible/roles/bgp_config/tests/inventory
 delete mode 100644 geant/gap_ansible/roles/bgp_config/tests/test.yml

diff --git a/geant/gap_ansible/roles/bgp_config/meta/main.yml b/geant/gap_ansible/roles/bgp_config/meta/main.yml
index ea68190c..36d899dd 100644
--- a/geant/gap_ansible/roles/bgp_config/meta/main.yml
+++ b/geant/gap_ansible/roles/bgp_config/meta/main.yml
@@ -1,7 +1,7 @@
 galaxy_info:
-  author: your name
-  description: your role description
-  company: your company (optional)
+  author: A. Kurbatov
+  description: GEANT Orchestration and Automation Team
+  company: GEANT
 
   # If the issue tracker for your role is not on github, uncomment the
   # next line and provide a value
@@ -14,14 +14,15 @@ galaxy_info:
   # - GPL-3.0-only
   # - Apache-2.0
   # - CC-BY-4.0
-  license: license (GPL-2.0-or-later, MIT, etc)
+  license: MIT
 
-  min_ansible_version: 2.1
+  min_ansible_version: '2.10'
 
   # If this a Container Enabled role, provide the minimum Ansible Container version.
   # min_ansible_container_version:
 
-  galaxy_tags: []
+  galaxy_tags:
+    - network
     # List tags for your role here, one per line. A tag is a keyword that describes
     # and categorizes the role. Users find roles by searching for tags. Be sure to
     # remove the '[]' above, if you add tags to this list.
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml b/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
new file mode 100644
index 00000000..262accef
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
@@ -0,0 +1,15 @@
+---
+- name: Set ansible host to localhost to compile template
+  ansible.builtin.set_fact:
+    ansible_host: "localhost"
+    ansible_connection: local
+
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf"
+  # when: verb in ["deploy", "update", "terminate"]
+  ansible.builtin.template:
+    src: "bgp_neighbor.j2"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf"
+    lstrip_blocks: true
+    trim_blocks: true
+    mode: '0755'
+  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/main.yml b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
index 0edcfb6b..5ffcc658 100644
--- a/geant/gap_ansible/roles/bgp_config/tasks/main.yml
+++ b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
@@ -1,2 +1,15 @@
 ---
 # tasks file for bgp_config
+- name: Load Standard Policy Statements vars
+  ansible.builtin.include_tasks: merge_vars.yaml
+
+- name: Debug bgp_session_list
+  ansible.builtin.debug:
+    var: bgp_obj
+
+- name: Compile templates
+  ansible.builtin.include_tasks: compile.yaml
+
+- name: Deploy templates if standalone run
+  when: is_standalone_run | ansible.builtin.bool
+  ansible.builtin.include_tasks: deploy_po.yaml
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
new file mode 100644
index 00000000..d0912929
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
@@ -0,0 +1,7 @@
+---
+# - name: Load Custom BGP policies if defined
+#   when: 
+- name: Set Import and export policies names
+  ansible.builtin.set_fact:
+    import_policies: "{{ bgp.policies.import.v4 }}"
+    export_policies: "{{ bgp.policies.export }}"
diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp.j2
new file mode 100644
index 00000000..f45754dc
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp.j2
@@ -0,0 +1,21 @@
+            <bgp xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+{% if router_role == 'pe' or is_pe_promotion_wf %}
+  {% with bgp_base_obj=pe_bgp_base, bgp_context='bgp_base' %}
+        {% include 'router/bgp_base.j2' %}
+  {% endwith %}
+  {% with bgp_obj=pe_bgp_tools, bgp_group_context='bgp_base' %}
+        {% include "router/bgp_group.j2" %}
+        {% include "router/bgp_neighbor.j2" %}
+  {% endwith %}
+  {% with bgp_obj=pe_bgp_internal, bgp_group_context='bgp_base' %}
+        {% include "router/bgp_group.j2" %}
+  {% endwith %}
+{% else %}
+  {% with bgp_base_obj=p_bgp_base, bgp_obj=p_bgp_internal, bgp_context='bgp_base',
+          bgp_group_context='bgp_base' %}
+        {% include 'router/bgp_base.j2' %}
+        {% include 'router/bgp_group.j2' %}
+  {% endwith %}
+{% endif %}
+            </bgp>
+
diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
new file mode 100644
index 00000000..440b06e4
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
@@ -0,0 +1,38 @@
+                {% for neighbor in bgp_obj %}
+                <neighbor alu:operation="replace">
+                    <ip-address>{{ neighbor.peer_address }}</ip-address>
+                    <admin-state>enable</admin-state>
+                    <description>{{ partner_name | upper }}_{{ partner.type }}</description>
+
+                    {% if neighbor.peer_address | ipv4 %}
+                    <group>{{ bgp.group.ipv4 }}</group>
+                    {% elif neighbor.peer_address | ipv6 %}
+                    <group>{{ bgp.group.ipv6 }}</group>
+                    {% endif %}
+                    <peer-as>{{ partner.asn }}</peer-as>
+                  {% if neighbor.authentication_key is not none %}
+                    <authentication-key>{{ neighbor.authentication_key }}</authentication-key>
+                  {% endif %}
+                  {% if neighbor.hold_time is defined %}
+                    <hold-time>
+                      <seconds>{{ neighbor.hold_time }}</seconds>
+                    </hold-time>
+                  {% endif %}
+                    <family>
+                      {% for family in neighbor.families %}
+                        <{{ family }}>true</{{ family }}>
+                      {% endfor %}
+                    </family>
+                    <import>
+                        {% for pol in import_policies %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                    </import>
+                    <export>
+                        {% for pol in export_policies %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                    </export>
+                </neighbor>
+                {% endfor %}
+ 
diff --git a/geant/gap_ansible/roles/bgp_config/tests/inventory b/geant/gap_ansible/roles/bgp_config/tests/inventory
deleted file mode 100644
index 878877b0..00000000
--- a/geant/gap_ansible/roles/bgp_config/tests/inventory
+++ /dev/null
@@ -1,2 +0,0 @@
-localhost
-
diff --git a/geant/gap_ansible/roles/bgp_config/tests/test.yml b/geant/gap_ansible/roles/bgp_config/tests/test.yml
deleted file mode 100644
index d3de857b..00000000
--- a/geant/gap_ansible/roles/bgp_config/tests/test.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- hosts: localhost
-  remote_user: root
-  roles:
-    - bgp_config
diff --git a/geant/gap_ansible/roles/bgp_config/vars/main.yml b/geant/gap_ansible/roles/bgp_config/vars/main.yml
index 260a92d9..d7fbb286 100644
--- a/geant/gap_ansible/roles/bgp_config/vars/main.yml
+++ b/geant/gap_ansible/roles/bgp_config/vars/main.yml
@@ -1,2 +1,5 @@
 ---
 # vars file for bgp_config
+is_standalone_run: true
+
+bgp_obj: "{{ ap.sbp.bgp_session_list }}"
-- 
GitLab


From 3162498252102ce9338826616cc7c12b182e39c2 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 17:01:37 +0000
Subject: [PATCH 17/46] Deploy service config role by Milos

---
 .../deploy_service_config/files/nokia/footer  |   2 +
 .../deploy_service_config/files/nokia/header  |   2 +
 .../roles/deploy_service_config/meta/main.yml |  13 +-
 .../tasks/assemble_config.yml                 |  49 ++++
 .../tasks/connection_tasks.yml                |  17 ++
 .../deploy_service_config/tasks/main.yml      |  29 +-
 .../tasks/push_config.yml                     |  70 +++++
 .../tasks/traverse_subscription.yml           |  46 +++
 .../deploy_service_config/tests/README.md     |  20 ++
 .../tests/general_mechanics.yml               |  10 +
 .../tests/modified_gip_latest.json            | 269 ++++++++++++++++++
 .../deploy_service_config/tests/test.yml      |  59 +++-
 .../roles/deploy_service_config/vars/main.yml |   2 +
 13 files changed, 577 insertions(+), 11 deletions(-)
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/files/nokia/footer
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/files/nokia/header
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/README.md
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml
 create mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json

diff --git a/geant/gap_ansible/roles/deploy_service_config/files/nokia/footer b/geant/gap_ansible/roles/deploy_service_config/files/nokia/footer
new file mode 100644
index 00000000..3da5889a
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/files/nokia/footer
@@ -0,0 +1,2 @@
+  </configure>
+</config>
diff --git a/geant/gap_ansible/roles/deploy_service_config/files/nokia/header b/geant/gap_ansible/roles/deploy_service_config/files/nokia/header
new file mode 100644
index 00000000..81165578
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/files/nokia/header
@@ -0,0 +1,2 @@
+<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
diff --git a/geant/gap_ansible/roles/deploy_service_config/meta/main.yml b/geant/gap_ansible/roles/deploy_service_config/meta/main.yml
index ea68190c..c8cc947e 100644
--- a/geant/gap_ansible/roles/deploy_service_config/meta/main.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/meta/main.yml
@@ -1,7 +1,7 @@
 galaxy_info:
-  author: your name
-  description: your role description
-  company: your company (optional)
+  author: Milos Zdravkovic
+  description: GOAT
+  company: GEANT
 
   # If the issue tracker for your role is not on github, uncomment the
   # next line and provide a value
@@ -14,14 +14,15 @@ galaxy_info:
   # - GPL-3.0-only
   # - Apache-2.0
   # - CC-BY-4.0
-  license: license (GPL-2.0-or-later, MIT, etc)
+  license: MIT
 
-  min_ansible_version: 2.1
+  min_ansible_version: '2.10'
 
   # If this a Container Enabled role, provide the minimum Ansible Container version.
   # min_ansible_container_version:
 
-  galaxy_tags: []
+  galaxy_tags:
+    - network
     # List tags for your role here, one per line. A tag is a keyword that describes
     # and categorizes the role. Users find roles by searching for tags. Be sure to
     # remove the '[]' above, if you add tags to this list.
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
new file mode 100644
index 00000000..4196066d
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
@@ -0,0 +1,49 @@
+---
+
+# Although I was working on a separate branch, I had 
+# to resist the temptation of not modifying the entry
+# playbook in order to introduce the opid_dir variable
+# and avoid it's use all over the place. 
+
+- name: Locally-delegated assemble block
+  delegate_to: localhost
+  block:
+  # Because ansible.builtin.assemble works with a single directory 
+  - name: Create a subdirectory for the assembled output
+    ansible.builtin.file:
+      path: "/var/tmp/ansible_run_{{ opid }}/assembled/"
+      state: directory
+      mode: '0755'
+  
+  # Enumeration prefix is needed to impact the order of assembly 
+  - name: Copy Nokia SR OS header for assembly
+    ansible.builtin.copy:
+      src: "{{ vendor }}/header"
+      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/00_header"
+
+  # Enumeration prefix is needed to impact the order of assembly 
+  - name: Copy Nokia SR OS footer for assembly
+    ansible.builtin.copy:
+      src: "{{ vendor }}/footer"
+      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/02_footer"
+  
+  # Enumeration prefix is needed to impact the order of assembly 
+  - name: Assemble body of the config
+    ansible.builtin.assemble:
+      src: "/var/tmp/ansible_run_{{ opid }}/"
+      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/01-body"
+  
+  # Use the enumeration prefixes to assemble fragments in the right order 
+  - name: Merge header, body and footer to get the final config 
+    ansible.builtin.assemble:
+      src: "/var/tmp/ansible_run_{{ opid }}/assembled"
+      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment"
+  
+  - name: Clean up the fragments
+    ansible.builtin.file:
+      path: "{{ item }}"
+      state: absent
+      mode: '0755'
+    with_fileglob:
+    - "/var/tmp/ansible_run_{{ opid }}/assembled/0*"  
+ 
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
new file mode 100644
index 00000000..38022c8e
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
@@ -0,0 +1,17 @@
+---
+- name: Set ansible_host to terminal server when router is offline
+  ansible.builtin.set_fact:
+    ansible_host: "{{ router.router_site.site_ts_address }}"
+    ansible_port: "{{ router.router_ts_port }}"
+  when: router.router_access_via_ts | ansible.builtin.bool
+
+
+# Loading of group _vars/ should probably be done 
+# from the entry-playbook. Or perhaps from a dedicated role
+#- name: Import variables from 'all'
+#  ansible.builtin.include_vars:
+#    dir: /opt/ansible_inventory/group_vars/all
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[router.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[router.vendor].ansible_network_os }}"
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
index c78cb095..fec9babe 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
@@ -1,2 +1,29 @@
 ---
-# tasks file for deploy_service_config
+
+- name: Fetch access port info from the subscription   
+  ansible.builtin.include_tasks: traverse_subscription.yml
+
+# The "delegate_to" works as expected in conjuction with "import_tasks".
+# However, mixing "imports" with "includes" is not recommended. 
+# Another way is to "apply" the "delegate_to: localhost".
+- name: Assemble the config from fragments in previous roles
+  ansible.builtin.include_tasks: assemble_config.yml
+
+- name: Include set connection tasks
+  ansible.builtin.include_tasks: connection_tasks.yml
+
+# The "verb == deploy" is (probably) not needed 
+# because it has already been checked in the 
+# invoking playbook (nren_l3_core_services.yaml):
+#   
+# - name: Deploy
+#    block:
+#    - name: Include deployment role
+#      ansible.builtin.include_role:
+#        name: deploy_service_config
+#     when: verb == deploy  
+#
+- name: Push assembled config to device
+  ansible.builtin.include_tasks: push_config.yml
+
+
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
new file mode 100644
index 00000000..408afdc3
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
@@ -0,0 +1,70 @@
+
+- name: 'Config deploy [CHECK ONLY][NOKIA]'
+  # ansible.netcommon.netconf_config:
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment') }}"
+    commit: true
+    validate: true
+    #config_mode: private ; CHANGELOG.md suggests this is implicit now?
+  diff: true
+  register: output
+  check_mode: true
+  when: >
+    ( dry_run | ansible.builtin.bool ) is true and
+    vendor == "nokia"
+
+- name: Fail if there is any diff
+  ansible.builtin.fail:
+    msg: iBGP configuration drifted!!!
+  when: >
+    output.changed | ansible.builtin.bool
+    and
+    is_verification_workflow | ansible.builtin.bool
+
+- name: 'Config deploy [AND COMMIT][NOKIA]'
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    #config_mode: private ; CHANGELOG.md suggests this is implicit now?
+  diff: true
+  check_mode: false
+  when: >
+    ( dry_run | ansible.builtin.bool ) is false and
+    vendor == "nokia"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
new file mode 100644
index 00000000..b6369efb
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
@@ -0,0 +1,46 @@
+---
+
+# The following tarversal of JSON should be part of 
+# the entry playbook. Or maybe even better, a separate 
+# role invoked at its very beginning so that all other 
+# roles can use it.
+
+#
+# Note: This requires python3-jmespath to be installed.
+#
+
+- name: Find matching nren_ap_list element
+  ansible.builtin.set_fact:
+    filtered_ap_list: "{{ subscription['nren_l3_core_service']['nren_ap_list'] | json_query(query) }}"
+  vars:
+    query: "[?sbp.edge_port.node.router_fqdn == `{{ inventory_hostname }}`]"
+
+- name: Check if subscription contradicts inventory_hostname
+  ansible.builtin.fail:
+    msg: "The number of router_fqdn elements that match is {{ filtered_ap_list | length }}."
+  when: filtered_ap_list | length != 1
+
+- name: Find matching nren_ap_list element
+  ansible.builtin.set_fact:
+    ap: "{{ filtered_ap_list[0] }}"   
+
+- name: Print the matched nren_ap_list element
+  ansible.builtin.debug:
+    msg: "{{ ap }}"
+
+- name: Set the short name for node
+  ansible.builtin.set_fact:
+    router: "{{ ap.sbp.edge_port.node }}"
+
+- name: Print the node
+  ansible.builtin.debug:
+    msg: "{{ router }}"
+
+- name: Set the short name for vendor
+  ansible.builtin.set_fact:
+    vendor: "{{ router.vendor }}"
+
+- name: Print the vendor
+  ansible.builtin.debug:
+    msg: "{{ vendor }}"
+
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/README.md b/geant/gap_ansible/roles/deploy_service_config/tests/README.md
new file mode 100644
index 00000000..a09942e7
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tests/README.md
@@ -0,0 +1,20 @@
+
+Before running this:
+
+```
+ansible-playbook -i rt0.ely.uk.dev.geant.private, -e@modified_gip_latest.json test.yml -k
+```
+
+make sure that `/etc/hosts` has the corresponding entry:
+
+```
+127.0.0.1       rt0.ely.uk.dev.geant.private
+```
+
+and that SSH service has been started:
+
+```
+sudo systemctl start ssh
+```
+
+`Note:` The `rt0.ely.uk.dev.geant.private` matches the second element (`BACKUP`) in the JSON's `nren_ap_list[]`. 
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml b/geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml
new file mode 100644
index 00000000..0d05e076
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml
@@ -0,0 +1,10 @@
+## Netconf access
+#
+netconf_access:
+  nokia:
+    ansible_network_os: geant.gap_ansible.sros
+    # ansible_network_os: nokia.sros.md
+    ansible_connection: netconf
+  juniper:
+    ansible_network_os: junos
+    ansible_connection: netconf
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json b/geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json
new file mode 100644
index 00000000..fe102416
--- /dev/null
+++ b/geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json
@@ -0,0 +1,269 @@
+{
+  "partner_name": "JISC",
+  "subscription": {
+    "description": "GÉANT IP service",
+    "nren_l3_core_service": {
+      "nren_ap_list": [
+        {
+          "sbp": {
+            "name": "ServiceBindingPort",
+            "label": null,
+            "vlan_id": 11,
+            "sbp_type": "l3",
+            "edge_port": {
+              "name": "EdgePortBlock",
+              "node": {
+                "name": "RouterBlock",
+                "label": null,
+                "vendor": "nokia",
+                "router_fqdn": "rt0.cbg.uk.dev.geant.private",
+                "router_role": "pe",
+                "router_site": {
+                  "name": "SiteBlock",
+                  "label": null,
+                  "site_city": "Cambridge",
+                  "site_name": "CBG",
+                  "site_tier": "1",
+                  "site_country": "UK",
+                  "site_latitude": "52.2",
+                  "site_longitude": "0.11667",
+                  "site_ts_address": "62.40.111.70",
+                  "site_internal_id": 11,
+                  "site_country_code": "UK",
+                  "owner_subscription_id": "b842d5ab-144d-4c42-8c6a-4c7b5402b30f",
+                  "site_bgp_community_id": 11,
+                  "subscription_instance_id": "4c78e94b-60a0-4227-aa69-2d95edfb27bb"
+                },
+                "router_ts_port": 3830,
+                "router_access_via_ts": true,
+                "owner_subscription_id": "efee8705-5f0f-4fec-844a-7cd7626fe6a8",
+                "router_lo_iso_address": "49.51e5.0001.0101.0100.0002.00",
+                "router_lo_ipv4_address": "10.101.0.2",
+                "router_lo_ipv6_address": "dead:feeb:101::2",
+                "subscription_instance_id": "a8355d18-4f58-4dd7-82e8-c7ca6297416d"
+              },
+              "label": null,
+              "enable_lacp": true,
+              "geant_ga_id": "GA-5577",
+              "mac_address": null,
+              "member_speed": "400G",
+              "encapsulation": "dot1q",
+              "minimum_links": 2,
+              "edge_port_name": "lag-21",
+              "edge_port_type": "CUSTOMER",
+              "ignore_if_down": false,
+              "edge_port_ae_members": [
+                {
+                  "name": "EdgePortAEMemberBlock",
+                  "label": null,
+                  "interface_name": "2/1/c17/1",
+                  "interface_description": "jisc-port-21",
+                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
+                  "subscription_instance_id": "989ac8dd-0db3-4d43-b638-287cbb0b6b30"
+                },
+                {
+                  "name": "EdgePortAEMemberBlock",
+                  "label": null,
+                  "interface_name": "2/1/c35/1",
+                  "interface_description": "jisc-port-22",
+                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
+                  "subscription_instance_id": "634f079a-f8ff-45c2-8f33-809e3472f70d"
+                }
+              ],
+              "edge_port_description": "JISC edge port-2",
+              "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
+              "subscription_instance_id": "587383db-c04c-4848-bf26-0610190a273f"
+            },
+            "geant_sid": "gs-19234",
+            "ipv4_mask": 31,
+            "ipv6_mask": 126,
+            "is_tagged": true,
+            "ipv4_address": "1.1.1.1",
+            "ipv6_address": "2001:798::1",
+            "bgp_session_list": [
+              {
+                "name": "BGPSession",
+                "label": null,
+                "families": [
+                  "v4unicast"
+                ],
+                "is_passive": false,
+                "bfd_enabled": false,
+                "bfd_interval": null,
+                "is_multi_hop": true,
+                "peer_address": "1.1.1.2",
+                "rtbh_enabled": true,
+                "bfd_multiplier": null,
+                "multipath_enabled": false,
+                "authentication_key": "alQERqnaerq324",
+                "send_default_route": false,
+                "has_custom_policies": false,
+                "owner_subscription_id": "5f86aa86-9d88-4e63-b893-6f42e50806ef",
+                "subscription_instance_id": "18de722b-a050-4887-bc22-7291cdbe2d97"
+              },
+              {
+                "name": "BGPSession",
+                "label": null,
+                "families": [
+                  "v6unicast"
+                ],
+                "is_passive": false,
+                "bfd_enabled": false,
+                "bfd_interval": null,
+                "is_multi_hop": true,
+                "peer_address": "2001:798::2",
+                "rtbh_enabled": true,
+                "bfd_multiplier": null,
+                "multipath_enabled": false,
+                "authentication_key": "alQERqnaerq324",
+                "send_default_route": false,
+                "has_custom_policies": false,
+                "owner_subscription_id": "7dd1a6f2-8afe-4324-81f4-f34b2fce7f6f",
+                "subscription_instance_id": "a88f1a46-eaac-44f2-bb2a-2c343ea4f2fc"
+              }
+            ],
+            "owner_subscription_id": "e257a102-1c24-44b6-a161-b3e63ed102fc",
+            "custom_firewall_filters": false,
+            "subscription_instance_id": "8d3e8499-b121-4bf8-b92a-78bd8647334d"
+          },
+          "name": "NRENAccessPort",
+          "label": null,
+          "ap_type": "PRIMARY",
+          "owner_subscription_id": "215a1618-7615-4ecd-9b2a-06711187d012",
+          "subscription_instance_id": "a65599ed-48c8-469c-a562-942fe75f368e"
+        },
+        {
+          "sbp": {
+            "name": "ServiceBindingPort",
+            "label": null,
+            "vlan_id": 11,
+            "sbp_type": "l3",
+            "edge_port": {
+              "name": "EdgePortBlock",
+              "node": {
+                "name": "RouterBlock",
+                "label": null,
+                "vendor": "nokia",
+                "router_fqdn": "rt0.ely.uk.dev.geant.private",
+                "router_role": "pe",
+                "router_site": {
+                  "name": "SiteBlock",
+                  "label": null,
+                  "site_city": "Cambridge",
+                  "site_name": "CBG",
+                  "site_tier": "1",
+                  "site_country": "UK",
+                  "site_latitude": "52.2",
+                  "site_longitude": "0.11667",
+                  "site_ts_address": "62.40.111.70",
+                  "site_internal_id": 11,
+                  "site_country_code": "UK",
+                  "owner_subscription_id": "b842d5ab-144d-4c42-8c6a-4c7b5402b30f",
+                  "site_bgp_community_id": 11,
+                  "subscription_instance_id": "4c78e94b-60a0-4227-aa69-2d95edfb27bb"
+                },
+                "router_ts_port": 3830,
+                "router_access_via_ts": true,
+                "owner_subscription_id": "efee8705-5f0f-4fec-844a-7cd7626fe6a8",
+                "router_lo_iso_address": "49.51e5.0001.0101.0100.0002.00",
+                "router_lo_ipv4_address": "10.101.0.2",
+                "router_lo_ipv6_address": "dead:feeb:101::2",
+                "subscription_instance_id": "a8355d18-4f58-4dd7-82e8-c7ca6297416d"
+              },
+              "label": null,
+              "enable_lacp": true,
+              "geant_ga_id": "GA-5577",
+              "mac_address": null,
+              "member_speed": "400G",
+              "encapsulation": "dot1q",
+              "minimum_links": 2,
+              "edge_port_name": "lag-21",
+              "edge_port_type": "CUSTOMER",
+              "ignore_if_down": false,
+              "edge_port_ae_members": [
+                {
+                  "name": "EdgePortAEMemberBlock",
+                  "label": null,
+                  "interface_name": "2/1/c17/1",
+                  "interface_description": "jisc-port-21",
+                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
+                  "subscription_instance_id": "989ac8dd-0db3-4d43-b638-287cbb0b6b30"
+                },
+                {
+                  "name": "EdgePortAEMemberBlock",
+                  "label": null,
+                  "interface_name": "2/1/c35/1",
+                  "interface_description": "jisc-port-22",
+                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
+                  "subscription_instance_id": "634f079a-f8ff-45c2-8f33-809e3472f70d"
+                }
+              ],
+              "edge_port_description": "JISC edge port-2",
+              "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
+              "subscription_instance_id": "587383db-c04c-4848-bf26-0610190a273f"
+            },
+            "geant_sid": "gs-19234",
+            "ipv4_mask": 31,
+            "ipv6_mask": 126,
+            "is_tagged": true,
+            "ipv4_address": "1.1.1.1",
+            "ipv6_address": "2001:798::1",
+            "bgp_session_list": [
+              {
+                "name": "BGPSession",
+                "label": null,
+                "families": [
+                  "v4unicast"
+                ],
+                "is_passive": false,
+                "bfd_enabled": false,
+                "bfd_interval": null,
+                "is_multi_hop": true,
+                "peer_address": "1.1.1.2",
+                "rtbh_enabled": true,
+                "bfd_multiplier": null,
+                "multipath_enabled": false,
+                "authentication_key": "alQERqnaerq324",
+                "send_default_route": false,
+                "has_custom_policies": false,
+                "owner_subscription_id": "5f86aa86-9d88-4e63-b893-6f42e50806ef",
+                "subscription_instance_id": "18de722b-a050-4887-bc22-7291cdbe2d97"
+              },
+              {
+                "name": "BGPSession",
+                "label": null,
+                "families": [
+                  "v6unicast"
+                ],
+                "is_passive": false,
+                "bfd_enabled": false,
+                "bfd_interval": null,
+                "is_multi_hop": true,
+                "peer_address": "2001:798::2",
+                "rtbh_enabled": true,
+                "bfd_multiplier": null,
+                "multipath_enabled": false,
+                "authentication_key": "alQERqnaerq324",
+                "send_default_route": false,
+                "has_custom_policies": false,
+                "owner_subscription_id": "7dd1a6f2-8afe-4324-81f4-f34b2fce7f6f",
+                "subscription_instance_id": "a88f1a46-eaac-44f2-bb2a-2c343ea4f2fc"
+              }
+            ],
+            "owner_subscription_id": "e257a102-1c24-44b6-a161-b3e63ed102fc",
+            "custom_firewall_filters": false,
+            "subscription_instance_id": "8d3e8499-b121-4bf8-b92a-78bd8647334d"
+          },
+          "name": "NRENAccessPort",
+          "label": null,
+          "ap_type": "BAKUP",
+          "owner_subscription_id": "215a1618-7615-4ecd-9b2a-06711187d012",
+          "subscription_instance_id": "a65599ed-48c8-469c-a562-942fe75f368e"
+        }
+      ]
+    }
+  },
+  "edge_port_fqdn_list": [
+    "rt0.cbg.uk.dev.geant.private"
+  ]
+}
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/test.yml b/geant/gap_ansible/roles/deploy_service_config/tests/test.yml
index 1ff3af01..7f37d19e 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tests/test.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tests/test.yml
@@ -1,5 +1,56 @@
 ---
-- hosts: localhost
-  remote_user: root
-  roles:
-    - deploy_service_config
+- name: Qucik test playbook for this role 
+  hosts: all
+  tasks:
+  - name: Generate an ID for this run
+    ansible.builtin.set_fact:
+      opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
+
+  - name: Print the ID
+    ansible.builtin.debug:
+      msg: "{{ opid }}"
+
+  - name: Create a folder for all compiled output
+    ansible.builtin.file:
+      path: "/var/tmp/ansible_run_{{ opid }}"
+      state: directory
+      mode: '0755'
+    delegate_to: localhost
+
+  - name: Create A.txt with distinct content
+    copy:
+      dest: "/var/tmp/ansible_run_{{ opid }}/A.txt"
+      content: |
+        This is file A.
+        Line 1 in A.txt
+        Line 2 in A.txt
+    delegate_to: localhost
+
+  - name: Create B.txt with distinct content
+    copy:
+      dest: "/var/tmp/ansible_run_{{ opid }}/B.txt"
+      content: |
+        This is file B.
+        Line 1 in B.txt
+        Line 2 in B.txt
+    delegate_to: localhost
+
+  - name: Create C.txt with distinct content
+    copy:
+      dest: "/var/tmp/ansible_run_{{ opid }}/C.txt"
+      content: |
+        This is file C.
+        Line 1 in C.txt
+        Line 2 in C.txt
+    delegate_to: localhost
+
+  - name: Include group_vars just for this test
+    ansible.builtin.include_vars:
+      file: ./general_mechanics.yml
+
+  - name: Include this role for testing
+    ansible.builtin.include_role:
+      name: ../../deploy_service_config
+       
+
+
diff --git a/geant/gap_ansible/roles/deploy_service_config/vars/main.yml b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
index 0a9af9d9..bf5a91de 100644
--- a/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
@@ -1,2 +1,4 @@
 ---
 # vars file for deploy_service_config
+dry_run: true
+is_verification_workflow: false
-- 
GitLab


From 95115712b9ba242cbae80aae9c94f658d7c65916 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 17:02:04 +0000
Subject: [PATCH 18/46] BGP config role updates

---
 .../roles/bgp_config/tasks/compile.yaml       |  2 +-
 .../roles/bgp_config/templates/bgp.j2         | 24 +++++--------------
 .../roles/bgp_config/vars/main.yml            |  2 +-
 3 files changed, 8 insertions(+), 20 deletions(-)

diff --git a/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml b/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
index 262accef..ff6d5492 100644
--- a/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
+++ b/geant/gap_ansible/roles/bgp_config/tasks/compile.yaml
@@ -7,7 +7,7 @@
 - name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf"
   # when: verb in ["deploy", "update", "terminate"]
   ansible.builtin.template:
-    src: "bgp_neighbor.j2"
+    src: "bgp.j2"
     dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf"
     lstrip_blocks: true
     trim_blocks: true
diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp.j2
index f45754dc..47b82cfb 100644
--- a/geant/gap_ansible/roles/bgp_config/templates/bgp.j2
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp.j2
@@ -1,21 +1,9 @@
+
+        <router xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
+            <router-name>Base</router-name>
             <bgp xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
-{% if router_role == 'pe' or is_pe_promotion_wf %}
-  {% with bgp_base_obj=pe_bgp_base, bgp_context='bgp_base' %}
-        {% include 'router/bgp_base.j2' %}
-  {% endwith %}
-  {% with bgp_obj=pe_bgp_tools, bgp_group_context='bgp_base' %}
-        {% include "router/bgp_group.j2" %}
-        {% include "router/bgp_neighbor.j2" %}
-  {% endwith %}
-  {% with bgp_obj=pe_bgp_internal, bgp_group_context='bgp_base' %}
-        {% include "router/bgp_group.j2" %}
-  {% endwith %}
-{% else %}
-  {% with bgp_base_obj=p_bgp_base, bgp_obj=p_bgp_internal, bgp_context='bgp_base',
-          bgp_group_context='bgp_base' %}
-        {% include 'router/bgp_base.j2' %}
-        {% include 'router/bgp_group.j2' %}
-  {% endwith %}
-{% endif %}
+            {% include 'bgp_neighbor.j2' %}
             </bgp>
 
+       </router>
+
diff --git a/geant/gap_ansible/roles/bgp_config/vars/main.yml b/geant/gap_ansible/roles/bgp_config/vars/main.yml
index d7fbb286..5bdb6c9d 100644
--- a/geant/gap_ansible/roles/bgp_config/vars/main.yml
+++ b/geant/gap_ansible/roles/bgp_config/vars/main.yml
@@ -1,5 +1,5 @@
 ---
 # vars file for bgp_config
-is_standalone_run: true
+is_standalone_run: false
 
 bgp_obj: "{{ ap.sbp.bgp_session_list }}"
-- 
GitLab


From d02f3a79e4bb7239f0046fd2b7417df9b2b4bf0a Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 17:02:31 +0000
Subject: [PATCH 19/46] roles is_standalone_run var update

---
 geant/gap_ansible/roles/fw_filters/vars/main.yml     | 2 +-
 geant/gap_ansible/roles/policy_options/vars/main.yml | 2 +-
 geant/gap_ansible/roles/prefix_lists/vars/main.yml   | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/geant/gap_ansible/roles/fw_filters/vars/main.yml b/geant/gap_ansible/roles/fw_filters/vars/main.yml
index 161f1549..2b4e499d 100644
--- a/geant/gap_ansible/roles/fw_filters/vars/main.yml
+++ b/geant/gap_ansible/roles/fw_filters/vars/main.yml
@@ -1,3 +1,3 @@
 ---
 # vars file for fw_filters
-is_standalone_run: true
+is_standalone_run: false
diff --git a/geant/gap_ansible/roles/policy_options/vars/main.yml b/geant/gap_ansible/roles/policy_options/vars/main.yml
index f935f638..8f15eb5c 100644
--- a/geant/gap_ansible/roles/policy_options/vars/main.yml
+++ b/geant/gap_ansible/roles/policy_options/vars/main.yml
@@ -1,6 +1,6 @@
 ---
 # vars file for policy_options
-is_standalone_run: true
+is_standalone_run: false
 
 site_name: "{{ ap.sbp.edge_port.node.router_site.site_name }}"
 ap_type: "{{ ap.ap_type }}"
diff --git a/geant/gap_ansible/roles/prefix_lists/vars/main.yml b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
index cdbd2909..38f88d46 100644
--- a/geant/gap_ansible/roles/prefix_lists/vars/main.yml
+++ b/geant/gap_ansible/roles/prefix_lists/vars/main.yml
@@ -1,3 +1,3 @@
 ---
 # vars file for prefix_lists
-is_standalone_run: true
+is_standalone_run: false
-- 
GitLab


From 84661211c1c6a58469452c4a4db6f00bb92850a7 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 17:02:49 +0000
Subject: [PATCH 20/46] Nren_l3_core_service playbook

---
 .../playbooks/nren_l3_core_service.yaml       | 28 +++++++++++++++----
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
index 4d9e9d67..9d3f89b5 100644
--- a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
+++ b/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
@@ -19,6 +19,10 @@
         mode: '0755'
       delegate_to: localhost
 
+    - name: Import group_vars/all
+      ansible.builtin.include_vars:
+        dir: /opt/ansible_inventory/group_vars/all
+
     - name: Import standard variables for {{ subscription.product.name }}
       ansible.builtin.include_vars:
         dir: /opt/ansible_inventory/geant_services/{{ subscription.product.product_type }}
@@ -27,11 +31,15 @@
       ansible.builtin.include_vars:
         dir: /opt/ansible_inventory/geant_partners/{{ partner_name | lower }}
 
-    # - name: Compile Prefix Lists
-    #   block:
-    #     - name: Include Prefix-list role
-    #       ansible.builtin.include_role:
-    #         name: prefix_lists
+    - name: Compile Prefix Lists
+      block:
+        - name: Include Prefix-list role
+          ansible.builtin.include_role:
+            name: prefix_lists
+          loop:
+            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+          loop_control:
+            loop_var: ap
 
     - name: Compile Firewall filters
       block:
@@ -68,10 +76,18 @@
         - name: Include BGP session
           ansible.builtin.include_role:
             name: bgp_config
+          loop:
+            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+          loop_control:
+            loop_var: ap
 
     - name: Deploy
-      when: verb == deploy
+      # when: verb == deploy
       block:
         - name: Include deployment role
           ansible.builtin.include_role:
             name: deploy_service_config
+          loop:
+            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+          loop_control:
+            loop_var: ap
-- 
GitLab


From 54fe7b5a0fede8f8866f98d541bd53d216c864e6 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 17:05:16 +0000
Subject: [PATCH 21/46] SBP - BFD settings

Role-level vars are pointing to the inventory vars;
If BFD is provided from GSO, override BFD-vars using the values from GSO
via merge_vars.
---
 .../roles/sbp/tasks/merge_vars.yaml           | 35 +++++++------------
 geant/gap_ansible/roles/sbp/vars/main.yml     |  9 ++++-
 2 files changed, 20 insertions(+), 24 deletions(-)

diff --git a/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml b/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
index af4506b6..9107bbca 100644
--- a/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/sbp/tasks/merge_vars.yaml
@@ -2,46 +2,35 @@
 - name: Set interface v4 BFD values
   when: ap.sbp.v4_bfd_settings.bfd_enabled | ansible.builtin.bool
   block:
-    - name: Set v4 BFD interval to GSO value
-      when: ap.sbp.v4_bfd_settings.bfd_interval != None
+    - name: Set v4 BFD RX interval to GSO value
+      when: ap.sbp.v4_bfd_settings.bfd_interval_rx != None
       ansible.builtin.set_fact:
-        sbp_v4_bfd_interval: "{{ ap.sbp.v4_bfd_settings.bfd_interval }}"
+        sbp_v4_bfd_interval_rx: "{{ ap.sbp.v4_bfd_settings.bfd_interval_rx }}"
 
-    - name: Set v4 BFD interval to standard value
-      when: ap.sbp.v4_bfd_settings.bfd_interval == None
+    - name: Set v4 BFD TX interval to GSO value
+      when: ap.sbp.v4_bfd_settings.bfd_interval_tx != None
       ansible.builtin.set_fact:
-        sbp_v4_bfd_interval: "{{ sbp_params.bfd.ipv4.transmit }}"
-      # FIX: interval -> transmit + receive
+        sbp_v4_bfd_interval_tx: "{{ ap.sbp.v4_bfd_settings.bfd_interval_tx }}"
 
     - name: Set v4 BFD multiplier to GSO value
       when: ap.sbp.v4_bfd_settings.bfd_multiplier != None
       ansible.builtin.set_fact:
         sbp_v4_bfd_multiplier: "{{ ap.sbp.v4_bfd_settings.bfd_multiplier }}"
 
-    - name: Set v4 BFD multiplier to standard value
-      when: ap.sbp.v4_bfd_settings.bfd_multiplier == None
-      ansible.builtin.set_fact:
-        sbp_v4_bfd_multiplier: "{{ sbp_params.bfd.ipv4.multiplier }}"
-
 - name: Set interface v6 BFD values
   when: ap.sbp.v6_bfd_settings.bfd_enabled | ansible.builtin.bool
   block:
-    - name: Set v6 BFD interval to GSO value
-      when: ap.sbp.v6_bfd_settings.bfd_interval != None
+    - name: Set v6 BFD RX interval to GSO value
+      when: ap.sbp.v6_bfd_settings.bfd_interval_rx != None
       ansible.builtin.set_fact:
-        sbp_v6_bfd_interval: "{{ ap.sbp.v6_bfd_settings.bfd_interval }}"
+        sbp_v6_bfd_interval_rx: "{{ ap.sbp.v6_bfd_settings.bfd_interval_rx }}"
 
-    - name: Set v6 BFD interval to standard value
-      when: ap.sbp.v6_bfd_settings.bfd_interval == None
+    - name: Set v6 BFD TX interval to GSO value
+      when: ap.sbp.v6_bfd_settings.bfd_interval_tx != None
       ansible.builtin.set_fact:
-        sbp_v6_bfd_interval: "{{ sbp_params.bfd.ipv6.transmit }}"
+        sbp_v6_bfd_interval_tx: "{{ ap.sbp.v6_bfd_settings.bfd_interval_tx }}"
 
     - name: Set v6 BFD multiplier to GSO value
       when: ap.sbp.v6_bfd_settings.bfd_multiplier != None
       ansible.builtin.set_fact:
         sbp_v6_bfd_multiplier: "{{ ap.sbp.v6_bfd_settings.bfd_multiplier }}"
-
-    - name: Set v6 BFD multiplier to standard value
-      when: ap.sbp.v6_bfd_settings.bfd_multiplier == None
-      ansible.builtin.set_fact:
-        sbp_v6_bfd_multiplier: "{{ sbp_params.bfd.ipv6.multiplier }}"
diff --git a/geant/gap_ansible/roles/sbp/vars/main.yml b/geant/gap_ansible/roles/sbp/vars/main.yml
index 2fd01845..116ca033 100644
--- a/geant/gap_ansible/roles/sbp/vars/main.yml
+++ b/geant/gap_ansible/roles/sbp/vars/main.yml
@@ -1,5 +1,12 @@
 ---
 # vars file for sbp
-is_standalone_run: true
+is_standalone_run: false
 
 lag_name: "{{ ap.sbp.edge_port.edge_port_name }}"
+
+sbp_v4_bfd_multiplier: "{{ sbp_params.bfd.ipv4.multiplier }}"
+sbp_v4_bfd_interval_rx: "{{ sbp_params.bfd.ipv4.receive }}"
+sbp_v4_bfd_interval_tx: "{{ sbp_params.bfd.ipv4.transmit }}"
+sbp_v6_bfd_multiplier: "{{ sbp_params.bfd.ipv6.multiplier }}"
+sbp_v6_bfd_interval_rx: "{{ sbp_params.bfd.ipv6.receive }}"
+sbp_v6_bfd_interval_tx: "{{ sbp_params.bfd.ipv6.transmit }}"
-- 
GitLab


From cf1dd24031e2fb1eb3cfd340a80c39d865b8d72e Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 17:24:36 +0000
Subject: [PATCH 22/46] Update in inventory var structure

---
 geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml  | 2 +-
 .../roles/policy_options/templates/policy_statements.j2       | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
index be58b438..6a424a69 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -14,7 +14,7 @@
     - name: Set NREN community value
       when: (partner.asn | int) < 65536
       ansible.builtin.set_fact:
-        nren_community_values: ["{{ geant_re_as_number }}:{{ partner.asn }}", "{{ block_community_prefix }}:{{ partner.asn }}"]
+        nren_community_values: ["{{ geant_re_as_number }}:{{ partner.asn }}", "{{ bgp.block_community_prefix }}:{{ partner.asn }}"]
 
     - name: Set NREN community value
       when: (partner.asn | int) > 65535
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
index 390cf595..32570140 100644
--- a/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_statements.j2
@@ -59,10 +59,10 @@
                   {% endfor %}
                 {% elif act_k == "bgp_med" %}
             <bgp-med>
-                <set>{{ act_v | default(standard_bgp_med[ap_type]) }}</set>
+                <set>{{ act_v | default(bgp.standard_metric.med[ap_type]) }}</set>
             </bgp-med>
                 {% elif act_k == "local_preference" %}
-            <local-preference>{{ act_v | default(standard_local_pref[ap_type]) }}</local-preference>
+            <local-preference>{{ act_v | default(bgp.standard_metric.loca_pref[ap_type]) }}</local-preference>
                 {% else %}
             <{{ act_k | replace("_", "-") }}>{{ act_v }}</{{act_k  | replace("_", "-") }}>
                 {% endif %}
-- 
GitLab


From 122fa70d7e1f8fdd96baf27f10098c7f73a38806 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Fri, 15 Nov 2024 17:55:56 +0000
Subject: [PATCH 23/46] Policy options - option to load custom policies if
 selected

---
 .../roles/policy_options/tasks/merge_vars.yaml     | 14 ++++++++++++++
 .../policy_options/templates/policy_options.j2     |  2 +-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
index 6a424a69..80972737 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -25,3 +25,17 @@
       ansible.builtin.set_fact:
         nren_po_communities: "{{ nren_po_communities | default([]) + [ {'name': item.0, 'member': item.1} ] }}"
       loop: "{{ nren_community_names | zip(nren_community_values) | list }}"
+
+- name: Select Custom policies if specified by GSO
+  # FIX: Should be per BGP session
+  when: >-
+    ap.sbp.bgp_session_list[0].has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ partner_name | upper }}_PO_POL_STATEMENTS"
+
+- name: Select Standard policies if custom are not selected
+  # FIX: Should be per BGP session
+  when: >-
+    not ap.sbp.bgp_session_list[0].has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ standard_nren_policies }}"
diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
index d2f49fba..d36314cc 100644
--- a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
@@ -26,7 +26,7 @@
 
   {# Policy statements #}
     {% if standard_nren_policies is defined %}
-      {% with policy_obj=standard_nren_policies %}
+      {% with policy_obj=nren_policies %}
       {% include 'policy_statements.j2' %}
       {% endwith %}
     {% endif %}
-- 
GitLab


From 44b3733bc7f46864106ae90967507ed5d3b5c5ee Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Sat, 16 Nov 2024 09:36:06 +0000
Subject: [PATCH 24/46] BGP: distinguish between V4 and V6 import policies

---
 geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml   | 7 +++----
 .../gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 | 4 ++++
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
index d0912929..48209820 100644
--- a/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
@@ -1,7 +1,6 @@
 ---
-# - name: Load Custom BGP policies if defined
-#   when: 
-- name: Set Import and export policies names
+- name: Set Standard Import and export policies names
   ansible.builtin.set_fact:
-    import_policies: "{{ bgp.policies.import.v4 }}"
+    import_policies_v4: "{{ bgp.policies.import.v4 }}"
+    import_policies_v6: "{{ bgp.policies.import.v6 }}"
     export_policies: "{{ bgp.policies.export }}"
diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
index 440b06e4..c072292e 100644
--- a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
@@ -18,6 +18,10 @@
                       <seconds>{{ neighbor.hold_time }}</seconds>
                     </hold-time>
                   {% endif %}
+                  {% if neighbor.multipath_enabled %}
+                  <multipath-eligible>true</multipath-eligible>
+                  {% endif %}
+
                     <family>
                       {% for family in neighbor.families %}
                         <{{ family }}>true</{{ family }}>
-- 
GitLab


From 7b201c854a47e9c8bf1b68a16f0ee9bd857ff588 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Sat, 16 Nov 2024 09:41:25 +0000
Subject: [PATCH 25/46] BGP neighbor template - account for diff policies
 depending on BGP family

---
 .../roles/bgp_config/templates/bgp_neighbor.j2            | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
index c072292e..773798c1 100644
--- a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
@@ -28,9 +28,15 @@
                       {% endfor %}
                     </family>
                     <import>
-                        {% for pol in import_policies %}
+                      {% if neighbor.peer_address | ipv4 %}
+                        {% for pol in import_policies_v4 %}
                         <policy>{{ pol }}</policy>
                         {% endfor %}
+                      {% elif neighbor.peer_address | ipv6 %}
+                        {% for pol in import_policies_v6 %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                      {% endif %}
                     </import>
                     <export>
                         {% for pol in export_policies %}
-- 
GitLab


From 08ed0c9578ed17e692c4cb4c875e2f6e59d03265 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 21 Nov 2024 17:46:57 +0100
Subject: [PATCH 26/46] removal of `geant_ip` role

---
 geant/gap_ansible/roles/geant_ip/README.md    | 38 ---------------
 .../roles/geant_ip/defaults/main.yml          |  2 -
 .../roles/geant_ip/handlers/main.yml          |  2 -
 .../gap_ansible/roles/geant_ip/meta/main.yml  | 38 ---------------
 .../roles/geant_ip/tasks/compile.yaml         | 24 ----------
 .../gap_ansible/roles/geant_ip/tasks/main.yml | 23 ---------
 .../roles/geant_ip/tasks/standard_tasks.yaml  | 44 -----------------
 .../geant_ip/templates/nokia/l3/deploy_sbp.j2 | 48 -------------------
 .../gap_ansible/roles/geant_ip/vars/main.yml  | 15 ------
 9 files changed, 234 deletions(-)
 delete mode 100644 geant/gap_ansible/roles/geant_ip/README.md
 delete mode 100644 geant/gap_ansible/roles/geant_ip/defaults/main.yml
 delete mode 100644 geant/gap_ansible/roles/geant_ip/handlers/main.yml
 delete mode 100644 geant/gap_ansible/roles/geant_ip/meta/main.yml
 delete mode 100644 geant/gap_ansible/roles/geant_ip/tasks/compile.yaml
 delete mode 100644 geant/gap_ansible/roles/geant_ip/tasks/main.yml
 delete mode 100644 geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml
 delete mode 100644 geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2
 delete mode 100644 geant/gap_ansible/roles/geant_ip/vars/main.yml

diff --git a/geant/gap_ansible/roles/geant_ip/README.md b/geant/gap_ansible/roles/geant_ip/README.md
deleted file mode 100644
index 225dd44b..00000000
--- a/geant/gap_ansible/roles/geant_ip/README.md
+++ /dev/null
@@ -1,38 +0,0 @@
-Role Name
-=========
-
-A brief description of the role goes here.
-
-Requirements
-------------
-
-Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
-
-Role Variables
---------------
-
-A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
-
-Dependencies
-------------
-
-A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
-
-Example Playbook
-----------------
-
-Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
-
-    - hosts: servers
-      roles:
-         - { role: username.rolename, x: 42 }
-
-License
--------
-
-BSD
-
-Author Information
-------------------
-
-An optional section for the role authors to include contact information, or a website (HTML is not allowed).
diff --git a/geant/gap_ansible/roles/geant_ip/defaults/main.yml b/geant/gap_ansible/roles/geant_ip/defaults/main.yml
deleted file mode 100644
index 1b65cb38..00000000
--- a/geant/gap_ansible/roles/geant_ip/defaults/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-# defaults file for geant_ip
diff --git a/geant/gap_ansible/roles/geant_ip/handlers/main.yml b/geant/gap_ansible/roles/geant_ip/handlers/main.yml
deleted file mode 100644
index 3c8caf87..00000000
--- a/geant/gap_ansible/roles/geant_ip/handlers/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-# handlers file for geant_ip
diff --git a/geant/gap_ansible/roles/geant_ip/meta/main.yml b/geant/gap_ansible/roles/geant_ip/meta/main.yml
deleted file mode 100644
index dde461cc..00000000
--- a/geant/gap_ansible/roles/geant_ip/meta/main.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-galaxy_info:
-  author: A. Kurbatov
-  description: GEANT Orchestration and Automation Team
-  company: GEANT
-
-  # If the issue tracker for your role is not on github, uncomment the
-  # next line and provide a value
-  # issue_tracker_url: http://example.com/issue/tracker
-
-  # Choose a valid license ID from https://spdx.org - some suggested licenses:
-  # - BSD-3-Clause (default)
-  # - MIT
-  # - GPL-2.0-or-later
-  # - GPL-3.0-only
-  # - Apache-2.0
-  # - CC-BY-4.0
-  license: MIT
-
-  min_ansible_version: '2.10'
-
-  # If this a Container Enabled role, provide the minimum Ansible Container version.
-  # min_ansible_container_version:
-
-  galaxy_tags:
-    - network
-    # List tags for your role here, one per line. A tag is a keyword that describes
-    # and categorizes the role. Users find roles by searching for tags. Be sure to
-    # remove the '[]' above, if you add tags to this list.
-    #
-    # NOTE: A tag is limited to a single word comprised of alphanumeric characters.
-    #       Maximum 20 tags per role.
-
-dependencies: []
-  # List your role dependencies here, one per line. Be sure to remove the '[]' above,
-  # if you add dependencies to this list.
-
-collections:
-  - geant.gap_ansible
diff --git a/geant/gap_ansible/roles/geant_ip/tasks/compile.yaml b/geant/gap_ansible/roles/geant_ip/tasks/compile.yaml
deleted file mode 100644
index c185a7e5..00000000
--- a/geant/gap_ansible/roles/geant_ip/tasks/compile.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
----
-- name: Set ansible host to localhost to compile config when router is offline
-  when:
-    router.router_access_via_ts | ansible.builtin.bool
-  ansible.builtin.set_fact:
-    ansible_host: "localhost"
-    ansible_connection: local
-
-- name: Create a folder for all the things
-  ansible.builtin.file:
-    path: "/var/tmp/ansible_run_{{ opid }}"
-    state: directory
-    mode: '0755'
-  delegate_to: localhost
-
-- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ verb }}_{{ object }}.conf"
-  when: verb == "create"
-  ansible.builtin.template:
-    src: "{{ item.sbp.edge_port.node.vendor }}/{{ item.sbp.sbp_type }}/{{ verb }}_{{ object }}.j2"
-    dest: "/var/tmp/ansible_run_{{ opid }}/{{ verb }}_{{ object }}.conf"
-    lstrip_blocks: true
-    trim_blocks: true
-    mode: '0755'
-  delegate_to: localhost
diff --git a/geant/gap_ansible/roles/geant_ip/tasks/main.yml b/geant/gap_ansible/roles/geant_ip/tasks/main.yml
deleted file mode 100644
index 296b5291..00000000
--- a/geant/gap_ansible/roles/geant_ip/tasks/main.yml
+++ /dev/null
@@ -1,23 +0,0 @@
----
-# tasks file for geant_ip
-- name: Include Standard role tasks
-  ansible.builtin.include_tasks: standard_tasks.yaml
-
-- name: Include Filter role
-  ansible.builtin.include_role:
-    name: fw_filters
-  vars:
-    gen_filters: "{{ IPV4_EDGE_IN }}"
-  loop: "{{ subscription.nren_l3_core_service.nren_ap_list }}"
-
-- name: Include templates compilation for SBP
-  when: verb in verbs and object in ["sbp"]
-  ansible.builtin.include_tasks: compile.yaml
-  loop: "{{ subscription.nren_l3_core_service.nren_ap_list }}"
-
-- name: Include set connection tasks
-  ansible.builtin.include_tasks: connection_tasks.yaml
-
-- name: Include deploy tasks
-  when: verb in verbs
-  ansible.builtin.include_tasks: deploy.yaml
diff --git a/geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml b/geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml
deleted file mode 100644
index f1db3834..00000000
--- a/geant/gap_ansible/roles/geant_ip/tasks/standard_tasks.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
----
-- name: Print the usage
-  when: (verb is not defined) or (verb not in verbs) or (object is not defined) or (object not in objects)
-  ansible.builtin.debug:
-    msg:
-      - "'verb' and 'object' keywords are mandatory. Usage: -e verb=$verb -e object=$object"
-
-- name: Print defined verbs
-  when: (verb is not defined) or (verb not in verbs)
-  ansible.builtin.debug:
-    msg:
-      - "Allowed verb: {{ item }}"
-  loop: "{{ verbs }}"
-
-- name: Print defined objects
-  when: (object is not defined) or (object not in objects)
-  ansible.builtin.debug:
-    msg:
-      - "Allowed object: {{ item }}"
-  loop: "{{ objects }}"
-
-- name: Stop if arguments are incorrect
-  when: (verb is not defined) or (verb not in verbs) or (object is not defined) or (object not in objects)
-  ansible.builtin.meta: end_play
-
-- name: Import variables from 'all'
-  ansible.builtin.include_vars:
-    dir: /opt/ansible_inventory/group_vars/all
-
-- name: Import standard variables for {{ subscription.product.name }}
-  ansible.builtin.include_vars:
-    dir: /opt/ansible_inventory/geant_services/{{ subscription.product.product_type }}
-
-- name: Import partner specific variables for "{{ partner_name }}"
-  ansible.builtin.include_vars:
-    file: /opt/ansible_inventory/geant_partners/{{ partner_name | lower }}.yaml
-
-- name: Generate an ID for this run
-  ansible.builtin.set_fact:
-    opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
-
-- name: Print the ID
-  ansible.builtin.debug:
-    msg: "{{ opid }}"
diff --git a/geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2 b/geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2
deleted file mode 100644
index d2ba5293..00000000
--- a/geant/gap_ansible/roles/geant_ip/templates/nokia/l3/deploy_sbp.j2
+++ /dev/null
@@ -1,48 +0,0 @@
-{% set sbp = item.sbp %}
-{% set lag_name = sbp.edge_port.edge_port_name %}
-
-<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:alu="urn:ietf:params:xml:ns:netconf:base:1.0">
-    <configure xmlns="urn:nokia.com:sros:ns:yang:sr:conf">
-        <service xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
-            <ies xmlns="urn:nokia.com:sros:ns:yang:sr:conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
-                <interface alu:operation="replace">
-                    <interface-name>{{ lag_name }}.{{ sbp.vlan_id }}</interface-name>
-                    <description>SRV_GLOBAL CUSTOMER {{ partner_name }} #{{ partner_name }}-{{ sbp.ap_type }} ${{ sbp.geant_sid }} | ASN{{ asn }} | </description>
-                    <ip-mtu>{{ sbp_params.ip_mtu }}</ip-mtu>
-                    <sap>
-                        <sap-id>{{ lag_name }}:{{ sbp.vlan_id }}</sap-id>
-                        <admin-state>enable</admin-state>
-                    </sap>
-                    <ipv4>
-                      {% if sbp.ipv4_bfd %}
-                        <bfd>
-                            <admin-state>enable</admin-state>
-                            <transmit-interval>{{ sbp_params.bfd.ipv4.trasmit }}</transmit-interval>
-                            <receive>{{ sbp_params.bfd.ipv4.receive }}</receive>
-                            <multiplier>{{ sbp_params.bfd.ipv4.multiplier | default(3) }}</multiplier>
-                        </bfd>
-                      {% endif %}
-                        <primary>
-                            <address>{{ sbp.ipv4_address }}</address>
-                            <prefix-length>{{ sbp.ipv4_mask }}</prefix-length>
-                        </primary>
-                    </ipv4>
-                    <ipv6>
-                      {% if sbp.ipv6_bfd %}
-                        <bfd>
-                            <admin-state>enable</admin-state>
-                            <transmit-interval>{{ sbp_params.bfd.ipv6.trasmit }}</transmit-interval>
-                            <receive>{{ sbp_params.bfd.ipv6.receive }}</receive>
-                            <multiplier>{{ sbp_params.bfd.ipv6.multiplier | default(3) }}</multiplier>
-                        </bfd>
-                      {% endif %}
-                        <address>
-                            <ipv6-address>{{ sbp.ipv6_address }}</ipv6-address>
-                            <prefix-length>{{ sbp.ipv6_mask }}</prefix-length>
-                        </address>
-                    </ipv6>
-                </interface>
-            </ies>
-        </service>
-   </configure>
-</config>
diff --git a/geant/gap_ansible/roles/geant_ip/vars/main.yml b/geant/gap_ansible/roles/geant_ip/vars/main.yml
deleted file mode 100644
index dd2f35bc..00000000
--- a/geant/gap_ansible/roles/geant_ip/vars/main.yml
+++ /dev/null
@@ -1,15 +0,0 @@
----
-# vars file for geant_ip
-
-dry_run: true
-is_verification_workflow: false
-
-verbs:
-  - deploy
-  - check
-  - update
-  - terminate
-
-objects:
-  - sbp
-  - bgp
-- 
GitLab


From c36bbd8f5e999ce403f35ff67aa11e9cbd6ce0b0 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 21 Nov 2024 17:47:28 +0100
Subject: [PATCH 27/46] policy_options - var renaming

---
 .../roles/policy_options/templates/policy_options.j2            | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2 b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
index d36314cc..47e5933d 100644
--- a/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
+++ b/geant/gap_ansible/roles/policy_options/templates/policy_options.j2
@@ -25,7 +25,7 @@
   {#  {% endif %} #}
 
   {# Policy statements #}
-    {% if standard_nren_policies is defined %}
+    {% if nren_policies is defined %}
       {% with policy_obj=nren_policies %}
       {% include 'policy_statements.j2' %}
       {% endwith %}
-- 
GitLab


From eb403d61e8df0a9ea7872b45bb738c2e6768b68e Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:04:55 +0000
Subject: [PATCH 28/46] SBP template rework

If BFD enabled, take the GSO values if they are specified, else take the
default from the Service inventory.
---
 .../roles/sbp/templates/deploy_sbp.j2         | 32 ++++++++++++++++---
 1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2 b/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
index 7a581a43..18748b50 100644
--- a/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
+++ b/geant/gap_ansible/roles/sbp/templates/deploy_sbp.j2
@@ -34,9 +34,21 @@
                       {% if ap.sbp.v4_bfd_settings.bfd_enabled %}
                         <bfd>
                             <admin-state>enable</admin-state>
-                            <transmit-interval>{{ sbp_v4_bfd_interval }}</transmit-interval>
+                            {% if ap.sbp.v4_bfd_settings.bfd_interval_tx is not none %}
+                            <transmit-interval>{{ ap.sbp.v4_bfd_settings.bfd_interval_tx }}</transmit-interval>
+                            {% else %}
+                            <transmit-interval>{{ sbp_params.bfd.ipv4.transmit }}</transmit-interval>
+                            {% endif %}
+                            {% if ap.sbp.v4_bfd_settings.bfd_interval_rx is not none %}
+                            <receive>{{ ap.sbp.v4_bfd_settings.bfd_interval_rx  }}</receive>
+                            {% else %}
                             <receive>{{ sbp_params.bfd.ipv4.receive }}</receive>
-                            <multiplier>{{ sbp_v4_bfd_multiplier | default(3) }}</multiplier>
+                            {% endif %}
+                            {% if ap.sbp.v4_bfd_settings.bfd_multiplier is not none %}
+                            <multiplier>{{ ap.sbp.v4_bfd_settings.bfd_multiplier  }}</multiplier>
+                            {% else %}
+                            <multiplier>{{ sbp_params.bfd.ipv4.multiplier }}</multiplier>
+                            {% endif %}
                         </bfd>
                       {% endif %}
                         <primary>
@@ -48,9 +60,21 @@
                       {% if ap.sbp.v6_bfd_settings.bfd_enabled %}
                         <bfd>
                             <admin-state>enable</admin-state>
-                            <transmit-interval>{{ sbp_v6_bfd_interval }}</transmit-interval>
+                            {% if ap.sbp.v6_bfd_settings.bfd_interval_tx is not none %}
+                            <transmit-interval>{{ ap.sbp.v6_bfd_settings.bfd_interval_tx }}</transmit-interval>
+                            {% else %}
+                            <transmit-interval>{{ sbp_params.bfd.ipv6.transmit }}</transmit-interval>
+                            {% endif %}
+                            {% if ap.sbp.v6_bfd_settings.bfd_interval_rx is not none %}
+                            <receive>{{ ap.sbp.v6_bfd_settings.bfd_interval_rx  }}</receive>
+                            {% else %}
                             <receive>{{ sbp_params.bfd.ipv6.receive }}</receive>
-                            <multiplier>{{ sbp_v6_bfd_multiplier | default(3) }}</multiplier>
+                            {% endif %}
+                            {% if ap.sbp.v6_bfd_settings.bfd_multiplier is not none %}
+                            <multiplier>{{ ap.sbp.v6_bfd_settings.bfd_multiplier  }}</multiplier>
+                            {% else %}
+                            <multiplier>{{ sbp_params.bfd.ipv6.multiplier }}</multiplier>
+                            {% endif %}
                         </bfd>
                       {% endif %}
                         <address>
-- 
GitLab


From d48c961f08612820153b58830ca75dd24374601a Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:05:52 +0000
Subject: [PATCH 29/46] prefix_lists: remove debug print

---
 geant/gap_ansible/roles/prefix_lists/tasks/main.yml | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
index 42c174f4..9657bd96 100644
--- a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
@@ -42,12 +42,8 @@
 
     - name: Put everything together
       ansible.builtin.set_fact:
-        nren_prefix_lists: "{{ nren_prefix_lists | default([]) + [ {'name': ipv4_prefix_list_name, 'prefixes': bgpq4_ipv4_routes},
-                                                                  {'name': ipv6_prefix_list_name, 'prefixes': bgpq4_ipv6_routes} ] }}"
-
-    - name: Debug nren_prefix_lists
-      ansible.builtin.debug:
-        var: nren_prefix_lists
+        nren_prefix_lists: "{{ nren_prefix_lists | default([]) + [{'name': ipv4_prefix_list_name, 'prefixes': bgpq4_ipv4_routes},
+                                                                  {'name': ipv6_prefix_list_name, 'prefixes': bgpq4_ipv6_routes}] }}"
 
     - name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_prefix_lists.conf"
       ansible.builtin.template:
-- 
GitLab


From 5b3930d4b8a8016b7d790f1effba0a4b84851b9c Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:07:35 +0000
Subject: [PATCH 30/46] policy_options: `product_type` update

`product_type`:
NRENL3CoreService -> L3CoreService
and additional check on subscription.l3_core_service_type
---
 .../roles/policy_options/tasks/merge_vars.yaml         | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
index 80972737..54da8bfd 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -1,7 +1,9 @@
 ---
-- name: Prepare Policy vars for NREN L3 Core Service with standard filters
+- name: Prepare Policy vars for L3 Core Service with standard filters
   when: >-
-    subscription.product.product_type == "NRENL3CoreService"
+    subscription.product.product_type == "L3CoreService"
+    and
+    subscription.l3_core_service_type == "GÉANT IP"
   block:
     - name: Merge NREN standard filters
       ansible.builtin.set_fact:
@@ -11,12 +13,12 @@
       ansible.builtin.set_fact:
         nren_community_names: ["GEANT_{{ partner_name | upper }}", "GEANT_{{ partner_name | upper }}_BLOCK"]
 
-    - name: Set NREN community value
+    - name: Set NREN community value (2-byte ASN)
       when: (partner.asn | int) < 65536
       ansible.builtin.set_fact:
         nren_community_values: ["{{ geant_re_as_number }}:{{ partner.asn }}", "{{ bgp.block_community_prefix }}:{{ partner.asn }}"]
 
-    - name: Set NREN community value
+    - name: Set NREN community value (4-byte ASN)
       when: (partner.asn | int) > 65535
       ansible.builtin.set_fact:
         nren_community_values: ["origin:{{ partner.asn }}:{{ geant_re_as_number }}", "origin:{{ partner.asn }}:{{ block_community_prefix }}"]
-- 
GitLab


From 93db0a36a17040190fcf05132dd62d0ec05c0a85 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:10:05 +0000
Subject: [PATCH 31/46] fw_filters: updated checks on GSO `product_type` and
 `l3_core_service_type`

---
 .../roles/fw_filters/tasks/merge_variables.yaml           | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
index 16062a4e..e332f512 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/merge_variables.yaml
@@ -2,7 +2,9 @@
 # Prepare FW vars depending on the "service_type" and "custom_filters"
 - name: Prepare FW vars for NREN L3 Core Service with custom filters
   when: >-
-    subscription.product.product_type == "NRENL3CoreService"
+    subscription.product.product_type == "L3CoreService"
+    and
+    subscription.l3_core_service_type == "GÉANT IP"
     and
     ap.sbp.custom_firewall_filters | ansible.builtin.bool
   block:
@@ -17,7 +19,9 @@
 
 - name: Prepare FW vars for NREN L3 Core Service with standard filters
   when: >-
-    subscription.product.product_type == "NRENL3CoreService"
+    subscription.product.product_type == "L3CoreService"
+    and
+    subscription.l3_core_service_type == "GÉANT IP"
     and
     not ap.sbp.custom_firewall_filters | ansible.builtin.bool
   block:
-- 
GitLab


From 2b09d5a621b9575af8011d90d7e51f8586839b2f Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:10:39 +0000
Subject: [PATCH 32/46] fw_filters: update config artifact file name for
 consistency with other roles.

---
 geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
index 27e4357c..1d7d8d4c 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/deploy_fw.yaml
@@ -19,7 +19,7 @@
   geant.gap_ansible.nokia_netconf_config:
     format: xml
     default_operation: merge
-    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf') }}"
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf') }}"
     commit: true
     validate: true
     config_mode: private
@@ -32,7 +32,7 @@
   geant.gap_ansible.nokia_netconf_config:
     format: xml
     default_operation: merge
-    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf') }}"
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf') }}"
     commit: true
     commit_comment: "{{ commit_comment }}"
     config_mode: private
-- 
GitLab


From cd68bb89b149d8fb8cd469358695dd09a6e5c201 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:11:11 +0000
Subject: [PATCH 33/46] fw_filters: udpate Config file name for consistency
 with other roles

---
 geant/gap_ansible/roles/fw_filters/tasks/compile.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
index 6393b382..542c04d5 100644
--- a/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
+++ b/geant/gap_ansible/roles/fw_filters/tasks/compile.yaml
@@ -4,11 +4,11 @@
     ansible_host: "localhost"
     ansible_connection: local
 
-- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf"
+- name: Print the template in "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf"
   # when: verb in ["deploy", "update", "terminate"]
   ansible.builtin.template:
     src: "filters/gen_filters.j2"
-    dest: "/var/tmp/ansible_run_{{ opid }}/filters_{{ partner_name }}.conf"
+    dest: "/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_filters.conf"
     lstrip_blocks: true
     trim_blocks: true
     mode: '0755'
-- 
GitLab


From d3f8fc9ee67af7c3f88780a30bb29e4b050de198 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:12:31 +0000
Subject: [PATCH 34/46] deploy_service_config: cleanup and linting

---
 .../tasks/assemble_config.yml                 |  79 +++--
 .../tasks/connection_tasks.yml                |   6 -
 .../deploy_service_config/tasks/main.yml      |  17 +-
 .../tasks/push_config.yml                     |  29 +-
 .../tasks/traverse_subscription.yml           |  11 +-
 .../deploy_service_config/tests/README.md     |  20 --
 .../tests/general_mechanics.yml               |  10 -
 .../deploy_service_config/tests/inventory     |   2 -
 .../tests/modified_gip_latest.json            | 269 ------------------
 .../deploy_service_config/tests/test.yml      |  56 ----
 .../roles/deploy_service_config/vars/main.yml |   3 +
 11 files changed, 69 insertions(+), 433 deletions(-)
 delete mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/README.md
 delete mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml
 delete mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/inventory
 delete mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json
 delete mode 100644 geant/gap_ansible/roles/deploy_service_config/tests/test.yml

diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
index 4196066d..75a420c6 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
@@ -1,49 +1,48 @@
 ---
 
-# Although I was working on a separate branch, I had 
+# Although I was working on a separate branch, I had
 # to resist the temptation of not modifying the entry
 # playbook in order to introduce the opid_dir variable
-# and avoid it's use all over the place. 
+# and avoid it's use all over the place.
 
 - name: Locally-delegated assemble block
   delegate_to: localhost
   block:
-  # Because ansible.builtin.assemble works with a single directory 
-  - name: Create a subdirectory for the assembled output
-    ansible.builtin.file:
-      path: "/var/tmp/ansible_run_{{ opid }}/assembled/"
-      state: directory
-      mode: '0755'
-  
-  # Enumeration prefix is needed to impact the order of assembly 
-  - name: Copy Nokia SR OS header for assembly
-    ansible.builtin.copy:
-      src: "{{ vendor }}/header"
-      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/00_header"
+  # Because ansible.builtin.assemble works with a single directory
+    - name: Create a subdirectory for the assembled output
+      ansible.builtin.file:
+        path: "/var/tmp/ansible_run_{{ opid }}/assembled/"
+        state: directory
+        mode: '0755'
 
-  # Enumeration prefix is needed to impact the order of assembly 
-  - name: Copy Nokia SR OS footer for assembly
-    ansible.builtin.copy:
-      src: "{{ vendor }}/footer"
-      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/02_footer"
-  
-  # Enumeration prefix is needed to impact the order of assembly 
-  - name: Assemble body of the config
-    ansible.builtin.assemble:
-      src: "/var/tmp/ansible_run_{{ opid }}/"
-      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/01-body"
-  
-  # Use the enumeration prefixes to assemble fragments in the right order 
-  - name: Merge header, body and footer to get the final config 
-    ansible.builtin.assemble:
-      src: "/var/tmp/ansible_run_{{ opid }}/assembled"
-      dest: "/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment"
-  
-  - name: Clean up the fragments
-    ansible.builtin.file:
-      path: "{{ item }}"
-      state: absent
-      mode: '0755'
-    with_fileglob:
-    - "/var/tmp/ansible_run_{{ opid }}/assembled/0*"  
- 
+    # Enumeration prefix is needed to impact the order of assembly
+    - name: Copy Nokia SR OS header for assembly
+      ansible.builtin.copy:
+        src: "{{ vendor }}/header"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/00_header"
+
+    # Enumeration prefix is needed to impact the order of assembly
+    - name: Copy Nokia SR OS footer for assembly
+      ansible.builtin.copy:
+        src: "{{ vendor }}/footer"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/02_footer"
+
+    # Enumeration prefix is needed to impact the order of assembly
+    - name: Assemble body of the config
+      ansible.builtin.assemble:
+        src: "/var/tmp/ansible_run_{{ opid }}/"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/01-body"
+
+    # Use the enumeration prefixes to assemble fragments in the right order
+    - name: Merge header, body and footer to get the final config
+      ansible.builtin.assemble:
+        src: "/var/tmp/ansible_run_{{ opid }}/assembled"
+        dest: "/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment"
+
+    - name: Clean up the fragments
+      ansible.builtin.file:
+        path: "{{ item }}"
+        state: absent
+        mode: '0755'
+      with_fileglob:
+        - "/var/tmp/ansible_run_{{ opid }}/assembled/0*"
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
index 38022c8e..6dd169a3 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/connection_tasks.yml
@@ -5,12 +5,6 @@
     ansible_port: "{{ router.router_ts_port }}"
   when: router.router_access_via_ts | ansible.builtin.bool
 
-
-# Loading of group _vars/ should probably be done 
-# from the entry-playbook. Or perhaps from a dedicated role
-#- name: Import variables from 'all'
-#  ansible.builtin.include_vars:
-#    dir: /opt/ansible_inventory/group_vars/all
 - name: Load netconf connection config
   ansible.builtin.set_fact:
     ansible_connection: "{{ netconf_access[router.vendor].ansible_connection }}"
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
index fec9babe..cfb638df 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/main.yml
@@ -1,10 +1,9 @@
 ---
-
-- name: Fetch access port info from the subscription   
-  ansible.builtin.include_tasks: traverse_subscription.yml
+# - name: Fetch access port info from the subscription
+#   ansible.builtin.include_tasks: traverse_subscription.yml
 
 # The "delegate_to" works as expected in conjuction with "import_tasks".
-# However, mixing "imports" with "includes" is not recommended. 
+# However, mixing "imports" with "includes" is not recommended.
 # Another way is to "apply" the "delegate_to: localhost".
 - name: Assemble the config from fragments in previous roles
   ansible.builtin.include_tasks: assemble_config.yml
@@ -12,18 +11,16 @@
 - name: Include set connection tasks
   ansible.builtin.include_tasks: connection_tasks.yml
 
-# The "verb == deploy" is (probably) not needed 
-# because it has already been checked in the 
+# The "verb == deploy" is (probably) not needed
+# because it has already been checked in the
 # invoking playbook (nren_l3_core_services.yaml):
-#   
+#
 # - name: Deploy
 #    block:
 #    - name: Include deployment role
 #      ansible.builtin.include_role:
 #        name: deploy_service_config
-#     when: verb == deploy  
+#     when: verb == deploy
 #
 - name: Push assembled config to device
   ansible.builtin.include_tasks: push_config.yml
-
-
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
index 408afdc3..a8b9d421 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
@@ -1,41 +1,42 @@
-
-- name: 'Config deploy [CHECK ONLY][NOKIA]'
-  # ansible.netcommon.netconf_config:
+---
+- name: Config deploy [CHECK ONLY][NOKIA]
+  when: >
+    dry_run | ansible.builtin.bool
+    and
+    vendor == "nokia"
   geant.gap_ansible.nokia_netconf_config:
     format: xml
     default_operation: merge
     content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment') }}"
     commit: true
     validate: true
-    #config_mode: private ; CHANGELOG.md suggests this is implicit now?
+    config_mode: private
   diff: true
   register: output
   check_mode: true
-  when: >
-    ( dry_run | ansible.builtin.bool ) is true and
-    vendor == "nokia"
 
 - name: Fail if there is any diff
-  ansible.builtin.fail:
-    msg: iBGP configuration drifted!!!
   when: >
     output.changed | ansible.builtin.bool
     and
     is_verification_workflow | ansible.builtin.bool
+  ansible.builtin.fail:
+    msg: Service "{{ subscription.product.product_type }}" config for "{{ partner_name | upper }}" drifted!
 
-- name: 'Config deploy [AND COMMIT][NOKIA]'
+- name: Config deploy [AND COMMIT][NOKIA]
+  when: >
+    not dry_run | ansible.builtin.bool
+    and
+    vendor == "nokia"
   geant.gap_ansible.nokia_netconf_config:
     format: xml
     default_operation: merge
     content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment') }}"
     commit: true
     commit_comment: "{{ commit_comment }}"
-    #config_mode: private ; CHANGELOG.md suggests this is implicit now?
+    config_mode: private
   diff: true
   check_mode: false
-  when: >
-    ( dry_run | ansible.builtin.bool ) is false and
-    vendor == "nokia"
 
 
 
diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
index b6369efb..86ae5601 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/traverse_subscription.yml
@@ -1,8 +1,8 @@
 ---
 
-# The following tarversal of JSON should be part of 
-# the entry playbook. Or maybe even better, a separate 
-# role invoked at its very beginning so that all other 
+# The following tarversal of JSON should be part of
+# the entry playbook. Or maybe even better, a separate
+# role invoked at its very beginning so that all other
 # roles can use it.
 
 #
@@ -11,7 +11,7 @@
 
 - name: Find matching nren_ap_list element
   ansible.builtin.set_fact:
-    filtered_ap_list: "{{ subscription['nren_l3_core_service']['nren_ap_list'] | json_query(query) }}"
+    filtered_ap_list: "{{ subscription['l3_core_service']['ap_list'] | json_query(query) }}"
   vars:
     query: "[?sbp.edge_port.node.router_fqdn == `{{ inventory_hostname }}`]"
 
@@ -22,7 +22,7 @@
 
 - name: Find matching nren_ap_list element
   ansible.builtin.set_fact:
-    ap: "{{ filtered_ap_list[0] }}"   
+    ap: "{{ filtered_ap_list[0] }}"
 
 - name: Print the matched nren_ap_list element
   ansible.builtin.debug:
@@ -43,4 +43,3 @@
 - name: Print the vendor
   ansible.builtin.debug:
     msg: "{{ vendor }}"
-
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/README.md b/geant/gap_ansible/roles/deploy_service_config/tests/README.md
deleted file mode 100644
index a09942e7..00000000
--- a/geant/gap_ansible/roles/deploy_service_config/tests/README.md
+++ /dev/null
@@ -1,20 +0,0 @@
-
-Before running this:
-
-```
-ansible-playbook -i rt0.ely.uk.dev.geant.private, -e@modified_gip_latest.json test.yml -k
-```
-
-make sure that `/etc/hosts` has the corresponding entry:
-
-```
-127.0.0.1       rt0.ely.uk.dev.geant.private
-```
-
-and that SSH service has been started:
-
-```
-sudo systemctl start ssh
-```
-
-`Note:` The `rt0.ely.uk.dev.geant.private` matches the second element (`BACKUP`) in the JSON's `nren_ap_list[]`. 
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml b/geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml
deleted file mode 100644
index 0d05e076..00000000
--- a/geant/gap_ansible/roles/deploy_service_config/tests/general_mechanics.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-## Netconf access
-#
-netconf_access:
-  nokia:
-    ansible_network_os: geant.gap_ansible.sros
-    # ansible_network_os: nokia.sros.md
-    ansible_connection: netconf
-  juniper:
-    ansible_network_os: junos
-    ansible_connection: netconf
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/inventory b/geant/gap_ansible/roles/deploy_service_config/tests/inventory
deleted file mode 100644
index 878877b0..00000000
--- a/geant/gap_ansible/roles/deploy_service_config/tests/inventory
+++ /dev/null
@@ -1,2 +0,0 @@
-localhost
-
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json b/geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json
deleted file mode 100644
index fe102416..00000000
--- a/geant/gap_ansible/roles/deploy_service_config/tests/modified_gip_latest.json
+++ /dev/null
@@ -1,269 +0,0 @@
-{
-  "partner_name": "JISC",
-  "subscription": {
-    "description": "GÉANT IP service",
-    "nren_l3_core_service": {
-      "nren_ap_list": [
-        {
-          "sbp": {
-            "name": "ServiceBindingPort",
-            "label": null,
-            "vlan_id": 11,
-            "sbp_type": "l3",
-            "edge_port": {
-              "name": "EdgePortBlock",
-              "node": {
-                "name": "RouterBlock",
-                "label": null,
-                "vendor": "nokia",
-                "router_fqdn": "rt0.cbg.uk.dev.geant.private",
-                "router_role": "pe",
-                "router_site": {
-                  "name": "SiteBlock",
-                  "label": null,
-                  "site_city": "Cambridge",
-                  "site_name": "CBG",
-                  "site_tier": "1",
-                  "site_country": "UK",
-                  "site_latitude": "52.2",
-                  "site_longitude": "0.11667",
-                  "site_ts_address": "62.40.111.70",
-                  "site_internal_id": 11,
-                  "site_country_code": "UK",
-                  "owner_subscription_id": "b842d5ab-144d-4c42-8c6a-4c7b5402b30f",
-                  "site_bgp_community_id": 11,
-                  "subscription_instance_id": "4c78e94b-60a0-4227-aa69-2d95edfb27bb"
-                },
-                "router_ts_port": 3830,
-                "router_access_via_ts": true,
-                "owner_subscription_id": "efee8705-5f0f-4fec-844a-7cd7626fe6a8",
-                "router_lo_iso_address": "49.51e5.0001.0101.0100.0002.00",
-                "router_lo_ipv4_address": "10.101.0.2",
-                "router_lo_ipv6_address": "dead:feeb:101::2",
-                "subscription_instance_id": "a8355d18-4f58-4dd7-82e8-c7ca6297416d"
-              },
-              "label": null,
-              "enable_lacp": true,
-              "geant_ga_id": "GA-5577",
-              "mac_address": null,
-              "member_speed": "400G",
-              "encapsulation": "dot1q",
-              "minimum_links": 2,
-              "edge_port_name": "lag-21",
-              "edge_port_type": "CUSTOMER",
-              "ignore_if_down": false,
-              "edge_port_ae_members": [
-                {
-                  "name": "EdgePortAEMemberBlock",
-                  "label": null,
-                  "interface_name": "2/1/c17/1",
-                  "interface_description": "jisc-port-21",
-                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
-                  "subscription_instance_id": "989ac8dd-0db3-4d43-b638-287cbb0b6b30"
-                },
-                {
-                  "name": "EdgePortAEMemberBlock",
-                  "label": null,
-                  "interface_name": "2/1/c35/1",
-                  "interface_description": "jisc-port-22",
-                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
-                  "subscription_instance_id": "634f079a-f8ff-45c2-8f33-809e3472f70d"
-                }
-              ],
-              "edge_port_description": "JISC edge port-2",
-              "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
-              "subscription_instance_id": "587383db-c04c-4848-bf26-0610190a273f"
-            },
-            "geant_sid": "gs-19234",
-            "ipv4_mask": 31,
-            "ipv6_mask": 126,
-            "is_tagged": true,
-            "ipv4_address": "1.1.1.1",
-            "ipv6_address": "2001:798::1",
-            "bgp_session_list": [
-              {
-                "name": "BGPSession",
-                "label": null,
-                "families": [
-                  "v4unicast"
-                ],
-                "is_passive": false,
-                "bfd_enabled": false,
-                "bfd_interval": null,
-                "is_multi_hop": true,
-                "peer_address": "1.1.1.2",
-                "rtbh_enabled": true,
-                "bfd_multiplier": null,
-                "multipath_enabled": false,
-                "authentication_key": "alQERqnaerq324",
-                "send_default_route": false,
-                "has_custom_policies": false,
-                "owner_subscription_id": "5f86aa86-9d88-4e63-b893-6f42e50806ef",
-                "subscription_instance_id": "18de722b-a050-4887-bc22-7291cdbe2d97"
-              },
-              {
-                "name": "BGPSession",
-                "label": null,
-                "families": [
-                  "v6unicast"
-                ],
-                "is_passive": false,
-                "bfd_enabled": false,
-                "bfd_interval": null,
-                "is_multi_hop": true,
-                "peer_address": "2001:798::2",
-                "rtbh_enabled": true,
-                "bfd_multiplier": null,
-                "multipath_enabled": false,
-                "authentication_key": "alQERqnaerq324",
-                "send_default_route": false,
-                "has_custom_policies": false,
-                "owner_subscription_id": "7dd1a6f2-8afe-4324-81f4-f34b2fce7f6f",
-                "subscription_instance_id": "a88f1a46-eaac-44f2-bb2a-2c343ea4f2fc"
-              }
-            ],
-            "owner_subscription_id": "e257a102-1c24-44b6-a161-b3e63ed102fc",
-            "custom_firewall_filters": false,
-            "subscription_instance_id": "8d3e8499-b121-4bf8-b92a-78bd8647334d"
-          },
-          "name": "NRENAccessPort",
-          "label": null,
-          "ap_type": "PRIMARY",
-          "owner_subscription_id": "215a1618-7615-4ecd-9b2a-06711187d012",
-          "subscription_instance_id": "a65599ed-48c8-469c-a562-942fe75f368e"
-        },
-        {
-          "sbp": {
-            "name": "ServiceBindingPort",
-            "label": null,
-            "vlan_id": 11,
-            "sbp_type": "l3",
-            "edge_port": {
-              "name": "EdgePortBlock",
-              "node": {
-                "name": "RouterBlock",
-                "label": null,
-                "vendor": "nokia",
-                "router_fqdn": "rt0.ely.uk.dev.geant.private",
-                "router_role": "pe",
-                "router_site": {
-                  "name": "SiteBlock",
-                  "label": null,
-                  "site_city": "Cambridge",
-                  "site_name": "CBG",
-                  "site_tier": "1",
-                  "site_country": "UK",
-                  "site_latitude": "52.2",
-                  "site_longitude": "0.11667",
-                  "site_ts_address": "62.40.111.70",
-                  "site_internal_id": 11,
-                  "site_country_code": "UK",
-                  "owner_subscription_id": "b842d5ab-144d-4c42-8c6a-4c7b5402b30f",
-                  "site_bgp_community_id": 11,
-                  "subscription_instance_id": "4c78e94b-60a0-4227-aa69-2d95edfb27bb"
-                },
-                "router_ts_port": 3830,
-                "router_access_via_ts": true,
-                "owner_subscription_id": "efee8705-5f0f-4fec-844a-7cd7626fe6a8",
-                "router_lo_iso_address": "49.51e5.0001.0101.0100.0002.00",
-                "router_lo_ipv4_address": "10.101.0.2",
-                "router_lo_ipv6_address": "dead:feeb:101::2",
-                "subscription_instance_id": "a8355d18-4f58-4dd7-82e8-c7ca6297416d"
-              },
-              "label": null,
-              "enable_lacp": true,
-              "geant_ga_id": "GA-5577",
-              "mac_address": null,
-              "member_speed": "400G",
-              "encapsulation": "dot1q",
-              "minimum_links": 2,
-              "edge_port_name": "lag-21",
-              "edge_port_type": "CUSTOMER",
-              "ignore_if_down": false,
-              "edge_port_ae_members": [
-                {
-                  "name": "EdgePortAEMemberBlock",
-                  "label": null,
-                  "interface_name": "2/1/c17/1",
-                  "interface_description": "jisc-port-21",
-                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
-                  "subscription_instance_id": "989ac8dd-0db3-4d43-b638-287cbb0b6b30"
-                },
-                {
-                  "name": "EdgePortAEMemberBlock",
-                  "label": null,
-                  "interface_name": "2/1/c35/1",
-                  "interface_description": "jisc-port-22",
-                  "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
-                  "subscription_instance_id": "634f079a-f8ff-45c2-8f33-809e3472f70d"
-                }
-              ],
-              "edge_port_description": "JISC edge port-2",
-              "owner_subscription_id": "0ce37d72-3112-40b8-866b-a68b302fcfab",
-              "subscription_instance_id": "587383db-c04c-4848-bf26-0610190a273f"
-            },
-            "geant_sid": "gs-19234",
-            "ipv4_mask": 31,
-            "ipv6_mask": 126,
-            "is_tagged": true,
-            "ipv4_address": "1.1.1.1",
-            "ipv6_address": "2001:798::1",
-            "bgp_session_list": [
-              {
-                "name": "BGPSession",
-                "label": null,
-                "families": [
-                  "v4unicast"
-                ],
-                "is_passive": false,
-                "bfd_enabled": false,
-                "bfd_interval": null,
-                "is_multi_hop": true,
-                "peer_address": "1.1.1.2",
-                "rtbh_enabled": true,
-                "bfd_multiplier": null,
-                "multipath_enabled": false,
-                "authentication_key": "alQERqnaerq324",
-                "send_default_route": false,
-                "has_custom_policies": false,
-                "owner_subscription_id": "5f86aa86-9d88-4e63-b893-6f42e50806ef",
-                "subscription_instance_id": "18de722b-a050-4887-bc22-7291cdbe2d97"
-              },
-              {
-                "name": "BGPSession",
-                "label": null,
-                "families": [
-                  "v6unicast"
-                ],
-                "is_passive": false,
-                "bfd_enabled": false,
-                "bfd_interval": null,
-                "is_multi_hop": true,
-                "peer_address": "2001:798::2",
-                "rtbh_enabled": true,
-                "bfd_multiplier": null,
-                "multipath_enabled": false,
-                "authentication_key": "alQERqnaerq324",
-                "send_default_route": false,
-                "has_custom_policies": false,
-                "owner_subscription_id": "7dd1a6f2-8afe-4324-81f4-f34b2fce7f6f",
-                "subscription_instance_id": "a88f1a46-eaac-44f2-bb2a-2c343ea4f2fc"
-              }
-            ],
-            "owner_subscription_id": "e257a102-1c24-44b6-a161-b3e63ed102fc",
-            "custom_firewall_filters": false,
-            "subscription_instance_id": "8d3e8499-b121-4bf8-b92a-78bd8647334d"
-          },
-          "name": "NRENAccessPort",
-          "label": null,
-          "ap_type": "BAKUP",
-          "owner_subscription_id": "215a1618-7615-4ecd-9b2a-06711187d012",
-          "subscription_instance_id": "a65599ed-48c8-469c-a562-942fe75f368e"
-        }
-      ]
-    }
-  },
-  "edge_port_fqdn_list": [
-    "rt0.cbg.uk.dev.geant.private"
-  ]
-}
diff --git a/geant/gap_ansible/roles/deploy_service_config/tests/test.yml b/geant/gap_ansible/roles/deploy_service_config/tests/test.yml
deleted file mode 100644
index 7f37d19e..00000000
--- a/geant/gap_ansible/roles/deploy_service_config/tests/test.yml
+++ /dev/null
@@ -1,56 +0,0 @@
----
-- name: Qucik test playbook for this role 
-  hosts: all
-  tasks:
-  - name: Generate an ID for this run
-    ansible.builtin.set_fact:
-      opid: "{{ lookup('community.general.random_string', length=18, special=false) }}"
-
-  - name: Print the ID
-    ansible.builtin.debug:
-      msg: "{{ opid }}"
-
-  - name: Create a folder for all compiled output
-    ansible.builtin.file:
-      path: "/var/tmp/ansible_run_{{ opid }}"
-      state: directory
-      mode: '0755'
-    delegate_to: localhost
-
-  - name: Create A.txt with distinct content
-    copy:
-      dest: "/var/tmp/ansible_run_{{ opid }}/A.txt"
-      content: |
-        This is file A.
-        Line 1 in A.txt
-        Line 2 in A.txt
-    delegate_to: localhost
-
-  - name: Create B.txt with distinct content
-    copy:
-      dest: "/var/tmp/ansible_run_{{ opid }}/B.txt"
-      content: |
-        This is file B.
-        Line 1 in B.txt
-        Line 2 in B.txt
-    delegate_to: localhost
-
-  - name: Create C.txt with distinct content
-    copy:
-      dest: "/var/tmp/ansible_run_{{ opid }}/C.txt"
-      content: |
-        This is file C.
-        Line 1 in C.txt
-        Line 2 in C.txt
-    delegate_to: localhost
-
-  - name: Include group_vars just for this test
-    ansible.builtin.include_vars:
-      file: ./general_mechanics.yml
-
-  - name: Include this role for testing
-    ansible.builtin.include_role:
-      name: ../../deploy_service_config
-       
-
-
diff --git a/geant/gap_ansible/roles/deploy_service_config/vars/main.yml b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
index bf5a91de..5def5f74 100644
--- a/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/vars/main.yml
@@ -2,3 +2,6 @@
 # vars file for deploy_service_config
 dry_run: true
 is_verification_workflow: false
+
+router: "{{ ap.sbp.edge_port.node }}"
+vendor: "{{ router.vendor }}"
-- 
GitLab


From 0f195fa2cec22cd52e580fd82a90d12c63117eaf Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:13:08 +0000
Subject: [PATCH 35/46] l3_core_service playbook rename in line with GSO.

---
 ...core_service.yaml => l3_core_service.yaml} | 22 +++++++++----------
 1 file changed, 10 insertions(+), 12 deletions(-)
 rename geant/gap_ansible/playbooks/{nren_l3_core_service.yaml => l3_core_service.yaml} (78%)

diff --git a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml b/geant/gap_ansible/playbooks/l3_core_service.yaml
similarity index 78%
rename from geant/gap_ansible/playbooks/nren_l3_core_service.yaml
rename to geant/gap_ansible/playbooks/l3_core_service.yaml
index 9d3f89b5..f3f835fa 100644
--- a/geant/gap_ansible/playbooks/nren_l3_core_service.yaml
+++ b/geant/gap_ansible/playbooks/l3_core_service.yaml
@@ -1,8 +1,6 @@
 - name: Manage GEANT IP instance
   hosts: all
   gather_facts: false
-  # roles:
-  #   - ../roles/geant_ip
   tasks:
     - name: Generate an ID for this run
       ansible.builtin.set_fact:
@@ -23,13 +21,13 @@
       ansible.builtin.include_vars:
         dir: /opt/ansible_inventory/group_vars/all
 
-    - name: Import standard variables for {{ subscription.product.name }}
+    - name: Import standard variables for "{{ subscription.product.product_type }}/{{ subscription.l3_core_service_type | replace(' ', '_') }}"
       ansible.builtin.include_vars:
-        dir: /opt/ansible_inventory/geant_services/{{ subscription.product.product_type }}
+        dir: /opt/ansible_inventory/geant_services/{{ subscription.product.product_type }}/{{ subscription.l3_core_service_type | replace(' ', '_') }}
 
-    - name: Import partner specific variables for "{{ partner_name }}"
+    - name: Import partner specific variables for "{{ partner_name | upper }}"
       ansible.builtin.include_vars:
-        dir: /opt/ansible_inventory/geant_partners/{{ partner_name | lower }}
+        dir: /opt/ansible_inventory/geant_partners/{{ partner_name | upper }}
 
     - name: Compile Prefix Lists
       block:
@@ -37,7 +35,7 @@
           ansible.builtin.include_role:
             name: prefix_lists
           loop:
-            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+            "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
@@ -47,7 +45,7 @@
           ansible.builtin.include_role:
             name: fw_filters
           loop:
-            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+            "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
@@ -57,7 +55,7 @@
           ansible.builtin.include_role:
             name: sbp
           loop:
-            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+            "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
@@ -67,7 +65,7 @@
           ansible.builtin.include_role:
             name: policy_options
           loop:
-            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+            "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
@@ -77,7 +75,7 @@
           ansible.builtin.include_role:
             name: bgp_config
           loop:
-            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+            "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
@@ -88,6 +86,6 @@
           ansible.builtin.include_role:
             name: deploy_service_config
           loop:
-            "{{ subscription.nren_l3_core_service.nren_ap_list }}"
+            "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
-- 
GitLab


From ab6b9edae71e3613f4595881a37933558e43e689 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 12:17:33 +0000
Subject: [PATCH 36/46] bgp_config role - template update

Use of proper `neighbor.ip_type` field to decide on groups, etc.
---
 .../roles/bgp_config/templates/bgp_neighbor.j2            | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
index 773798c1..6c53f994 100644
--- a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
@@ -4,9 +4,9 @@
                     <admin-state>enable</admin-state>
                     <description>{{ partner_name | upper }}_{{ partner.type }}</description>
 
-                    {% if neighbor.peer_address | ipv4 %}
+                    {% if neighbor.ip_type == 'ipv4' %}
                     <group>{{ bgp.group.ipv4 }}</group>
-                    {% elif neighbor.peer_address | ipv6 %}
+                    {% elif neighbor.ip_type == 'ipv6' %}
                     <group>{{ bgp.group.ipv6 }}</group>
                     {% endif %}
                     <peer-as>{{ partner.asn }}</peer-as>
@@ -28,11 +28,11 @@
                       {% endfor %}
                     </family>
                     <import>
-                      {% if neighbor.peer_address | ipv4 %}
+                      {% if neighbor.ip_type == 'ipv4' %}
                         {% for pol in import_policies_v4 %}
                         <policy>{{ pol }}</policy>
                         {% endfor %}
-                      {% elif neighbor.peer_address | ipv6 %}
+                      {% elif neighbor.ip_type == 'ipv6' %}
                         {% for pol in import_policies_v6 %}
                         <policy>{{ pol }}</policy>
                         {% endfor %}
-- 
GitLab


From c19a04a46e9ef8d5e206f751db46b655a65d9566 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 13:18:30 +0000
Subject: [PATCH 37/46] prefix_lists: update meta/main

---
 .../roles/prefix_lists/meta/main.yml          | 30 +++++++------------
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/geant/gap_ansible/roles/prefix_lists/meta/main.yml b/geant/gap_ansible/roles/prefix_lists/meta/main.yml
index ea68190c..ed3d2d88 100644
--- a/geant/gap_ansible/roles/prefix_lists/meta/main.yml
+++ b/geant/gap_ansible/roles/prefix_lists/meta/main.yml
@@ -1,27 +1,14 @@
 galaxy_info:
-  author: your name
-  description: your role description
-  company: your company (optional)
+  author: Simone Spinelli, A. Kurbatov
+  description: Geant Orchestration and Automation Team
+  company: Geant
 
-  # If the issue tracker for your role is not on github, uncomment the
-  # next line and provide a value
-  # issue_tracker_url: http://example.com/issue/tracker
+  license: MIT
 
-  # Choose a valid license ID from https://spdx.org - some suggested licenses:
-  # - BSD-3-Clause (default)
-  # - MIT
-  # - GPL-2.0-or-later
-  # - GPL-3.0-only
-  # - Apache-2.0
-  # - CC-BY-4.0
-  license: license (GPL-2.0-or-later, MIT, etc)
+  min_ansible_version: '2.10'
 
-  min_ansible_version: 2.1
-
-  # If this a Container Enabled role, provide the minimum Ansible Container version.
-  # min_ansible_container_version:
-
-  galaxy_tags: []
+  galaxy_tags:
+    - network
     # List tags for your role here, one per line. A tag is a keyword that describes
     # and categorizes the role. Users find roles by searching for tags. Be sure to
     # remove the '[]' above, if you add tags to this list.
@@ -32,3 +19,6 @@ galaxy_info:
 dependencies: []
   # List your role dependencies here, one per line. Be sure to remove the '[]' above,
   # if you add dependencies to this list.
+
+collections:
+  - geant.gap_ansible
-- 
GitLab


From 5b519cbde09cd83c1a9ad71499ad855007cce7c6 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 13:19:24 +0000
Subject: [PATCH 38/46] prefix_lists: update tasks in accordance to Ansible
 Linting documentation

---
 geant/gap_ansible/roles/prefix_lists/tasks/main.yml | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
index 9657bd96..966e0cb0 100644
--- a/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
+++ b/geant/gap_ansible/roles/prefix_lists/tasks/main.yml
@@ -1,11 +1,12 @@
 ---
 # tasks file for prefix_lists
-- name: Big block
+- name: Collect prefixes and render the prefix template
   delegate_to: localhost
   block:
     - name: Collect IPV4 routes from bgpq4
-      ansible.builtin.shell: bgpq4 -j4 "{{ partner.as_set }}"
+      ansible.builtin.command: bgpq4 -j4 "{{ partner.as_set }}"
       register: bgpq4_ipv4_routes_in_json
+      changed_when: true
 
     - name: Convert IPV4 output to real json
       ansible.builtin.set_fact:
@@ -23,8 +24,9 @@
 
 
     - name: Collect IPV6 routes from bgpq4
-      ansible.builtin.shell: bgpq4 -j6 "{{ partner.as_set }}"
+      ansible.builtin.command: bgpq4 -j6 "{{ partner.as_set }}"
       register: bgpq4_ipv6_routes_in_json
+      changed_when: true
 
     - name: Convert IPV6 outeput to real json
       ansible.builtin.set_fact:
-- 
GitLab


From a12b44e2fb1a83dda3d9dabe5ee8a160b1fde25e Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 18:52:51 +0000
Subject: [PATCH 39/46] bgp_config updates

- BFD liveness
- export_policies split into v4 and v6
---
 .../roles/bgp_config/tasks/merge_vars.yaml            |  3 ++-
 .../roles/bgp_config/templates/bgp_neighbor.j2        | 11 ++++++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
index 48209820..77676232 100644
--- a/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/bgp_config/tasks/merge_vars.yaml
@@ -3,4 +3,5 @@
   ansible.builtin.set_fact:
     import_policies_v4: "{{ bgp.policies.import.v4 }}"
     import_policies_v6: "{{ bgp.policies.import.v6 }}"
-    export_policies: "{{ bgp.policies.export }}"
+    export_policies_v4: "{{ bgp.policies.export.v4 }}"
+    export_policies_v6: "{{ bgp.policies.export.v6 }}"
diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
index 6c53f994..81422c64 100644
--- a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
@@ -2,6 +2,9 @@
                 <neighbor alu:operation="replace">
                     <ip-address>{{ neighbor.peer_address }}</ip-address>
                     <admin-state>enable</admin-state>
+                    {% if neighbor.bfd_enabled %}
+                    <bfd-liveness>true</bfd-liveness>
+                    {% endif %}
                     <description>{{ partner_name | upper }}_{{ partner.type }}</description>
 
                     {% if neighbor.ip_type == 'ipv4' %}
@@ -39,9 +42,15 @@
                       {% endif %}
                     </import>
                     <export>
-                        {% for pol in export_policies %}
+                      {% if neighbor.ip_type == 'ipv4' %}
+                        {% for pol in export_policies_v4 %}
+                        <policy>{{ pol }}</policy>
+                        {% endfor %}
+                      {% elif neighbor.ip_type == 'ipv6' %}
+                        {% for pol in export_policies_v6 %}
                         <policy>{{ pol }}</policy>
                         {% endfor %}
+                      {% endif %}
                     </export>
                 </neighbor>
                 {% endfor %}
-- 
GitLab


From a0c0de0e77b14e51ca94d1e299bdea1ef703fc28 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 18:55:26 +0000
Subject: [PATCH 40/46] policy_options - proper handling of custom policies

Per BGP `ip_type`:
will cover 4 cases:
- custom v4, custom v6
- custom v4, standard v6
- standard v4, custom v6
- standard v4, standard v6
---
 .../policy_options/tasks/merge_vars.yaml      | 70 ++++++++++++++++---
 1 file changed, 60 insertions(+), 10 deletions(-)

diff --git a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
index 54da8bfd..f4bfd77a 100644
--- a/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
+++ b/geant/gap_ansible/roles/policy_options/tasks/merge_vars.yaml
@@ -5,9 +5,13 @@
     and
     subscription.l3_core_service_type == "GÉANT IP"
   block:
-    - name: Merge NREN standard filters
+    - name: Merge NREN standard policies V4
       ansible.builtin.set_fact:
-        standard_nren_policies: "{{ lookup('community.general.merge_variables', 'STANDARD_PO_POL_STATEMENTS') }}"
+        standard_nren_policies_v4: "{{ lookup('community.general.merge_variables', 'STANDARD_PO_POL_STATEMENTS_V4') }}"
+
+    - name: Merge NREN standard policies v6
+      ansible.builtin.set_fact:
+        standard_nren_policies_v6: "{{ lookup('community.general.merge_variables', 'STANDARD_PO_POL_STATEMENTS_V6') }}"
 
     - name: Set NREN community name
       ansible.builtin.set_fact:
@@ -28,16 +32,62 @@
         nren_po_communities: "{{ nren_po_communities | default([]) + [ {'name': item.0, 'member': item.1} ] }}"
       loop: "{{ nren_community_names | zip(nren_community_values) | list }}"
 
-- name: Select Custom policies if specified by GSO
-  # FIX: Should be per BGP session
+- name: Set BGP V4 session object
+  ansible.builtin.set_fact:
+    bgp_session_v4: "{{ ap.sbp | json_query(query) }}"
+  vars:
+    query: "bgp_session_list[?ip_type == 'ipv4'] | [0]"
+
+- name: Set BGP V6 session object
+  ansible.builtin.set_fact:
+    bgp_session_v6: "{{ ap.sbp | json_query(query) }}"
+  vars:
+    query: "bgp_session_list[?ip_type == 'ipv6'] | [0]"
+
+- name: Select Custom V4 policies if specified by GSO
   when: >-
-    ap.sbp.bgp_session_list[0].has_custom_policies | ansible.builtin.bool
+    bgp_session_v4.has_custom_policies | ansible.builtin.bool
   ansible.builtin.set_fact:
-    nren_policies: "{{ partner_name | upper }}_PO_POL_STATEMENTS"
+    custom_nren_policies_v4: "{{ lookup('community.general.merge_variables', 'CUSTOM_PO_POL_STATEMENTS_V4') }}"
 
-- name: Select Standard policies if custom are not selected
-  # FIX: Should be per BGP session
+- name: Select Custom V6 policies if specified by GSO
   when: >-
-    not ap.sbp.bgp_session_list[0].has_custom_policies | ansible.builtin.bool
+    bgp_session_v6.has_custom_policies | ansible.builtin.bool
   ansible.builtin.set_fact:
-    nren_policies: "{{ standard_nren_policies }}"
+    custom_nren_policies_v6: "{{ lookup('community.general.merge_variables', 'CUSTOM_PO_POL_STATEMENTS_V6') }}"
+
+- name: Combine policies when V4 is custom and V6 is standard
+  when: >
+    bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    not bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [custom_nren_policies_v4, standard_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Combine policies when V4 is custom and V6 is custom
+  when: >
+    bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [custom_nren_policies_v4, custom_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Combine policies when V4 is standard and V6 is custom
+  when: >
+    not bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [standard_nren_policies_v4, custom_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Combine policies when V4 is standard and V6 is standard
+  when: >
+    not bgp_session_v4.has_custom_policies | ansible.builtin.bool
+    and
+    not bgp_session_v6.has_custom_policies | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    nren_policies: "{{ [standard_nren_policies_v4, standard_nren_policies_v6] | community.general.lists_mergeby('name') }}"
+
+- name: Debug final nren_policies
+  ansible.builtin.debug:
+    var: nren_policies
-- 
GitLab


From 28c26631cd76a91e1ae65c325e20279669fc3c7f Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 28 Nov 2024 19:07:39 +0000
Subject: [PATCH 41/46] bgp_config: add passive neighbor option to template

---
 geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2 b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
index 81422c64..dc71e135 100644
--- a/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
+++ b/geant/gap_ansible/roles/bgp_config/templates/bgp_neighbor.j2
@@ -52,6 +52,9 @@
                         {% endfor %}
                       {% endif %}
                     </export>
+                    {% if neighbor.is_passive %}
+                    <passive>true</passive>
+                    {% endif %}
                 </neighbor>
                 {% endfor %}
  
-- 
GitLab


From 9e064950e2d0983701aeb3f0b93d64c2c83814f8 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Tue, 3 Dec 2024 18:25:51 +0000
Subject: [PATCH 42/46] Reworked `l3_core_service` playbook

Aggregate include roles into 2 major blocks:
- SBP-related
- BGP-related
to work with the L3 creation WF.
---
 .../playbooks/l3_core_service.yaml            | 55 ++++++++++++++-----
 1 file changed, 41 insertions(+), 14 deletions(-)

diff --git a/geant/gap_ansible/playbooks/l3_core_service.yaml b/geant/gap_ansible/playbooks/l3_core_service.yaml
index f3f835fa..9b154817 100644
--- a/geant/gap_ansible/playbooks/l3_core_service.yaml
+++ b/geant/gap_ansible/playbooks/l3_core_service.yaml
@@ -29,38 +29,47 @@
       ansible.builtin.include_vars:
         dir: /opt/ansible_inventory/geant_partners/{{ partner_name | upper }}
 
-    - name: Compile Prefix Lists
+
+    - name: Compile SBP-related config
+      when: object == 'sbp'
       block:
-        - name: Include Prefix-list role
+        - name: Include Filter role
           ansible.builtin.include_role:
-            name: prefix_lists
+            name: fw_filters
           loop:
             "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
-    - name: Compile Firewall filters
-      block:
-        - name: Include Filter role
+        - name: Include SBP role
           ansible.builtin.include_role:
-            name: fw_filters
+            name: sbp
           loop:
             "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
-    - name: Compile SBP config
+    # - name: Compile SBP config
+    #   block:
+    #     - name: Include SBP role
+    #       ansible.builtin.include_role:
+    #         name: sbp
+    #       loop:
+    #         "{{ subscription.l3_core_service.ap_list }}"
+    #       loop_control:
+    #         loop_var: ap
+    #
+    - name: Compile BGP-related config
+      when: object == "bgp"
       block:
-        - name: Include SBP role
+        - name: Include Prefix-list role
           ansible.builtin.include_role:
-            name: sbp
+            name: prefix_lists
           loop:
             "{{ subscription.l3_core_service.ap_list }}"
           loop_control:
             loop_var: ap
 
-    - name: Compile BGP policies
-      block:
         - name: Include BGP policies
           ansible.builtin.include_role:
             name: policy_options
@@ -69,8 +78,6 @@
           loop_control:
             loop_var: ap
 
-    - name: Compile BGP sesssions config
-      block:
         - name: Include BGP session
           ansible.builtin.include_role:
             name: bgp_config
@@ -79,6 +86,26 @@
           loop_control:
             loop_var: ap
 
+    # - name: Compile BGP policies
+    #   block:
+    #     - name: Include BGP policies
+    #       ansible.builtin.include_role:
+    #         name: policy_options
+    #       loop:
+    #         "{{ subscription.l3_core_service.ap_list }}"
+    #       loop_control:
+    #         loop_var: ap
+    #
+    # - name: Compile BGP sesssions config
+    #   block:
+    #     - name: Include BGP session
+    #       ansible.builtin.include_role:
+    #         name: bgp_config
+    #       loop:
+    #         "{{ subscription.l3_core_service.ap_list }}"
+    #       loop_control:
+    #         loop_var: ap
+
     - name: Deploy
       # when: verb == deploy
       block:
-- 
GitLab


From 6db203f156cf86d4da3c34978cb3f095d41be1d7 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Tue, 3 Dec 2024 18:38:46 +0000
Subject: [PATCH 43/46] BGP role: add missing deploy tasklist

---
 .../roles/bgp_config/tasks/deploy_bgp.yaml    | 41 +++++++++++++++++++
 .../roles/bgp_config/tasks/main.yml           |  2 +-
 2 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 geant/gap_ansible/roles/bgp_config/tasks/deploy_bgp.yaml

diff --git a/geant/gap_ansible/roles/bgp_config/tasks/deploy_bgp.yaml b/geant/gap_ansible/roles/bgp_config/tasks/deploy_bgp.yaml
new file mode 100644
index 00000000..4353e467
--- /dev/null
+++ b/geant/gap_ansible/roles/bgp_config/tasks/deploy_bgp.yaml
@@ -0,0 +1,41 @@
+---
+- name: Import variables from 'all'
+  ansible.builtin.include_vars:
+    dir: /opt/ansible_inventory/group_vars/all
+
+- name: Set ansible_host to terminal server when router is offline
+  when: ap.sbp.edge_port.node.router_access_via_ts | ansible.builtin.bool
+  ansible.builtin.set_fact:
+    ansible_host: "{{ ap.sbp.edge_port.node.router_site.site_ts_address }}"
+    ansible_port: "{{ ap.sbp.edge_port.node.router_ts_port }}"
+
+- name: Load netconf connection config
+  ansible.builtin.set_fact:
+    ansible_connection: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_connection }}"
+    ansible_network_os: "{{ netconf_access[ap.sbp.edge_port.node.vendor].ansible_network_os }}"
+
+- name: Deploy BGP config on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA]
+  when: dry_run | ansible.builtin.bool
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf') }}"
+    commit: true
+    validate: true
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: true
+
+- name: Deploy BGP config on "{{ inventory_hostname }}" [COMMIT][NOKIA]
+  when: not (dry_run | ansible.builtin.bool)
+  geant.gap_ansible.nokia_netconf_config:
+    format: xml
+    default_operation: merge
+    content: "{{ lookup('ansible.builtin.file', '/var/tmp/ansible_run_{{ opid }}/{{ partner_name }}_bgp.conf') }}"
+    commit: true
+    commit_comment: "{{ commit_comment }}"
+    config_mode: private
+  diff: true
+  register: output
+  check_mode: false
diff --git a/geant/gap_ansible/roles/bgp_config/tasks/main.yml b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
index 5ffcc658..7d0d28d0 100644
--- a/geant/gap_ansible/roles/bgp_config/tasks/main.yml
+++ b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
@@ -12,4 +12,4 @@
 
 - name: Deploy templates if standalone run
   when: is_standalone_run | ansible.builtin.bool
-  ansible.builtin.include_tasks: deploy_po.yaml
+  ansible.builtin.include_tasks: deploy_bgp.yaml
-- 
GitLab


From 9384b53617961f7d797de874114e5259ecb31db3 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Tue, 3 Dec 2024 18:39:09 +0000
Subject: [PATCH 44/46] deploy_config: update mode in copy module

---
 .../roles/deploy_service_config/tasks/assemble_config.yml    | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
index 75a420c6..83c77e19 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/assemble_config.yml
@@ -1,5 +1,4 @@
 ---
-
 # Although I was working on a separate branch, I had
 # to resist the temptation of not modifying the entry
 # playbook in order to introduce the opid_dir variable
@@ -20,24 +19,28 @@
       ansible.builtin.copy:
         src: "{{ vendor }}/header"
         dest: "/var/tmp/ansible_run_{{ opid }}/assembled/00_header"
+        mode: '0644'
 
     # Enumeration prefix is needed to impact the order of assembly
     - name: Copy Nokia SR OS footer for assembly
       ansible.builtin.copy:
         src: "{{ vendor }}/footer"
         dest: "/var/tmp/ansible_run_{{ opid }}/assembled/02_footer"
+        mode: '0644'
 
     # Enumeration prefix is needed to impact the order of assembly
     - name: Assemble body of the config
       ansible.builtin.assemble:
         src: "/var/tmp/ansible_run_{{ opid }}/"
         dest: "/var/tmp/ansible_run_{{ opid }}/assembled/01-body"
+        mode: '0644'
 
     # Use the enumeration prefixes to assemble fragments in the right order
     - name: Merge header, body and footer to get the final config
       ansible.builtin.assemble:
         src: "/var/tmp/ansible_run_{{ opid }}/assembled"
         dest: "/var/tmp/ansible_run_{{ opid }}/assembled/for_deployment"
+        mode: '0644'
 
     - name: Clean up the fragments
       ansible.builtin.file:
-- 
GitLab


From 5140f474ec596df1e750001727d09ad82fcaf508 Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Tue, 3 Dec 2024 18:39:30 +0000
Subject: [PATCH 45/46] push_config: remove empty lines

---
 .../tasks/push_config.yml                     | 32 -------------------
 1 file changed, 32 deletions(-)

diff --git a/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
index a8b9d421..8835da0a 100644
--- a/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
+++ b/geant/gap_ansible/roles/deploy_service_config/tasks/push_config.yml
@@ -37,35 +37,3 @@
     config_mode: private
   diff: true
   check_mode: false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-- 
GitLab


From c626afe434bb5850617b8361f43133f74c1c36dc Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Tue, 3 Dec 2024 18:44:43 +0000
Subject: [PATCH 46/46] BGP role: remove var debug

---
 geant/gap_ansible/roles/bgp_config/tasks/main.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/geant/gap_ansible/roles/bgp_config/tasks/main.yml b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
index 7d0d28d0..13eca9ef 100644
--- a/geant/gap_ansible/roles/bgp_config/tasks/main.yml
+++ b/geant/gap_ansible/roles/bgp_config/tasks/main.yml
@@ -3,10 +3,10 @@
 - name: Load Standard Policy Statements vars
   ansible.builtin.include_tasks: merge_vars.yaml
 
-- name: Debug bgp_session_list
-  ansible.builtin.debug:
-    var: bgp_obj
-
+# - name: Debug bgp_session_list
+#   ansible.builtin.debug:
+#     var: bgp_obj
+#
 - name: Compile templates
   ansible.builtin.include_tasks: compile.yaml
 
-- 
GitLab