diff --git a/geant/gap_ansible/playbooks/edge_port.yaml b/geant/gap_ansible/playbooks/edge_port.yaml new file mode 100644 index 0000000000000000000000000000000000000000..340d41d18592c694dae6dbb24b9b98de48ca1c18 --- /dev/null +++ b/geant/gap_ansible/playbooks/edge_port.yaml @@ -0,0 +1,5 @@ +- name: Create Edge Port + hosts: all + gather_facts: false + roles: + - ../roles/edge_port diff --git a/geant/gap_ansible/roles/edge_port/README.md b/geant/gap_ansible/roles/edge_port/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a090d1c2f83906723ddd9b1473a6ba9d53f643a1 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/README.md @@ -0,0 +1,36 @@ +Role Name +========= + +A role for configuring Edge (access) ports on Nokia SR routers. + +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, S. Spinelli. GEANT Orchestration and Automation Team (GOAT). diff --git a/geant/gap_ansible/roles/edge_port/defaults/main.yml b/geant/gap_ansible/roles/edge_port/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..0d82f9c0eec79ce7970fe472772ad1e5f91983b3 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for edge_port diff --git a/geant/gap_ansible/roles/edge_port/handlers/main.yml b/geant/gap_ansible/roles/edge_port/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..6e01eb9aca73d63936b9a8a72365217b06be1b13 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for edge_port diff --git a/geant/gap_ansible/roles/edge_port/meta/main.yml b/geant/gap_ansible/roles/edge_port/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..4653b30351f55924278063c3c8311bcfd73f8469 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/meta/main.yml @@ -0,0 +1,38 @@ +galaxy_info: + author: A. Kurbatov, S. Spinelli + 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/edge_port/tasks/compile.yaml b/geant/gap_ansible/roles/edge_port/tasks/compile.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6c7fc2c36ec3ad7da2d1fb2bc4fcceb37fe21693 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/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 }}/edge_port_{{ verb }}.conf" + when: verb == "create" + ansible.builtin.template: + src: "{{ router.vendor }}/edge_port_{{ verb }}.j2" + dest: "/var/tmp/ansible_run_{{ opid }}/edge_port_{{ verb }}.conf" + lstrip_blocks: true + trim_blocks: true + mode: '0755' + delegate_to: localhost diff --git a/geant/gap_ansible/roles/edge_port/tasks/connection_tasks.yaml b/geant/gap_ansible/roles/edge_port/tasks/connection_tasks.yaml new file mode 100644 index 0000000000000000000000000000000000000000..56768fbf4d4364c78a9c879dd0b7852133418deb --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/tasks/connection_tasks.yaml @@ -0,0 +1,11 @@ +--- +- name: Set ansible_host to terminal server when router is offline + when: router.router_access_via_ts | ansible.builtin.bool + ansible.builtin.set_fact: + ansible_host: "{{ router.router_site.site_ts_address }}" + ansible_port: "{{ router.router_ts_port }}" + +- 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/edge_port/tasks/deploy.yaml b/geant/gap_ansible/roles/edge_port/tasks/deploy.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f6e3ee638440f299fcaefbfd7fa9c747bb6fc1e5 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/tasks/deploy.yaml @@ -0,0 +1,38 @@ +--- +- name: Perform "{{ verb }}" Edge port 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.template', '{{ router.vendor }}/edge_port_{{ verb }}.j2') }}" + commit: true + validate: true + config_mode: private + diff: true + register: output + check_mode: true + + +- name: Fail if there is any diff + ansible.builtin.fail: + msg: Base config drift detected!!! + when: > + output.changed | ansible.builtin.bool + and + is_verification_workflow | ansible.builtin.bool + + +- name: Perform "{{ verb }}" Edge port on "{{ inventory_hostname }}" [FOR REAL][NOKIA] + when: >- + not (dry_run | ansible.builtin.bool) + geant.gap_ansible.nokia_netconf_config: + format: xml + default_operation: merge + content: "{{ lookup('ansible.builtin.template', '{{ router.vendor }}/edge_port_{{ verb }}.j2') }}" + commit: true + commit_comment: "{{ commit_comment }}" + config_mode: private + diff: true + register: output + check_mode: false diff --git a/geant/gap_ansible/roles/edge_port/tasks/main.yml b/geant/gap_ansible/roles/edge_port/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..4a0d1f4c22127a4714c01d43249dab195ade9f76 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/tasks/main.yml @@ -0,0 +1,15 @@ +--- +# tasks file for edge_port +- name: Include Standard role tasks + ansible.builtin.include_tasks: standard_tasks.yaml + +- name: Include templates compilation + when: verb in verbs + ansible.builtin.include_tasks: compile.yaml + +- 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/edge_port/tasks/standard_tasks.yaml b/geant/gap_ansible/roles/edge_port/tasks/standard_tasks.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f0bc6dea1395562feca38e574974bdccfe9ace16 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/tasks/standard_tasks.yaml @@ -0,0 +1,33 @@ +--- +- 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: Import routers variables + ansible.builtin.include_vars: + dir: /opt/ansible_inventory/group_vars/routers + +- name: Import variables from 'all' + ansible.builtin.include_vars: + dir: /opt/ansible_inventory/group_vars/all + +- 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/edge_port/templates/nokia/edge_port.j2 b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port.j2 new file mode 100644 index 0000000000000000000000000000000000000000..1799ca4efe04f6f5f463aef8af5adfe5eb773261 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port.j2 @@ -0,0 +1,66 @@ +<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"> + +{% for member in ep.edge_port_ae_members %} + <port 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" alu:operation="replace"> + <port-id>{{ member.interface_name }}</port-id> + <admin-state>enable</admin-state> + <description>PHY {{ ep.edge_port_type }} {{ partner_name }} P_{{ ep.edge_port_name }} | {{ member.interface_description }}</description> + <ethernet> + <mode>access</mode> + <mtu>{{ mtu_phy | default(9192) }}</mtu> + {% if edge_port_lldp_enable_map[ep.edge_port_type] is true %} + <lldp> + <dest-mac> + <mac-type>nearest-bridge</mac-type> + <receive>true</receive> + <transmit>true</transmit> + <tx-tlvs> + <port-desc>true</port-desc> + <sys-name>true</sys-name> + <sys-cap>true</sys-cap> + </tx-tlvs> + </dest-mac> + </lldp> + {% endif %} + </ethernet> + </port> +{% endfor %} +{% if edge_port_removed_ae_members is defined %} + {% for member in edge_port_removed_ae_members %} + <port 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" alu:operation="replace"> + <port-id>{{ member.interface_name }}</port-id> + <admin-state>disable</admin-state> + <description>''</description> + </port> + {% endfor %} +{% endif %} + <lag 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" alu:operation="replace"> + <lag-name>{{ ep.edge_port_name | lower }}</lag-name> + <admin-state>enable</admin-state> + {% if ep.edge_port_geant_ga_id is string %} + <description>LAG {{ ep.edge_port_type }} {{ partner_name }} ${{ ep.edge_port_geant_ga_id }} | </description> + {% else %} + <description>LAG {{ ep.edge_port_type }} {{ partner_name }} | </description> + {% endif %} + <mode>access</mode> + {% if ep.edge_port_enable_lacp is true %} + <lacp> + <mode>active</mode> + <administrative-key>{{ (ep.edge_port_name|split("-"))[1] }}</administrative-key> + </lacp> + {% endif %} +{% for member in ep.edge_port_ae_members %} + <port> + <port-id>{{ member.interface_name }}</port-id> + </port> +{% endfor %} + {% if ( ep.edge_port_minimum_links | int) > 1 %} + <port-threshold> + <value>{{ ( ep.edge_port_minimum_links | int) - 1 }}</value> + <action>down</action> + </port-threshold> + {% endif %} + </lag> + </configure> +</config> diff --git a/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_create.j2 b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_create.j2 new file mode 100644 index 0000000000000000000000000000000000000000..296e9fbc28e9f943128d98b361e7748d28eebcc2 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_create.j2 @@ -0,0 +1,65 @@ +<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"> + +{% for member in ep.edge_port_ae_members %} + <port 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" alu:operation="replace"> + <port-id>{{ member.interface_name }}</port-id> + <admin-state>enable</admin-state> + <description>PHY {{ ep.edge_port_type }} {{ partner_name }} P_{{ ep.edge_port_name }} | {{ member.interface_description }}</description> + <ethernet> + <mode>access</mode> + <mtu>{{ mtu_phy | default(9192) }}</mtu> + {% if edge_port_lldp_enable_map[ep.edge_port_type] is true %} + <lldp> + <dest-mac> + <mac-type>nearest-bridge</mac-type> + <receive>true</receive> + <transmit>true</transmit> + <tx-tlvs> + <port-desc>true</port-desc> + <sys-name>true</sys-name> + <sys-cap>true</sys-cap> + </tx-tlvs> + </dest-mac> + </lldp> + {% endif %} + </ethernet> + </port> +{% endfor %} +{% if removed_ae_members is defined and removed_ae_members|length > 0 %} + {% for member in removed_ae_members %} + <port 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" alu:operation="replace"> + <port-id>{{ member.interface_name }}</port-id> + <admin-state>disable</admin-state> + </port> + {% endfor %} +{% endif %} + <lag 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" alu:operation="replace"> + <lag-name>{{ ep.edge_port_name | lower }}</lag-name> + <admin-state>enable</admin-state> + {% if ep.geant_ga_id is string %} + <description>LAG {{ ep.edge_port_type }} {{ partner_name }} ${{ ep.geant_ga_id }} |</description> + {% else %} + <description>LAG {{ ep.edge_port_type }} {{ partner_name }} |</description> + {% endif %} + <mode>access</mode> + {% if ep.enable_lacp is true %} + <lacp> + <mode>active</mode> + <administrative-key>{{ (ep.edge_port_name|split("-"))[1] }}</administrative-key> + </lacp> + {% endif %} +{% for member in ep.edge_port_ae_members %} + <port> + <port-id>{{ member.interface_name }}</port-id> + </port> +{% endfor %} + {% if ( ep.minimum_links | int) > 1 %} + <port-threshold> + <value>{{ ( ep.minimum_links | int) - 1 }}</value> + <action>down</action> + </port-threshold> + {% endif %} + </lag> + </configure> +</config> diff --git a/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_terminate.j2 b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_terminate.j2 new file mode 100644 index 0000000000000000000000000000000000000000..36eed596088a1a5b564b607ef0820da0a3f14bf8 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_terminate.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"> + +{% for member in ep.edge_port_ae_members %} + <port 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" alu:operation="replace"> + <port-id>{{ member.interface_name }}</port-id> + <admin-state>disable</admin-state> + </port> +{% endfor %} + <lag 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" alu:operation="delete"> + <lag-name>{{ ep.edge_port_name | lower }}</lag-name> + </lag> + </configure> +</config> diff --git a/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_update.j2 b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_update.j2 new file mode 120000 index 0000000000000000000000000000000000000000..4f9110ef2350e0a36583633440d625068d7fc5f4 --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/templates/nokia/edge_port_update.j2 @@ -0,0 +1 @@ +edge_port_create.j2 \ No newline at end of file diff --git a/geant/gap_ansible/roles/edge_port/vars/main.yml b/geant/gap_ansible/roles/edge_port/vars/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..362f8c584546901dd367118198e44f2d699e3e0a --- /dev/null +++ b/geant/gap_ansible/roles/edge_port/vars/main.yml @@ -0,0 +1,19 @@ +--- +# vars file for edge_port +dry_run: true +is_verification_workflow: false + +verbs: + - create + - update + - terminate + +ep: "{{ subscription.edge_port }}" +router: "{{ ep.node }}" + +edge_port_lldp_enable_map: + INFRASTRUCTURE: true + CUSTOMER: true + PUBLIC: false + RE_INTERCONNECT: false + PRIVATE: false