diff --git a/geant/gap_ansible/playbooks/deploy_twamp.yaml b/geant/gap_ansible/playbooks/deploy_twamp.yaml new file mode 100644 index 0000000000000000000000000000000000000000..01d004f9e25521be391ab057d73441bd9c3e66aa --- /dev/null +++ b/geant/gap_ansible/playbooks/deploy_twamp.yaml @@ -0,0 +1,5 @@ +- name: Manage iptrunks TWAMP playbook + hosts: all + gather_facts: false + roles: + - ../roles/iptrunk_twamp diff --git a/geant/gap_ansible/roles/iptrunk_twamp/README.md b/geant/gap_ansible/roles/iptrunk_twamp/README.md new file mode 100644 index 0000000000000000000000000000000000000000..9f9c9906de47894c0592efefa32d81a862e55d60 --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/README.md @@ -0,0 +1,38 @@ +Role Name +========= + +A role to configure TWAMP on a newly provisioned trunks. + +Nokia side is always server; +Juniper side is client. + +Requirements +------------ + +GEANT custom netconf module with Nokia "commit_comment" feature. + +Role Variables +-------------- +- vars/main.yaml +- external inventory (group_vars) +- orchestrator + +Dependencies +------------ + +n/a + +Example Playbook +---------------- + +Role is supposed to be driven by GSO. + +License +------- + +MIT + +Author Information +------------------ + +A. Kurbatov, GEANT Orchestration and Automation Team. diff --git a/geant/gap_ansible/roles/iptrunk_twamp/defaults/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..bff214c5e92c17c13bb7fa012dfa06d336e714f2 --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for iptrunk_twamp diff --git a/geant/gap_ansible/roles/iptrunk_twamp/handlers/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..88a40b5bcb4960b23c8f5939a13763cd7c50f44a --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for iptrunk_twamp diff --git a/geant/gap_ansible/roles/iptrunk_twamp/meta/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..176f5ec62b59dfca599c98bc47a079810573e372 --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/meta/main.yml @@ -0,0 +1,56 @@ +galaxy_info: + author: Aleksandr Kurbatov, GEANT Orchestration and Automation Team + description: Deploy TWAMP probe on a IPtrunk + 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: + + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + # platforms: + # - name: Fedora + # versions: + # - all + # - 25 + # - name: SomePlatform + # versions: + # - all + # - 1.0 + # - 7 + # - 99.99 + + 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/iptrunk_twamp/tasks/compile_object.yaml b/geant/gap_ansible/roles/iptrunk_twamp/tasks/compile_object.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f248c392804407ce71365a6186d6eae365e7d372 --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/tasks/compile_object.yaml @@ -0,0 +1,29 @@ +--- +- name: Set ansible_host to terminal server when router is offline + ansible.builtin.set_fact: + ansible_host: localhost + when: + ( local_side.iptrunk_side_node.router_access_via_ts | ansible.builtin.bool ) is true + +- name: Create a folder for all the templates + 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 }}/{{ config_object }}.conf" + ansible.builtin.template: + src: "{{ local_side.iptrunk_side_node.vendor }}/{{ config_object }}.j2" + dest: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf" + lstrip_blocks: true + trim_blocks: true + mode: '0755' + delegate_to: localhost + +- name: Set ansible_host to terminal server when router is offline + ansible.builtin.set_fact: + ansible_host: "{{ local_side.iptrunk_side_node.router_site.site_ts_address }}" + ansible_port: "{{ local_side.iptrunk_side_node.router_ts_port }}" + when: + ( local_side.iptrunk_side_node.router_access_via_ts | ansible.builtin.bool ) is true diff --git a/geant/gap_ansible/roles/iptrunk_twamp/tasks/deploy_object.yaml b/geant/gap_ansible/roles/iptrunk_twamp/tasks/deploy_object.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f319ad2cdd73d09491997777307bdfe4fd84dace --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/tasks/deploy_object.yaml @@ -0,0 +1,49 @@ +--- +- name: Deploy "{{ config_object }}" on "{{ inventory_hostname }}" [CHECK ONLY][JUNIPER] + junipernetworks.junos.junos_config: + update: 'replace' + src: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf" + src_format: text + check_commit: true + diff: true + when: > + local_side.iptrunk_side_node.vendor == "juniper" and + dry_run | ansible.builtin.bool + +- name: Deploy "{{ config_object }}" on "{{ inventory_hostname }}" [AND COMMIT][JUNIPER] + junipernetworks.junos.junos_config: + update: 'replace' + src: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf" + src_format: text + comment: "{{ commit_comment }}" + diff: true + when: > + local_side.iptrunk_side_node.vendor == "juniper" and + not (dry_run | ansible.builtin.bool) + +- name: Deploy "{{ config_object }}" on "{{ inventory_hostname }}" [CHECK ONLY][NOKIA] + # ansible.netcommon.netconf_config: + geant.gap_ansible.nokia_netconf_config: + format: xml + default_operation: merge + content: "{{ lookup('ansible.builtin.template', '{{ local_side.iptrunk_side_node.vendor }}/{{ config_object }}.j2') }}" + commit: true + diff: true + check_mode: true + when: > + ( dry_run | ansible.builtin.bool ) is true and + local_side.iptrunk_side_node.vendor == "nokia" + +- name: Deploy "{{ config_object }}"on "{{ inventory_hostname }}" [AND COMMIT][NOKIA] + # ansible.netcommon.netconf_config: + geant.gap_ansible.nokia_netconf_config: + format: xml + default_operation: merge + content: "{{ lookup('ansible.builtin.template', '{{ local_side.iptrunk_side_node.vendor }}/{{ config_object }}.j2') }}" + commit: true + commit_comment: "{{ commit_comment }}" + diff: true + check_mode: false + when: > + ( dry_run | ansible.builtin.bool ) is false and + local_side.iptrunk_side_node.vendor == "nokia" diff --git a/geant/gap_ansible/roles/iptrunk_twamp/tasks/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..e1434ed912bf16c109e29f5a7ae0b9f4ece3b252 --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/tasks/main.yml @@ -0,0 +1,72 @@ +--- +# tasks file for iptrunk_twamp + +- name: Import routers variables + ansible.builtin.include_vars: + dir: /opt/ansible_inventory/group_vars/routers + +- name: Set an ID for this run + ansible.builtin.set_fact: + opid: "{{ lookup('community.general.random_string', length=18, special=false) }}" + config_is_different: "False" + +- name: Load local info + ansible.builtin.set_fact: + local_side: "{{ subscription | community.general.json_query(query) }}" + vars: + query: "iptrunk.iptrunk_sides[?iptrunk_side_node.router_fqdn == '{{ inventory_hostname }}'] | [0]" + +- name: Load netconf connection config + ansible.builtin.set_fact: + ansible_connection: "{{ netconf_access[local_side.iptrunk_side_node.vendor].ansible_connection }}" + ansible_network_os: "{{ netconf_access[local_side.iptrunk_side_node.vendor].ansible_network_os }}" + +- name: Load remote info + ansible.builtin.set_fact: + remote_side: "{{ subscription | community.general.json_query(query) }}" + vars: + query: "iptrunk.iptrunk_sides[?iptrunk_side_node.router_fqdn != '{{ inventory_hostname }}'] | [0]" + +- name: Set ansible_host to terminal server when router is offline + ansible.builtin.set_fact: + ansible_host: "{{ local_side.iptrunk_side_node.router_site.site_ts_address }}" + ansible_port: "{{ local_side.iptrunk_side_node.router_ts_port }}" + when: + ( local_side.iptrunk_side_node.router_access_via_ts | ansible.builtin.bool ) is true + +- name: Print the ID + ansible.builtin.debug: + msg: "{{ opid }}" + +- name: Set short router names for local and remote sides + ansible.builtin.set_fact: + local_side_short_name: '{{ local_side.iptrunk_side_node.router_fqdn | replace(".geant.net", "") }}' + remote_side_short_name: '{{ remote_side.iptrunk_side_node.router_fqdn | replace(".geant.net", "") }}' + +- name: Set Local and Remote side IPv4 addresses nodeA + ansible.builtin.set_fact: + local_side_address: "{{ trunks[0].config.nodeA.ipv4_address }}" + remote_side_address: "{{ trunks[0].config.nodeB.ipv4_address }}" + when: local_side.iptrunk_side_node.router_fqdn == trunks[0].config.nodeA.name + +- name: Set Local and Remote side IPv4 addresses nodeB + ansible.builtin.set_fact: + local_side_address: "{{ trunks[0].config.nodeB.ipv4_address }}" + remote_side_address: "{{ trunks[0].config.nodeA.ipv4_address }}" + when: local_side.iptrunk_side_node.router_fqdn == trunks[0].config.nodeB.name + +- name: Set the "config_object" to "twamp_client" when trunks side is Juniper + ansible.builtin.set_fact: + config_object: "twamp_client" + when: local_side.iptrunk_side_node.vendor == "juniper" + +- name: Set the "config_object" to "twamp_server" when trunk side is Nokia + ansible.builtin.set_fact: + config_object: "twamp_server" + when: local_side.iptrunk_side_node.vendor == "nokia" + +- name: Include compiling the template + ansible.builtin.include_tasks: compile_object.yaml + +- name: Include the deployment tasks if specified + ansible.builtin.include_tasks: deploy_object.yaml diff --git a/geant/gap_ansible/roles/iptrunk_twamp/templates/juniper/twamp_client.j2 b/geant/gap_ansible/roles/iptrunk_twamp/templates/juniper/twamp_client.j2 new file mode 100644 index 0000000000000000000000000000000000000000..32363a7348676f853920211b26ee073c6fdb9176 --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/templates/juniper/twamp_client.j2 @@ -0,0 +1,21 @@ +services { + rpm { + twamp { + client { +replace: control-connection {{ remote_side_short_name }} { + destination port {{ juniper_twamp_client.destination_port }}; + history-size {{ juniper_twamp_client.history_size }}; + target-address {{ remote_side_address }}; + test-count {{ juniper_twamp_client.test_count }}; + test-session "{{ local_side_short_name }}--{{ remote_side_short_name }}" { + target-address {{ remote_side_short_name }}; + data-fill-with-zeros; + data-size {{ juniper_twamp_client.data_size }}; + probe-count {{ juniper_twamp_client.probe_count }}; + probe-interval {{ juniper_twamp_client.proble_interval }}; + } + } + } + } + } +} diff --git a/geant/gap_ansible/roles/iptrunk_twamp/templates/nokia/twamp_server.j2 b/geant/gap_ansible/roles/iptrunk_twamp/templates/nokia/twamp_server.j2 new file mode 100644 index 0000000000000000000000000000000000000000..a0029b80476ce219e3f3357611975a9dae5d912c --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/templates/nokia/twamp_server.j2 @@ -0,0 +1,15 @@ +<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"> + <twamp 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"> + <server> + <admin-state>enable</admin-state> + <prefix alu:operation="replace"> + <ip-prefix>{{ remote_side_address }}/32</ip-prefix> + <description>{{ remote_side_short_name }}</description> + <max-connections>{{ nokia_twamp_server_max_conn }}</max-connections> + <max-sessions>{{ nokia_twamp_server_max_sess }}</max-sessions> + </prefix> + </server> + </twamp> + </configure> +</config> diff --git a/geant/gap_ansible/roles/iptrunk_twamp/vars/main.yml b/geant/gap_ansible/roles/iptrunk_twamp/vars/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..161f1b440e35f626feb0671a2ca83f82882bc22b --- /dev/null +++ b/geant/gap_ansible/roles/iptrunk_twamp/vars/main.yml @@ -0,0 +1,38 @@ +--- +# vars file for iptrunk_twamp +# +# + +dry_run: "True" + +nokia_twamp_server: + max_conn: 1 + max_sess: 1 + +juniper_twamp_client: + destination_port: 862 + history_size: 20 + test_count: 0 + test_interval: 30 + data_size: 200 + probe_count: 500 + probe_interval: 1 + +side_a_ipv4_address: "{{ subscription.iptrunk.iptrunk_ipv4_network | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('address') }}" +side_b_ipv4_address: "{{ subscription.iptrunk.iptrunk_ipv4_network | ansible.utils.ipaddr('net') | ansible.utils.ipaddr('1') | ansible.utils.ipaddr('address') }}" + +trunks: + - id: "{{ subscription.iptrunk.geant_s_sid }}" + config: + common: + description: "{{ subscription.iptrunk.iptrunk_description }}" + nodeA: + name: "{{ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_fqdn }}" + router_access_via_ts: "{{ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_access_via_ts }}" + loopback: "{{ subscription.iptrunk.iptrunk_sides[0].iptrunk_side_node.router_lo_ipv4_address }}" + ipv4_address: "{{ side_a_ipv4_address }}" + nodeB: + name: "{{ subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_fqdn }}" + router_access_via_ts: "{{ subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_access_via_ts }}" + loopback: "{{ subscription.iptrunk.iptrunk_sides[1].iptrunk_side_node.router_lo_ipv4_address }}" + ipv4_address: "{{ side_b_ipv4_address }}"