From c53f27e22923d9936b6ed3fbaf3c90bab901fbea Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 3 Apr 2025 22:07:43 +0100
Subject: [PATCH 1/2] Add new role for SDP config
---
geant/gap_ansible/roles/sdp/README.md | 29 +++++++++++++++
geant/gap_ansible/roles/sdp/defaults/main.yml | 2 ++
geant/gap_ansible/roles/sdp/handlers/main.yml | 2 ++
geant/gap_ansible/roles/sdp/meta/main.yml | 36 +++++++++++++++++++
.../gap_ansible/roles/sdp/tasks/compile.yaml | 14 ++++++++
.../roles/sdp/tasks/connection_tasks.yaml | 29 +++++++++++++++
geant/gap_ansible/roles/sdp/tasks/main.yml | 34 ++++++++++++++++++
.../roles/sdp/tasks/merge_vars.yaml | 13 +++++++
.../roles/sdp/tasks/push_config.yaml | 36 +++++++++++++++++++
.../roles/sdp/tasks/standard_tasks.yaml | 15 ++++++++
.../routers/nokia/add_pe_to_sdp_mesh/sdp.j2 | 25 +++++++++++++
.../nokia/remove_pe_from_sdp_mesh/sdp.j2 | 14 ++++++++
geant/gap_ansible/roles/sdp/vars/main.yml | 8 +++++
13 files changed, 257 insertions(+)
create mode 100644 geant/gap_ansible/roles/sdp/README.md
create mode 100644 geant/gap_ansible/roles/sdp/defaults/main.yml
create mode 100644 geant/gap_ansible/roles/sdp/handlers/main.yml
create mode 100644 geant/gap_ansible/roles/sdp/meta/main.yml
create mode 100644 geant/gap_ansible/roles/sdp/tasks/compile.yaml
create mode 100644 geant/gap_ansible/roles/sdp/tasks/connection_tasks.yaml
create mode 100644 geant/gap_ansible/roles/sdp/tasks/main.yml
create mode 100644 geant/gap_ansible/roles/sdp/tasks/merge_vars.yaml
create mode 100644 geant/gap_ansible/roles/sdp/tasks/push_config.yaml
create mode 100644 geant/gap_ansible/roles/sdp/tasks/standard_tasks.yaml
create mode 100644 geant/gap_ansible/roles/sdp/templates/routers/nokia/add_pe_to_sdp_mesh/sdp.j2
create mode 100644 geant/gap_ansible/roles/sdp/templates/routers/nokia/remove_pe_from_sdp_mesh/sdp.j2
create mode 100644 geant/gap_ansible/roles/sdp/vars/main.yml
diff --git a/geant/gap_ansible/roles/sdp/README.md b/geant/gap_ansible/roles/sdp/README.md
new file mode 100644
index 00000000..5beb3179
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/README.md
@@ -0,0 +1,29 @@
+# Role Name
+
+Role to manage l2circuits/epipes in multivendor network.
+
+## Requirements
+
+GEANT custom netconf module with Nokia "commit_comment" and "config_mode" features.
+
+## Role Variables
+
+- vars/main.yaml
+- external inventory (group_vars)
+- orchestrator (GSO)
+
+## Dependencies
+
+n/a
+
+## Example Playbook
+
+Role is supposed to be driven by GSO.
+
+## License
+
+MIT
+
+## Author Information
+
+A. Kurbatov. GEANT Orchestration and Automation Team (GOAT).
diff --git a/geant/gap_ansible/roles/sdp/defaults/main.yml b/geant/gap_ansible/roles/sdp/defaults/main.yml
new file mode 100644
index 00000000..c2376894
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/defaults/main.yml
@@ -0,0 +1,2 @@
+---
+# defaults file for sdp
diff --git a/geant/gap_ansible/roles/sdp/handlers/main.yml b/geant/gap_ansible/roles/sdp/handlers/main.yml
new file mode 100644
index 00000000..790d04df
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/handlers/main.yml
@@ -0,0 +1,2 @@
+---
+# handlers file for sdp
diff --git a/geant/gap_ansible/roles/sdp/meta/main.yml b/geant/gap_ansible/roles/sdp/meta/main.yml
new file mode 100644
index 00000000..8e604b5c
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/meta/main.yml
@@ -0,0 +1,36 @@
+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.
diff --git a/geant/gap_ansible/roles/sdp/tasks/compile.yaml b/geant/gap_ansible/roles/sdp/tasks/compile.yaml
new file mode 100644
index 00000000..8e128116
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/tasks/compile.yaml
@@ -0,0 +1,14 @@
+---
+- 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 }}/SDP.conf"
+ ansible.builtin.template:
+ src: "routers/nokia/{{ verb }}/sdp.j2"
+ dest: "/var/tmp/ansible_run_{{ opid }}/SDP.conf"
+ lstrip_blocks: true
+ trim_blocks: true
+ mode: "0755"
+ delegate_to: localhost
diff --git a/geant/gap_ansible/roles/sdp/tasks/connection_tasks.yaml b/geant/gap_ansible/roles/sdp/tasks/connection_tasks.yaml
new file mode 100644
index 00000000..da9016ea
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/tasks/connection_tasks.yaml
@@ -0,0 +1,29 @@
+---
+# Connection tasks for SDP role
+#
+- name: Set ansible_host to terminal server when router is offline
+ when: subscription.router.router_access_via_ts | ansible.builtin.bool and
+ inventory_hostname == subscription.router.router_fqdn
+ ansible.builtin.set_fact:
+ ansible_host: "{{ subscription.router.router_site.site_ts_address }}"
+ ansible_port: "{{ subscription.router.router_ts_port }}"
+
+- name: Load netconf connection config for subscription router
+ when: inventory_hostname == subscription.router.router_fqdn
+ ansible.builtin.set_fact:
+ ansible_connection: "{{ netconf_access[subscription.router.vendor].ansible_connection }}"
+ ansible_network_os: "{{ netconf_access[subscription.router.vendor].ansible_network_os }}"
+
+# - name: Debug hostvars
+# ansible.builtin.debug:
+# var: hostvars[inventory_hostname].vendor
+
+- name: Set ansible_host back to the {{ inventory_hostname }}
+ ansible.builtin.set_fact:
+ ansible_host: "{{ inventory_hostname }}"
+
+- name: Load netconf connection config for mesh routers
+ when: inventory_hostname != subscription.router.router_fqdn
+ ansible.builtin.set_fact:
+ ansible_connection: "{{ netconf_access[hostvars[inventory_hostname].vendor].ansible_connection }}"
+ ansible_network_os: "{{ netconf_access[hostvars[inventory_hostname].vendor].ansible_network_os }}"
diff --git a/geant/gap_ansible/roles/sdp/tasks/main.yml b/geant/gap_ansible/roles/sdp/tasks/main.yml
new file mode 100644
index 00000000..356a4abd
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/tasks/main.yml
@@ -0,0 +1,34 @@
+---
+# main tasks for SDP
+#
+- name: Print the usage
+ when: (verb is not defined) or (verb not in verbs)
+ ansible.builtin.debug:
+ msg:
+ - "'verb' keyword is mandatory. Usage: -e verb=$verb"
+
+- name: Print defined verbs
+ when: (verb is not defined) or (verb not in verbs)
+ ansible.builtin.debug:
+ msg:
+ - "Allowed verb: {{ item }}"
+ loop: "{{ verbs }}"
+
+- name: Stop if arguments are incorrect
+ when: (verb is not defined) or (verb not in verbs)
+ ansible.builtin.meta: end_play
+
+- name: Include standard tasks
+ ansible.builtin.include_tasks: standard_tasks.yaml
+
+- name: Include merge vars tasks
+ ansible.builtin.include_tasks: merge_vars.yaml
+
+- name: Include config compilation tasks
+ ansible.builtin.include_tasks: compile.yaml
+
+- name: Include connection tasks
+ ansible.builtin.include_tasks: connection_tasks.yaml
+
+- name: Include config deployment tasks
+ ansible.builtin.include_tasks: push_config.yaml
diff --git a/geant/gap_ansible/roles/sdp/tasks/merge_vars.yaml b/geant/gap_ansible/roles/sdp/tasks/merge_vars.yaml
new file mode 100644
index 00000000..fe6c16fe
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/tasks/merge_vars.yaml
@@ -0,0 +1,13 @@
+---
+# merge vars for SDP
+- name: Import variables from 'all'
+ ansible.builtin.include_vars:
+ dir: /opt/ansible_inventory/group_vars/all
+
+- name: Import routers variables
+ ansible.builtin.include_vars:
+ dir: /opt/ansible_inventory/group_vars/routers
+
+- name: Select SDP params for l2ciruit-type
+ ansible.builtin.set_fact:
+ sdp_type: "{{ (sdp_types | selectattr('id', 'equalto', '1'))[0] }}"
diff --git a/geant/gap_ansible/roles/sdp/tasks/push_config.yaml b/geant/gap_ansible/roles/sdp/tasks/push_config.yaml
new file mode 100644
index 00000000..8ac1c0e9
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/tasks/push_config.yaml
@@ -0,0 +1,36 @@
+---
+- name: Config deploy [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 }}/SDP.conf') }}"
+ commit: true
+ validate: true
+ config_mode: private
+ diff: true
+ register: output
+ check_mode: true
+
+- name: Fail if config diff is detected
+ when: >
+ output.changed | ansible.builtin.bool
+ and
+ is_verification_workflow | ansible.builtin.bool
+ ansible.builtin.fail:
+ msg: >
+ The config for {{ subscription.description }} has drifted!
+
+- name: Config deploy [REAL][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 }}/SDP.conf') }}"
+ commit: true
+ commit_comment: "{{ commit_comment }}"
+ config_mode: private
+ diff: true
+ register: output
diff --git a/geant/gap_ansible/roles/sdp/tasks/standard_tasks.yaml b/geant/gap_ansible/roles/sdp/tasks/standard_tasks.yaml
new file mode 100644
index 00000000..4772e5bb
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/tasks/standard_tasks.yaml
@@ -0,0 +1,15 @@
+---
+- 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
diff --git a/geant/gap_ansible/roles/sdp/templates/routers/nokia/add_pe_to_sdp_mesh/sdp.j2 b/geant/gap_ansible/roles/sdp/templates/routers/nokia/add_pe_to_sdp_mesh/sdp.j2
new file mode 100644
index 00000000..97dee48b
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/templates/routers/nokia/add_pe_to_sdp_mesh/sdp.j2
@@ -0,0 +1,25 @@
+<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">
+ {% if pe_router_list|length != 0 %}
+ {% for pe_fqdn, pe_addr in pe_router_list.items() %}
+ {% set sdp_id = pe_addr.lo4 | replace(sdp_prefix_regex, '') | replace('.', '') + sdp_type.id %}
+ <sdp alu:operation="replace">
+ <sdp-id>{{ sdp_id }}</sdp-id>
+ <admin-state>enable</admin-state>
+ <description>{{ pe_fqdn }}</description>
+ <delivery-type>mpls</delivery-type>
+ <path-mtu>{{ sdp_type.path_mtu }}</path-mtu>
+ {% if sdp_type.signaling is defined %}
+ <signaling>{{ sdp_type.signaling}}</signaling>
+ {% endif %}
+ <sr-isis>{{ sdp_type.sr_isis | lower }}</sr-isis>
+ <far-end>
+ <ip-address>{{ pe_addr.lo4 }}</ip-address>
+ </far-end>
+ </sdp>
+ {% endfor %}
+ {% endif %}
+ </service>
+ </configure>
+</config>
diff --git a/geant/gap_ansible/roles/sdp/templates/routers/nokia/remove_pe_from_sdp_mesh/sdp.j2 b/geant/gap_ansible/roles/sdp/templates/routers/nokia/remove_pe_from_sdp_mesh/sdp.j2
new file mode 100644
index 00000000..7101bbf9
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/templates/routers/nokia/remove_pe_from_sdp_mesh/sdp.j2
@@ -0,0 +1,14 @@
+<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">
+ {% if pe_router_list|length != 0 %}
+ {% for pe_fqdn, pe_addr in pe_router_list.items() %}
+ {% set sdp_id = pe_addr.lo4 | replace(sdp_prefix_regex, '') | replace('.', '') + sdp_type.id %}
+ <sdp alu:operation="delete">
+ <sdp-id>{{ sdp_id }}</sdp-id>
+ </sdp>
+ {% endfor %}
+ {% endif %}
+ </service>
+ </configure>
+</config>
diff --git a/geant/gap_ansible/roles/sdp/vars/main.yml b/geant/gap_ansible/roles/sdp/vars/main.yml
new file mode 100644
index 00000000..f82ca880
--- /dev/null
+++ b/geant/gap_ansible/roles/sdp/vars/main.yml
@@ -0,0 +1,8 @@
+---
+# vars file for sdp
+dry_run: true
+is_verification_workflow: false
+
+verbs:
+ - add_pe_to_sdp_mesh
+ - remove_pe_from_sdp_mesh
--
GitLab
From 83a832f4b0b0992a8ab279f482deabca118621aa Mon Sep 17 00:00:00 2001
From: Aleksandr Kurbatov <ak@geant.org>
Date: Thu, 3 Apr 2025 22:08:04 +0100
Subject: [PATCH 2/2] Update SDP playbook to use SDP role
---
geant/gap_ansible/playbooks/update_pe_sdp_mesh.yaml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/geant/gap_ansible/playbooks/update_pe_sdp_mesh.yaml b/geant/gap_ansible/playbooks/update_pe_sdp_mesh.yaml
index a895eece..48010d54 100644
--- a/geant/gap_ansible/playbooks/update_pe_sdp_mesh.yaml
+++ b/geant/gap_ansible/playbooks/update_pe_sdp_mesh.yaml
@@ -2,4 +2,5 @@
hosts: all
gather_facts: false
roles:
- - ../roles/promote_p_to_pe
+ # - ../roles/promote_p_to_pe
+ - ../roles/sdp
--
GitLab