diff --git a/README.md b/README.md index e35945007c6df888e34f08d969d705e9614babb7..e64ed94b3a99c8fef4b8d7da3b5b81c7a0c6b77c 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,4 @@ # geant-gap-ansible - - -## Getting started - -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files - -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: - -``` -cd existing_repo -git remote add origin https://gitlab.geant.org/goat/geant-gap-ansible.git -git branch -M main -git push -uf origin main -``` - -## Integrate with your tools - -- [ ] [Set up project integrations](https://gitlab.geant.org/goat/geant-gap-ansible/-/settings/integrations) - -## Collaborate with your team - -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. - -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) - -*** - -# Editing this README - -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. - -## Suggestions for a good README -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. - -## Name -Choose a self-explaining name for your project. - -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. - -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. - -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. - -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. - -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. - -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. - -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. - -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. - -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. - -## License -For open source projects, say how it is licensed. - -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +Here we store ansible roles and playbooks to be used with Forkflow Orchestrator. +The intention is to transform this in a proper Ansible Collection. diff --git a/action_plugins/__pycache__/merge_vars.cpython-310.pyc b/action_plugins/__pycache__/merge_vars.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5e795ccd63ec6a121f53f870540ea643c75e468d Binary files /dev/null and b/action_plugins/__pycache__/merge_vars.cpython-310.pyc differ diff --git a/action_plugins/__pycache__/merge_vars.cpython-39.pyc b/action_plugins/__pycache__/merge_vars.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef1cd79e46474c89cc212bbf3991a0ec79bf7b92 Binary files /dev/null and b/action_plugins/__pycache__/merge_vars.cpython-39.pyc differ diff --git a/action_plugins/merge_vars.py b/action_plugins/merge_vars.py new file mode 100644 index 0000000000000000000000000000000000000000..a215e7b072a3b434478a5c72cd56e96bbd3ef42e --- /dev/null +++ b/action_plugins/merge_vars.py @@ -0,0 +1 @@ +from ansible_merge_vars import ActionModule diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000000000000000000000000000000000000..b0f9a1dc314fd9300fa60064e751688fefc9eed3 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,2 @@ +[defaults] +nocolor=true diff --git a/base_config.yaml b/base_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d7062f7d3d75fe44f2efc1fd043d2aba8877a9da --- /dev/null +++ b/base_config.yaml @@ -0,0 +1,13 @@ +- name: Manage base config playbook + hosts: all + gather_facts: yes + remote_user: admin + vars_files: + - /opt/ansible_inventory/group_vars/junos/device_access.yaml + roles: + - Juniper.junos + - roles/base_config + tasks: + - name: Import routers variables + ansible.builtin.include_vars: + dir: /opt/ansible_inventory/group_vars/routers diff --git a/get_facts.yaml b/get_facts.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e8593f32c766bedde671362fc0bf9bbea4af8b4f --- /dev/null +++ b/get_facts.yaml @@ -0,0 +1,14 @@ +--- +- hosts: all + user: admin + vars_files: + - /opt/ansible_inventory/group_vars/junos/device_access.yaml + tasks: + - name: collect default set of facts + junipernetworks.junos.junos_facts: + gather_subset: hardware + register: router_facts + - name: show facts + debug: + msg: "{{ router_facts }}" + diff --git a/iptrunks.yaml b/iptrunks.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ac72485be715a234f7e31baa4f9d0a0280517743 --- /dev/null +++ b/iptrunks.yaml @@ -0,0 +1,5 @@ +- name: Manage base config playbook + hosts: staging_routers + roles: + - Juniper.junos + - roles/iptrunks diff --git a/roles/base_config/README.md b/roles/base_config/README.md new file mode 100644 index 0000000000000000000000000000000000000000..225dd44b9fc5b3abff7e9c68ff9e91d505cdd5f0 --- /dev/null +++ b/roles/base_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/roles/base_config/defaults/main.yml b/roles/base_config/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..86405e60cc0d8ac85698bf4338e83378f8f77e83 --- /dev/null +++ b/roles/base_config/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for base_config diff --git a/roles/base_config/handlers/main.yml b/roles/base_config/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..f79f5e37410296ab7108fd2de0600470bd13bf27 --- /dev/null +++ b/roles/base_config/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for base_config diff --git a/roles/base_config/meta/main.yml b/roles/base_config/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..c572acc9f8b466bea50f2799b0ca1956418b862c --- /dev/null +++ b/roles/base_config/meta/main.yml @@ -0,0 +1,52 @@ +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: + + # + # 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: [] + # 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/roles/base_config/tasks/compile_base_config.yaml b/roles/base_config/tasks/compile_base_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..01c439e33b8cde7ba4051b36aefee448c74c9ade --- /dev/null +++ b/roles/base_config/tasks/compile_base_config.yaml @@ -0,0 +1,21 @@ +- name: Create a folder for all the things + ansible.builtin.file: + path: "/var/tmp/ansible_run_{{opid}}" + state: directory + mode: '0755' + +- name: Merge the variables + include_tasks: merge_variables.yaml + +- name: Print the template in "/var/tmp/ansible_run_{{opid}}/{{mytemplates.template_name}}.conf" + template: + src: "{{ mytemplates.template_path }}" + dest: "/var/tmp/ansible_run_{{opid}}/{{mytemplates.template_name}}.conf" + lstrip_blocks: yes + trim_blocks: yes + delegate_to: localhost + +- name: Send message to syslog + syslogger: + msg: "[[{{opid}}]] {{mytemplates.template_name}} compiled" + log_pid: true diff --git a/roles/base_config/tasks/deploy_base_config.yaml b/roles/base_config/tasks/deploy_base_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cc51ee96c37b6fe04f207950b19d4749c25b6bc4 --- /dev/null +++ b/roles/base_config/tasks/deploy_base_config.yaml @@ -0,0 +1,45 @@ +- name: Send end of operation in syslog + syslogger: + msg: "[[{{opid}}]] deploy base config on {{inventory_hostname}} dry run" + log_pid: true + +- name: Deploy base_config on "{{inventory_hostname}}" [CHECK ONLY] + juniper_junos_config: + load: 'replace' + src: "/var/tmp/ansible_run_{{opid}}/{{mytemplates.template_name}}.conf" + format: text + config_mode: "private" + check: yes + commit: no + register: response + when: verb == "deploy" and dryrun == "True" + +#- name: Show diff for dry run +# debug: +# msg: "{{ response }}" +# when: verb == "deploy" and dryrun == "True" + +- name: Send end of operation in syslog + syslogger: + msg: "[[{{opid}}]] deploy base config on {{inventory_hostname}} for real " + log_pid: true + +- name: Deploy base_config on "{{inventory_hostname}}" [AND COMMIT] + juniper_junos_config: + load: 'replace' + src: "/var/tmp/ansible_run_{{opid}}/{{mytemplates.template_name}}.conf" + format: text + config_mode: "private" + comment: "{{ commit_comment }}" + register: response + when: verb == "deploy" and dryrun == "False" + +- name: Show diff + debug: + msg: "{{ response }}" + when: verb == "deploy" and dryrun == "False" + +- name: Send end of operation in syslog + syslogger: + msg: "[[{{opid}}]] Ending operations " + log_pid: true diff --git a/roles/base_config/tasks/main.yml b/roles/base_config/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..2a9471d4f64fd8fd0f0d21c1c9089f811cc716bb --- /dev/null +++ b/roles/base_config/tasks/main.yml @@ -0,0 +1,33 @@ +--- +# tasks file for base_config +- name: Print the usage + debug: + msg: + - "Allowed verbs: 'compile' and 'deploy'. Use: -e 'verb=$verb'." + when: (verb is not defined) or (verb not in verbs) + +- meta: end_play + when: (verb is not defined) or (verb not in verbs) + +- name: Gather_facts + junipernetworks.junos.junos_facts: + gather_subset: all + +- name: Import routers variables + ansible.builtin.include_vars: + dir: /opt/ansible_inventory/group_vars/routers + +- set_fact: + opid: "{{ lookup('community.general.random_string', length=18, special=false) }}" + config_is_different: "False" + +- name: Print the ID + debug: + msg: "{{opid}}" + +- include: compile_base_config.yaml + when: verb in verbs + +- include: deploy_base_config.yaml + when: verb == "deploy" + diff --git a/roles/base_config/tasks/merge_variables.yaml b/roles/base_config/tasks/merge_variables.yaml new file mode 100644 index 0000000000000000000000000000000000000000..235072f5ab9eafaf7e6a44f866c1747388f4a1c3 --- /dev/null +++ b/roles/base_config/tasks/merge_variables.yaml @@ -0,0 +1,25 @@ +## This playbook is used to merge variables that are splitted in group and host vars. +# Currently, this is valid for: +# system_login_users +# system_login_classes +# snmp_communities +# +# This playbook should be included in any other playbook that makes use of these variables. +# +- name: Merge system login user vars + merge_vars: + suffix_to_merge: users__to_merge + merged_var_name: system_login_users + expected_type: 'list' + +- name: Merge system login classes vars + merge_vars: + suffix_to_merge: classes__to_merge + merged_var_name: system_login_classes + expected_type: 'list' + +- name: Merge snmp communities vars + merge_vars: + suffix_to_merge: snmp_communities__to_merge + merged_var_name: snmp_communities + expected_type: 'list' diff --git a/roles/base_config/templates/routers/base_config.j2 b/roles/base_config/templates/routers/base_config.j2 new file mode 100644 index 0000000000000000000000000000000000000000..c9326bdea0d5eb935ca9c4c2cb0ae6bc8c4d3b86 --- /dev/null +++ b/roles/base_config/templates/routers/base_config.j2 @@ -0,0 +1,28 @@ +{% include 'class_of_service.j2' %} + +{% include 'chassis.j2' %} +{# #} +{% include 'forwarding_options.j2' %} +{# #} +{% include 'firewall.j2' %} +{# #} +{% include 'groups.j2' %} +{# #} +{% include 'interfaces.j2' %} +{# #} +{% include 'policy_options.j2' %} +{# #} +{% include 'policy_statements.j2' %} +{# #} +{% include 'routing_options.j2' %} +{# #} +{% include 'services.j2' %} +{# #} +{% include 'snmp.j2' %} +{# #} +{% include 'protocols/protocols_global.j2' %} + +{% include 'system/system_global.j2' %} + + +{% include 'routing_instances.j2' %} diff --git a/roles/base_config/templates/routers/chassis.j2 b/roles/base_config/templates/routers/chassis.j2 new file mode 100644 index 0000000000000000000000000000000000000000..d68f52fbae3dac924ca28f08ab5deb71bde47a08 --- /dev/null +++ b/roles/base_config/templates/routers/chassis.j2 @@ -0,0 +1,97 @@ +replace: chassis { + dump-on-panic; + {% if ansible_net_has_2RE == true %} + redundancy { + routing-engine 0 master; + routing-engine 1 backup; + failover { + on-loss-of-keepalives; + on-disk-failure; + } + {% if chassis_graceful_switchover_inactive is sameas true%} + inactive: graceful-switchover; + {% else %} + graceful-switchover; + {% endif %} + } + {% endif %} + routing-engine { + disk { + smart-check; + } + } + aggregated-devices { + ethernet { + device-count {{ chassis_aggredated_ethernet_count }}; + } + } + {% if ansible_net_has_2RE == true %} + {% if chassis_fabric_rm is defined %} + fabric { + redundancy-mode { + {{ chassis_fabric_rm }}; + } + } + {% endif %} + {% endif %} + {% if chassis_fpcs is defined %} + {% for fpc in chassis_fpcs %} + fpc {{ fpc.fpc_id }} { + {% if ( fpc.power is defined ) and ( fpc.power == "off" ) %} + power off; + {% else %} + {% for pic in fpc.pics %} + pic {{ pic.pic_id }} { + {% if pic.pic_mode is defined %} + pic-mode {{ pic.pic_mode }}; + {% endif %} + {% if pic.tunnel_services is defined %} + tunnel-services { + bandwidth {{ pic.tunnel_services }}; + } + {% endif %} + {% if pic.inline_services is defined %} + inline-services { + bandwidth {{ pic.inline_services }}; + } + {% endif %} + {% if pic.ports is defined %} + {% for port in pic.ports %} + port {{ port.id }} { + speed {{ port.speed }}; + } + {% endfor %} + {% endif %} + } + {% endfor %} + sampling-instance ipfx; + inline-services flex-flow-sizing ; + {% endif %} + } + {% endfor %} + {% else %} + {% for net_module in ansible_net_modules %} + {% if 'FPC' in net_module.name %} + {% set fpc_name_as_list = net_module.name.split(" ") %} + fpc {{ fpc_name_as_list[1] }} { + {% if fpc_name_as_list[1] is sameas "0" %} + pic 0 { + tunnel-services { + bandwidth 10g; + } + inline-services { + bandwidth 10g; + } + } + {% endif %} + sampling-instance ipfx; + inline-services flex-flow-sizing ; + } + {% endif %} + {% endfor %} + {% endif %} + {% if chassis_enhanced_ip is sameas true %} + network-services enhanced-ip; + {% endif %} +} + diff --git a/roles/base_config/templates/routers/class_of_service.j2 b/roles/base_config/templates/routers/class_of_service.j2 new file mode 100644 index 0000000000000000000000000000000000000000..5d656119e58064f57d9e9ff6f2eebaa0a303afa6 --- /dev/null +++ b/roles/base_config/templates/routers/class_of_service.j2 @@ -0,0 +1,136 @@ +replace: class-of-service { + {% if cos_classifiers is defined %} + classifiers { + {% for classifier in cos_classifiers %} + {{ classifier.type }} {{ classifier.name }} { + import {{ classifier.import }}; + {% for forwarding_class in classifier.forwarding_classes %} + forwarding-class {{ forwarding_class.name}} { + loss-priority {{ forwarding_class.loss_priority }} code-points [{% for code_point in forwarding_class.code_points %} {{ code_point }} {% endfor %} ]; + } + {% endfor %} + } + {% endfor %} + } + {% else %} + {{ raise('ERROR: YOU HAVE NO CLASSIFIERS DEFINED')}} + {%endif %} + {% if cos_drop_profiles is defined %} + drop-profiles { + {% for drop_profile in cos_drop_profiles %} + {{ drop_profile.name }} { + interpolate { + fill-level [{% for fill_level in drop_profile.fill_levels %} {{ fill_level }} {% endfor %} ]; + drop-probability [{% for drop_probability in drop_profile.drop_probabilities %} {{ drop_probability }} {% endfor %} ]; + } + } + {% endfor %} + } + {% else %} + {{ raise('ERROR: YOU HAVE NO DROP-PROFILES DEFINED')}} + {%endif %} + {% if cos_forwarding_classes is defined %} + forwarding-classes { + + {% for fc in cos_forwarding_classes %} + class {{ fc.name }} queue-num {{ fc.queue_num }} priority {{ fc.priority }}; + {% endfor %} + } + {% endif %} + + {% if cos_interfaces is defined %} + interfaces { + {% for interface in cos_interfaces %} + {{ interface.regex }} { + {% if interface.scheduler_map is defined %} + scheduler-map {{ interface.scheduler_map}}; + {% endif %} + unit * { + classifiers { + {% for classifier in interface.classifiers %} + {{ classifier.type }} {{ classifier.name }} ; + {% endfor %} + } + {% if interface.rewrite_rules is defined %} + rewrite-rules { + {% for rr in interface.rewrite_rules %} + {{ rr.type }} {{ rr.name }} protocol {{ rr.protocol}}; + {% endfor %} + } + {% endif %} + } + } + {% endfor %} + } + {% else %} + {{ raise('ERROR: YOU HAVE NO INTERFACES DEFINED')}} + {% endif %} + {% if cos_rewrite_rules is defined %} + {% for rewrite_rule in cos_rewrite_rules %} + rewrite-rules { + {{ rewrite_rule.type }} {{ rewrite_rule.name }} { + import {{ rewrite_rule.import }} + {% if rewrite_rule.forwarding_classes is defined %} + {% for fc in rewrite_rule.forwarding_classes %} + forwarding-class {{ fc.name }} { + {% if fc.loss_priorities is defined %} + {% for lp in fc.loss_priorities %} + loss-priority {{ lp.type }} code-point {{ lp.code_point }}; + {% endfor %} + {% endif %} + } + {% endfor %} + {% endif %} + } + } + {% endfor %} + {% endif %} + {% if cos_scheduler_maps is defined %} + scheduler-maps { + {% for scheduler_map in cos_scheduler_maps %} + {{ scheduler_map.name }} { + {% for mapping in scheduler_map.mappings %} + forwarding-class {{ mapping.class }} scheduler {{ mapping.scheduler }} ; + {% endfor %} + } + {% endfor %} + } + {% else %} + {{ raise('ERROR: YOU HAVE NO SCHEDULER-MAP DEFINED')}} + {% endif %} + {% if cos_schedulers is defined %} + schedulers { + {% for scheduler in cos_schedulers %} + {{ scheduler.name }} { + {% if scheduler.transmit_rate.unit == "remainder" %} + transmit-rate { + remainder; + } + {% elif scheduler.transmit_rate.unit == "percent" %} + transmit-rate percent {{ scheduler.transmit_rate.value }}; + {% elif scheduler.transmit_rate.unit == "rate" %} + transmit-rate {{ scheduler.transmit_rate.value }}; + {% else %} + {{ raise('ERROR: SCHEDULER TRANSMIT-RATE scheduler.transmit_rate.value NOT VALID')}} + {% endif %} + {% if ((scheduler.buffer_size.unit == "remainder") or (scheduler.buffer_size.unit == "shared")) %} + buffer-size { + {{ scheduler.buffer_size.unit }}; + } + {% elif ((scheduler.buffer_size.unit == "percent") or (scheduler.buffer_size.unit == "temporal")) %} + buffer-size {{ scheduler.buffer_size.unit }} {{ scheduler.buffer_size.value }}; + {% else %} + {{ raise('ERROR: SCHEDULER TRANSMIT-RATE scheduler.buffer_size.value NOT VALID')}} + {% endif %} + priority {{ scheduler.priority }}; + {% if scheduler.drop_profile_map is defined %} + drop-profile-map loss-priority {{ scheduler.drop_profile_map.loss_priority }} protocol {{ scheduler.drop_profile_map.protocol }} drop-profile {{ scheduler.drop_profile_map.drop_profile }}; + {% endif %} + } + {% endfor %} + } + {% else %} + {{ raise('ERROR: YOU HAVE NO SCHEDULER DEFINED')}} + {% endif %} +} + diff --git a/roles/base_config/templates/routers/firewall.j2 b/roles/base_config/templates/routers/firewall.j2 new file mode 100644 index 0000000000000000000000000000000000000000..970686436ca5748fcf9b11024da947740fc40b99 --- /dev/null +++ b/roles/base_config/templates/routers/firewall.j2 @@ -0,0 +1,77 @@ + +{##} +{#We should validate, but raise does not work :-( #} +{% set supported_from = [ 'destination-address','destination-port','icmp-type','port','prefix-list','protocol','source-address','source-prefix-list','tcp-established' ] %} +{% set supported_then = [ 'accept','policer','discard','reject' ] %} +{##} + +firewall { +{% for family, filters in firewall.items() %} +{% if family != "policer" %} + family {{ family }} { + {% for filter, filter_data in filters.items() %} +replace: filter {{ filter }} { + {% if filter_data.options is defined %} + {{ filter_data.options }}; + {% endif %} + {% for term in filter_data.terms %} + term {{ term.name }} { + {% if term.from is defined %} + from { + {% for from, from_data in term.from.items() %} + {# Stuff that goes in line: like ports, protocols and similar#} + {% if "tcp-established" in from %} + tcp-established; + {% elif ("port" in from) or ("protocol" in from) or ("icmp-type" in from) or ("next-header" in from) or ("hop-limit" in from)%} + {% if (from_data is iterable) and (from_data is not string) %} + {{ from }} [ {% for from_data_element in from_data %}{{ from_data_element }} {% endfor %} ]; + {% else %} + {{ from }} {{ from_data }}; + {% endif %} + {# Stuff that goes in a list: like addresses, prefix lists etc... #} + {% else %} + {{ from }} { + {% for from_data_element in from_data %} + {{ from_data_element }}; + {% endfor %} + } + {% endif %} + {% endfor %} + } + {% endif %} + then { + {% if (term.then is iterable) and (term.then is not string) %} + {% for then_action in term.then %} + {% if then_action is not string %} + {% for action, destination in then_action.items() %} + {{ action }} {{ destination}}; + {% endfor %} + {% else %} + {{ then_action }}; + {% endif %} + {% endfor %} + {% else %} + {{ term.then }}; + {% endif %} + } + } + {% endfor %} + } + {% endfor %} + } +{% else %} + {% for filter, filter_data in filters.items() %} +replace: policer {{ filter }} { + {% if filter_data.options is defined %} + {{ filter_data.options }}; + {% endif %} + if-exceeding { + bandwidth-limit {{ filter_data.bandwidth_limit }}; + burst-size-limit {{ filter_data.burst_size_limit }}; + } + then discard; + } + {% endfor %} +{% endif %} +{% endfor %} +} diff --git a/roles/base_config/templates/routers/forwarding_options.j2 b/roles/base_config/templates/routers/forwarding_options.j2 new file mode 100644 index 0000000000000000000000000000000000000000..61533386b92fc19c03d2f167ff0a4f3adfa7314b --- /dev/null +++ b/roles/base_config/templates/routers/forwarding_options.j2 @@ -0,0 +1,37 @@ +replace: forwarding-options { + sampling { + instance { + ipfx { + input { + rate 300; + } + {% for family in forwarding_options_families %} + family {{family.name}} { + output { + {% for server in forwarding_options_flow_servers %} + flow-server {{ server.address }} { + port {{ server.port}}; + version-ipfix { + template { + {{family.template}}; + } + } + } + {% endfor %} + inline-jflow { + source-address {{ forwarding_options_inline_jflow.source_address }} + flow-export-rate {{ forwarding_options_inline_jflow.flow_export_rate }} + } + } + } + {% endfor %} + } + } + } +enhanced-hash-key { + family mpls { + ether-pseudowire zero-control-word; + } +} +no-hyper-mode; +} diff --git a/roles/base_config/templates/routers/groups.j2 b/roles/base_config/templates/routers/groups.j2 new file mode 100644 index 0000000000000000000000000000000000000000..b0dd58c89002cd8e5943a1b9e6b5ea08711078da --- /dev/null +++ b/roles/base_config/templates/routers/groups.j2 @@ -0,0 +1,76 @@ +{% set hostname_as_a_list= inventory_hostname.split('.')%} +{% set short_hostname= hostname_as_a_list[:3] | join('.')%} +replace: groups { +NO_TRAPS { + interfaces { + <*> { + unit <*> { + no-traps; + } + } + } +} +{% if ansible_net_has_2RE == true %} +re0 { + system { + host-name {{ short_hostname }}.re0; + } + interfaces { + fxp0 { + description "PHY INFRASTRUCTURE MANAGEMENT | re0"; + speed 1g; + link-mode full-duplex; + unit 0 { + family inet { + address {{re0_fxp_ipv4address| default('172.16.254.3')}}/24; + } + } + } + } +} +re1 { + system { + host-name {{ short_hostname }}.re1; + } + interfaces { + fxp0 { + description "PHY INFRASTRUCTURE MANAGEMENT | re1"; + speed 1g; + link-mode full-duplex; + unit 0 { + family inet { + address {{re1_fxp_ipv4address| default('172.16.254.4')}}/24; + } + } + } + } +} +{%endif%} + +load-balance-adaptive { + interfaces { + <ae*> { + aggregated-ether-options { + load-balance { + adaptive; + } + } + } + } +} + +} + +{% if ansible_net_has_2RE == true %} +system { +replace: apply-groups [ re0 re1 ]; +} +interfaces { +replace: apply-groups [ re0 re1 load-balance-adaptive ]; +} +replace: apply-groups [ re0 re1 ]; +{%else%} +interfaces { +replace: apply-groups [ load-balance-adaptive ]; +} +{%endif%} diff --git a/roles/base_config/templates/routers/interfaces.j2 b/roles/base_config/templates/routers/interfaces.j2 new file mode 100644 index 0000000000000000000000000000000000000000..71da808392581340278abe4560d56d43197df2fa --- /dev/null +++ b/roles/base_config/templates/routers/interfaces.j2 @@ -0,0 +1,63 @@ +interfaces { +replace: lo0 { + unit 0 { + family inet { + filter { + input ROUTER_access; + } + address {{lo_ipv4_address}}/32; + } + family iso { + address {{ lo_iso_address }}; + } + family inet6 { + filter { + input ROUTER_access_V6; + } + address {{lo_ipv6_address}}/128; + } + } +} +replace: dsc { + unit 0 { + description "PHY INFRASTRUCTURE DISCARD | required for Multicast monitoring"; + family inet { + address 192.0.2.112/32; + } + } +} + +lt-0/0/0 { + +replace: unit 16 { + description "SRV_GLOBAL INFRASTRUCTURE ACCESS IAS SRF0000001 | BGP Peering - RE Side"; + encapsulation ethernet; + peer-unit 61; + family inet { + filter { + input bone-in; + output bone-out; + } + address {{ lt_ipv4_network | ipaddr('net') | ipaddr('address')}}/31; + } + family inet6 { + filter { + input bone6-in; + output bone6-out; + } + address {{ lt_ipv6_network | ipaddr('net') | ipaddr('1') | ipaddr('address')}}/126; + } + } +replace: unit 61 { + description "SRV_IAS INFRASTRUCTURE ACCESS GLOBAL SRF0000001 | BGP Peering - IAS Side"; + encapsulation ethernet; + peer-unit 16; + family inet { + address {{ lt_ipv4_network | ipaddr('net') | ipaddr('1') | ipaddr('address')}}/31; + } + family inet6 { + address {{ lt_ipv6_network | ipaddr('net') | ipaddr('2') | ipaddr('address')}}/126; + } + } +} +} diff --git a/roles/base_config/templates/routers/policy_options.j2 b/roles/base_config/templates/routers/policy_options.j2 new file mode 100644 index 0000000000000000000000000000000000000000..81b017d51cde43f8ca64de00df335d36837e1a54 --- /dev/null +++ b/roles/base_config/templates/routers/policy_options.j2 @@ -0,0 +1,32 @@ +policy-options { + {% for config_item, value in po_memory_limits.items() %} + {{ config_item }} { + memory-limit {{value}}; + } + {% endfor %} + {# prefix-lists #} + {% for prefixlist in po_prefixlists %} +replace: prefix-list {{ prefixlist.name }} { + {% if prefixlist.prefixes is defined %} + {% for prefix in prefixlist.prefixes %} + {{ prefix }}; + {% endfor %} + {% endif %} + {% if prefixlist.apply_path is defined %} + apply-path {{ prefixlist.apply_path }}; + {% endif %} + } + {% endfor %} + {# communities #} + {% if po_communities is defined %} + {% for community in po_communities %} +replace: community {{ community.name }} members {{ community.members }}; + {% endfor %} + {% endif %} + {# as-path #} + {% if po_as_path is defined %} + {% for as_path in po_as_path %} +replace: as-path {{ as_path.name }} {{ as_path.regex }}; + {% endfor %} + {% endif %} +} diff --git a/roles/base_config/templates/routers/policy_statements.j2 b/roles/base_config/templates/routers/policy_statements.j2 new file mode 100644 index 0000000000000000000000000000000000000000..7c81e1d9bfef6f967412d31974651a27296fd6da --- /dev/null +++ b/roles/base_config/templates/routers/policy_statements.j2 @@ -0,0 +1,103 @@ +{# TODO: list of from and then keywords as Jinja set #} +{% set FROM_ONE_LINER = ['community-count', 'route-filter', 'source-address-filter', 'family', 'source-class', 'validation-database'] %} + +policy-options { +{% if po_communities is defined %} +{% for community in po_communities %} +replace: community {{ community.name }} members {{ community.members }}; +{% endfor %} +{% endif %} + +{% if po_policy_statements is defined %} +{% for ps, ps_data in po_policy_statements.items() -%} +replace: policy-statement {{ ps }} { + {% if ps_data.terms is defined %} + {% for term in ps_data.terms -%} + term {{term.name}} { + {% if term.from is defined %} + from { + {% for from, from_data in term.from.items() -%} + {# TODO: check intersection of FROM_ONE_LINER and 'from' #} + {%- if ("community-count" in from) or ("route-filter" in from) or ("validation-database" in from) or ("family" in from) or ("source-class" in from) or ("source-address-filter" in from) or ("prefix-list" in from) %} + {% for from_data_element in from_data %} + {{ from }} {{ from_data_element }}; + {% endfor %} + {% elif (from_data is iterable) and (from_data is not string) %} + {{ from }} [ {% for from_data_element in from_data %}{{ from_data_element }} {% endfor %} ]; + {% else %} + {{ from }} { + {% for from_data_element in from_data -%} + {{ from_data_element }}; + {%- endfor %} + } + {% endif -%} + {%- endfor %} +} + {% endif %} + + {% if term.then is defined %} + then { + {% for then, then_data in term.then.items() -%} + {% if ("validation-state" in then) or ("next" in then) or ("label-allocation" in then) or ("-class" in then) %} + {% for then_data_element in then_data -%} + {{ then }} {{ then_data_element }}; + {% endfor %} + {% elif ("community" in then) %} + {% for then_data_element in then_data -%} + {{ then }} add {{ then_data_element }}; + {% endfor %} + {% elif (then_data is iterable) and (then_data is not string) %} + {{ then }} [ {% for then_data_element in then_data -%} {{ then_data_element }} {%- endfor%} ]; + {% else %} + {{ then }}; + {% endif %} + {%- endfor %} + } + {% endif %} +} + {% endfor %} +{% endif %} + +{% if ps_data.from is defined %} + from { + {% for from, from_data in ps_data.from.items() %} + {% if ("community-count" in from) or ("route-filter" in from) or ("validation-database" in from) or ("family" in from) or ("source-class" in from) or ("source-address-filter" in from) or ("prefix-list" in from) %} + {% for from_data_element in from_data %} + {{ from }} {{ from_data_element }}; + {% endfor %} + {% elif (from_data is iterable) and (from_data is not string) %} + {{ from }} [ {% for from_data_element in from_data %} {{ from_data_element }} {% endfor %} ]; + {% else %} + {{ from }} { + {% for from_data_element in from_data %} + {{ from_data_element }}; + {% endfor %} + } + {% endif %} + {% endfor %} +} +{% endif %} + +{% if ps_data.then is defined %} + then { + {% for then, then_data in ps_data.then.items() -%} + {% if ("validation-state" in then) or ("next" in then) or ("label-allocation" in then) or ("-class" in then) %} + {% for then_data_element in then_data -%} + {{ then }} {{ then_data_element }}; + {% endfor %} + {% elif ("community" in then) %} + {% for then_data_element in then_data -%} + {{ then }} add {{ then_data_element }}; + {% endfor %} + {% elif (then_data is iterable) and (then_data is not string) %} + {{ then }} [ {% for then_data_element in then_data -%} {{ then_data_element }} {%- endfor%} ]; + {% else %} + {{ then }}; + {% endif %} + {%- endfor %} + } +{% endif %} +} +{% endfor %} +{% endif %} +} diff --git a/roles/base_config/templates/routers/protocols/bgp.j2 b/roles/base_config/templates/routers/protocols/bgp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..ef6b9795386da23f4d74c7ef56ed7f16d8eac5b7 --- /dev/null +++ b/roles/base_config/templates/routers/protocols/bgp.j2 @@ -0,0 +1,73 @@ +protocols { + bgp { + path-selection external-router-id; + precision-timers; + log-updown; + drop-path-attributes 128; + {% if protocols_bgp.groups is defined%} + {% for group in protocols_bgp.groups %} +replace: group {{ group.name }} { + type {{ group.type }}; + description "{{ group.description }}"; + local-address {{ group.local_address }}; + {% if group.families is defined%} + {% for family in group.families %} + family {{ family.name }} { + {% for nlri in family.nlris %} + {{ nlri}}; + {% endfor %} + } + {% endfor %} + {% endif %} + {% if group.authentication_key is defined %} + authentication-key {{ group.authentication_key }}; + {% endif %} + {% if group.import_policies is defined%} +{# {% if group.import_policies|length > 1 %} #} + import [{% for policy in group.import_policies %} {{ policy }} {% endfor %}]; +{# {% else %} #} +{# import {{ policy }};#} +{# {% endif %} #} + {% endif %} + {% if group.export_policies is defined%} +{# {% if group.export_policies|length > 1 %} #} + export [{% for policy in group.export_policies %} {{ policy }} {% endfor %}]; +{# {% else %} #} +{# export {{ policy }}; #} +{# {% endif %} #} + {% endif %} + {% if group.neighbors is defined and group.name != "iGEANT" and group.name != "iGEANT6" %} + {% for neighbor in group.neighbors %} + neighbor {{ neighbor.ip_address }} { + description "{{ neighbor.description }}"; + hold-time {{ neighbor.hold_time }}; + {% if neighbor.passive == True %} + passive ; + {% endif %} + import ps-deny-all; + {% if neighbor.families is defined%} + {% for family in neighbor.families %} + family {{ family.name }} { + {% for nlri in family.nlris %} + {{ nlri}}; + {% endfor %} + } + {% endfor %} + {% endif %} + {% if neighbor.authentication_key is defined %} + authentication-key {{ neighbor.authentication_key }}; + {% endif %} + {% if neighbor.local_as is defined %} + local-as {{ neighbor.local_as }}; + {% endif %} + {% if neighbor.cluster_id is defined %} + cluster {{ neighbor.cluster_id }}; + {% endif %} + } + {% endfor %} + {% endif %} + } + {% endfor %} + {% endif %} + } +} diff --git a/roles/base_config/templates/routers/protocols/global_msdp.j2 b/roles/base_config/templates/routers/protocols/global_msdp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..5e508e118f4e45e1825c8b5d0fec986886492958 --- /dev/null +++ b/roles/base_config/templates/routers/protocols/global_msdp.j2 @@ -0,0 +1,19 @@ +protocols { +replace: msdp { + rib-group multicast; + active-source-limit { + maximum 20000; + threshold 20000; + log-interval 32700; + } + local-address {{ lo_ipv4_address }}; + source 0.0.0.0/0 { + active-source-limit { + maximum 1000; + threshold 900; + log-interval 32700; + } + } + {% include 'protocols/internal_msdp.j2' %} + } +} diff --git a/roles/base_config/templates/routers/protocols/igmp.j2 b/roles/base_config/templates/routers/protocols/igmp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..33bf5d440ab65e8ea77c58b4d087de9bbbad8fb8 --- /dev/null +++ b/roles/base_config/templates/routers/protocols/igmp.j2 @@ -0,0 +1,16 @@ +protocols { +replace: igmp { + interface all { + disable; + } + interface dsc.0 { + version 3; + static { + group 232.223.222.1 { + source 212.201.139.66; + source 193.17.9.3; + } + } + } + } +} diff --git a/roles/base_config/templates/routers/protocols/internal_msdp.j2 b/roles/base_config/templates/routers/protocols/internal_msdp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..a176def2239f7f3735291d7fbdba8df4dcb61217 --- /dev/null +++ b/roles/base_config/templates/routers/protocols/internal_msdp.j2 @@ -0,0 +1,25 @@ +{% if ansible_play_name != 'deploy_base_config' %} +protocols { + msdp { +replace: {% endif %} group internal_msdp { + mode mesh-group; + export [ BOGON_SOURCES ]; + import [ BOGON_SOURCES ]; + {% if ansible_play_name != 'deploy_base_config' %} + {% if new_router_to_add is defined %} + {% set all_the_network_plus_new_router = groups.lab_routers|union([new_router_to_add])%} + {% for host in all_the_network_plus_new_router|difference([inventory_hostname]) %} + peer {{ hostvars[host]["lo_ipv4_address"] }}; + {% endfor %} + {% else %} + {% set all_the_network_plus_new_router = groups.lab_routers %} + {% for host in all_the_network_plus_new_router|difference([inventory_hostname]) %} + peer {{ hostvars[host]["lo_ipv4_address"] }}; + {% endfor %} + {% endif %} + {% endif %} + } +{% if ansible_play_name != 'deploy_base_config' %} + } +} +{% endif %} diff --git a/roles/base_config/templates/routers/protocols/isis.j2 b/roles/base_config/templates/routers/protocols/isis.j2 new file mode 100644 index 0000000000000000000000000000000000000000..e86a24078b89691d956ffb0347d9ea3221bea736 --- /dev/null +++ b/roles/base_config/templates/routers/protocols/isis.j2 @@ -0,0 +1,42 @@ +{##} +{# Template to render isis stanza: it is used as it is for base config#} +{# If called by cic_isis playbook, it also includes isis interfaces, isis trunks and additional parameters like isis_disabled_interfaces, #} +{# isis_policies and isis_additional_interfaces #} +{##} +protocols { +replace: isis { + rib-group { + inet unicast-multicast; + inet6 unicast-multicastv6; + } + backup-spf-options { + use-post-convergence-lfa; + use-source-packet-routing; + } + overload timeout 300; + {% set loopback_as_a_list= lo_ipv4_address.split('.')%} + {% set last_octet_filled= '%02d' % (loopback_as_a_list[3]|int) %} + source-packet-routing { + srgb start-label 10000 index-range 10000; + node-segment { + ipv4-index 4{{ loopback_as_a_list[2][-1:] }}{{ last_octet_filled }}; + ipv6-index 6{{ loopback_as_a_list[2][-1:] }}{{ last_octet_filled }}; + } + } + level 1 disable; + level 2 wide-metrics-only; + + interface all { + passive; + } + interface fxp0.0 { + disable; + } + + {# ISIS policies (if defined) #} + {% if isis_policies is defined %} + export [ {% for policy in isis_policies %} {{ policy }} {% endfor %} ] + {% endif %} + } +} + diff --git a/roles/base_config/templates/routers/protocols/ldp.j2 b/roles/base_config/templates/routers/protocols/ldp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..33419e2f3531b5d5c3a32319b6decc547dce4eb6 --- /dev/null +++ b/roles/base_config/templates/routers/protocols/ldp.j2 @@ -0,0 +1,8 @@ +protocols { +replace: ldp { + preference 16; + track-igp-metric; + deaggregate; + interface lo0.0; + } +} diff --git a/roles/base_config/templates/routers/protocols/lldp.j2 b/roles/base_config/templates/routers/protocols/lldp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..064785a302da9884f32885763a434098ef55415f --- /dev/null +++ b/roles/base_config/templates/routers/protocols/lldp.j2 @@ -0,0 +1,7 @@ +protocols { +replace: lldp { + port-id-subtype interface-name; + interface all disable; + interface fxp0; + } +} diff --git a/roles/base_config/templates/routers/protocols/mld.j2 b/roles/base_config/templates/routers/protocols/mld.j2 new file mode 100644 index 0000000000000000000000000000000000000000..d43ef829a0a3e67f40cae0d510f1860faaef36ee --- /dev/null +++ b/roles/base_config/templates/routers/protocols/mld.j2 @@ -0,0 +1,7 @@ +protocols { +replace: mld { + interface all { + disable; + } + } +} diff --git a/roles/base_config/templates/routers/protocols/mpls.j2 b/roles/base_config/templates/routers/protocols/mpls.j2 new file mode 100644 index 0000000000000000000000000000000000000000..f4b337febe8aa89e6bd2f2ad3ebb9ffa68dce1ab --- /dev/null +++ b/roles/base_config/templates/routers/protocols/mpls.j2 @@ -0,0 +1,8 @@ +protocols { +replace: mpls { + ipv6-tunneling; + explicit-null; + icmp-tunneling; + interface all; + } +} diff --git a/roles/base_config/templates/routers/protocols/neighbor-discovery.j2 b/roles/base_config/templates/routers/protocols/neighbor-discovery.j2 new file mode 100644 index 0000000000000000000000000000000000000000..2717b6de4774d2b74581277564b1ffab0f19408a --- /dev/null +++ b/roles/base_config/templates/routers/protocols/neighbor-discovery.j2 @@ -0,0 +1,5 @@ +protocols { +replace: neighbor-discovery { + onlink-subnet-only; + } +} diff --git a/roles/base_config/templates/routers/protocols/pim.j2 b/roles/base_config/templates/routers/protocols/pim.j2 new file mode 100644 index 0000000000000000000000000000000000000000..aa6599961827b3000d584403e4543dffaf6b207a --- /dev/null +++ b/roles/base_config/templates/routers/protocols/pim.j2 @@ -0,0 +1,67 @@ +routing-options { + rib-groups { +replace: multicast { + export-rib inet.2; + import-rib inet.2; + } +replace: multicastv6 { + import-rib inet6.2; + } + } +} +protocols { +replace: pim { + rib-group { + inet multicast; + inet6 multicastv6; + } + rp { + bootstrap { + family inet { + priority 0; + import no-bsr; + export no-bsr; + } + family inet6 { + priority 0; + import no-bsr; + export no-bsr; + } + } + embedded-rp { + group-ranges { + ff7e::/16; + } + } +{% if inventory_hostname in protocols_pim.rp_routers %} + local { +{% else %} + static { +{% endif %} + address {{ protocols_pim.rpip }}; + } + } + interface all { + mode sparse; + } + interface fxp0.0 { + disable; + } +{% if custom_fact_existing_interfaces is defined %} + {% if not custom_fact_existing_interfaces is sameas false %} + {% for interface in custom_fact_existing_interfaces %} + {% if interface.name != "fxp0.0" and interface.name != "all" and interface|length > 1 and interface.disable is defined %} + interface {{interface.name}} { + disable; + } + {% endif %} + {%endfor%} + {%endif%} +{%endif%} + } +} +policy-options { +replace: policy-statement no-bsr { + then reject; + } +} diff --git a/roles/base_config/templates/routers/protocols/protocols_global.j2 b/roles/base_config/templates/routers/protocols/protocols_global.j2 new file mode 100644 index 0000000000000000000000000000000000000000..25448e533344aed89f447433407c8fe55d84a57c --- /dev/null +++ b/roles/base_config/templates/routers/protocols/protocols_global.j2 @@ -0,0 +1,19 @@ +{% include 'protocols/mld.j2' %} + +{% include 'protocols/pim.j2' %} + +{% include 'protocols/igmp.j2' %} + +{% include 'protocols/rsvp.j2' %} + +{% include 'protocols/mpls.j2' %} + +{% include 'protocols/ldp.j2' %} + +{% include 'protocols/lldp.j2' %} + +{% include 'protocols/neighbor-discovery.j2' %} + +{% include 'protocols/isis.j2' %} + +{% include 'protocols/bgp.j2' %} diff --git a/roles/base_config/templates/routers/protocols/rsvp.j2 b/roles/base_config/templates/routers/protocols/rsvp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..d881e5c9f143a3a335e38c41c6939a1d1c6e8b3b --- /dev/null +++ b/roles/base_config/templates/routers/protocols/rsvp.j2 @@ -0,0 +1,5 @@ +protocols { +replace: rsvp { + interface all; + } +} diff --git a/roles/base_config/templates/routers/routing_instances.j2 b/roles/base_config/templates/routers/routing_instances.j2 new file mode 100644 index 0000000000000000000000000000000000000000..d00d5ff1702f20cce40f68266dc8ee524e6ebfb3 --- /dev/null +++ b/roles/base_config/templates/routers/routing_instances.j2 @@ -0,0 +1,12 @@ +routing-instances { +replace: vrf-mgmt { + description "L3VPN Management"; + instance-type vrf; + route-distinguisher 20965:991; + vrf-target target:20965:991; + vrf-table-label; + routing-options { + autonomous-system 20965; + } + } +} diff --git a/roles/base_config/templates/routers/routing_options.j2 b/roles/base_config/templates/routers/routing_options.j2 new file mode 100644 index 0000000000000000000000000000000000000000..5d1d22f3bceae52b828c75075da58c012c8afff6 --- /dev/null +++ b/roles/base_config/templates/routers/routing_options.j2 @@ -0,0 +1,106 @@ +{% if global_routing_options is defined %} +replace: routing-options { + {% if ansible_net_has_2RE == true %} + nonstop-routing; + {% endif %} + + {% if global_routing_options.interface_routes.rib_group is defined %} + interface-routes { + rib-group { + {% for group in global_routing_options.interface_routes.rib_group %} + {{ group.name }} {{group.family}}; + {% endfor %} + {% endif %} + } + } + + {% if global_routing_options.ribs is defined %} + {%- for rib in global_routing_options.ribs %} + rib {{ rib.name }} { + {% if rib.static_routes is defined %} + static { + {% for static_route in rib.static_routes %} + route {{ static_route.route }} { + {% for action in static_route.actions %} + {{ action }}; + {% endfor %} + } + {% endfor %} + } + {% endif %} + {%- if rib.maximum_prefixes is defined %} + maximum-prefixes {{ rib.maximum_prefixes.prefix_num }} threshold {{ rib.maximum_prefixes.threshold }}; + {% endif -%} + } + {%- endfor -%} + {% endif %} + {% if global_routing_options.static_routes is defined %} + static { + {% for static_route in global_routing_options.static_routes %} + route {{ static_route.route }} { + {% for action in static_route.actions %} + {{ action }}; + {% endfor %} + } + {% endfor %} + } + {% endif %} + {% if global_routing_options.rib_groups is defined %} + rib-groups { + {% for rib_group in global_routing_options.rib_groups %} + {{ rib_group.name}} { + {%- if rib_group.import_rib is defined %} + {%- if rib_group.import_rib | length > 1 %} + import-rib [{%- for group in rib_group.import_rib %} {{ group }} {% endfor -%} ]; + {% else %} + import-rib {{ rib_group.import_rib[0] }}; + {% endif %} + {% endif %} + {% if rib_group.export_rib is defined %} + {%- if rib_group.export_rib | length > 1 %} + export-rib [{%- for group in rib_group.export_rib %} {{ group }} {% endfor -%} ]; + {% else %} + export-rib {{ rib_group.export_rib[0] }}; + {% endif %} + {% endif -%} + } + {% endfor %} + } + {% endif %} + router-id {{ lo_ipv4_address }}; + autonomous-system 20965; + forwarding-table { + export [ dest-class-usage source-class-usage ]; + chained-composite-next-hop { + ingress { + l2vpn; + l2ckt; + l3vpn; + } + } + } + {% if global_routing_options.rpki_validation is defined %} + validation { + notification-rib [ {% for rib in global_routing_options.rpki_validation.notification_ribs %} {{rib}} {% endfor %}]; + {% for validator_group in global_routing_options.rpki_validation.validators %} + group {{ validator_group.group }}{ + {% for session in validator_group.sessions %} + session {{ session.server }} { + port {{ session.port }}; + local-address {{ lo_ipv4_address }}; + } + {% endfor %} + } + {% endfor %} + } + {% endif %} + multicast { + forwarding-cache { + threshold { + suppress 20000; + reuse 18000; + } + } + } +} +{% endif %} diff --git a/roles/base_config/templates/routers/services.j2 b/roles/base_config/templates/routers/services.j2 new file mode 100644 index 0000000000000000000000000000000000000000..5eeab680fc0e8eab6d17f587417bc18b9e5b5b58 --- /dev/null +++ b/roles/base_config/templates/routers/services.j2 @@ -0,0 +1,106 @@ +services { +{% if service_version_ipfix is defined %} +replace: flow-monitoring { + version-ipfix { + {% for template in service_version_ipfix.templates %} + template {{ template.proto }} { + flow-active-timeout {{ template.flow_active_timeout }}; + flow-inactive-timeout {{ template.flow_inactive_timeout }}; + nexthop-learning { + {{ template.next_hop_learning }}; + } + template-refresh-rate { + seconds {{ template.template_refresh_rate }}; + } + option-refresh-rate { + seconds {{ template.option_refresh_rate }}; + } + {% if template.label_positions is defined %} + {{ template.protocol_template }} { + label-position [ {%for label_position in template.label_positions %} {{ label_position }}{% endfor %} ] ; + } + {% else %} + {{ template.protocol_template }}; + {% endif %} + } + {% endfor %} + } +} +{% endif %} +{% if services_analytics is defined %} +replace: analytics { +{% if services_analytics.streaming_servers is defined %} + {% for streaming_server_name, streaming_server_conf in services_analytics.streaming_servers.iteritems() %} + streaming-server {{ streaming_server_name }} { + remote-address {{ streaming_server_conf.remote_address }}; + remote-port {{ streaming_server_conf.remote_port }}; + } + {% endfor %} +{% else %} +{{ raise('ERROR: YOU HAVE NO STREAMING SERVER DEFINED')}} +{% endif %} +{% if services_analytics.export_profiles is defined %} + {% for export_profile_name, export_profile_conf in services_analytics.export_profiles.iteritems() %} + export-profile {{ export_profile_name }} { + local-address {{ export_profile_conf.local_address }} ; + local-port {{ export_profile_conf.local_port }} ; + reporting-rate {{ export_profile_conf.reporting_rate }} ; + format {{ export_profile_conf.format }} ; + transport {{ export_profile_conf.transport }} ; + } + {% endfor %} +{% else %} +{{ raise('ERROR: YOU HAVE NO EXPORT PROFILE DEFINED')}} +{% endif %} +{% if services_analytics.sensors is defined %} + {% for sensor_name, sensor_conf in services_analytics.sensors.iteritems() %} + sensor {{ sensor_name }} { + server-name {{ sensor_conf.server_name}}; + export-name {{ sensor_conf.export_name}}; + resource {{ sensor_conf.resource}}; + } + {% endfor %} +{% else %} +{{ raise('ERROR: YOU HAVE NO SENSORS DEFINED')}} +{% endif %} +} +{% endif %} + +{% if service_rpm is defined %} +replace: rpm { + {% if service_rpm.traceoptions is defined %} + traceoptions { + file {{ service_rpm.traceoptions.filename }} size {{ service_rpm.traceoptions.filesize }}; + {% for flag in service_rpm.traceoptions.flags %} + flag {{ flag }}; + {% endfor %} + } + {% endif %} + {% if service_rpm.twamp is defined %} + twamp { + {% if service_rpm.twamp.server is defined %} + server { + authentication-mode {{ service_rpm.twamp.server.auth_mode }}; + max-connection-duration {{ service_rpm.twamp.server.max_duration }}; + maximum-sessions {{ service_rpm.twamp.server.max_sessions }}; + maximum-sessions-per-connection {{ service_rpm.twamp.server.max_sessions_per_conn }}; + maximum-connections {{ service_rpm.twamp.server.max_connections }}; + maximum-connections-per-client {{ service_rpm.twamp.server.max_connections_per_client }}; + port {{ service_rpm.twamp.server.port }}; + {% for client_list in service_rpm.twamp.client_lists %} + client-list {{ client_list.name }} { + address { + {% for address in client_list.address %} + {{ address }}; + {% endfor %} + } + } + {% endfor %} +} + {% endif %} +} + {% endif %} + +} +{% endif %} +} diff --git a/roles/base_config/templates/routers/snmp.j2 b/roles/base_config/templates/routers/snmp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..832498e33dec07c501f41e966c810f1d22b79bb8 --- /dev/null +++ b/roles/base_config/templates/routers/snmp.j2 @@ -0,0 +1,58 @@ +replace: snmp { + location "{{ snmp_location }}"; + contact "{{ snmp_contact }}"; + {% if snmp_views is defined %} + {% for snmp_view in snmp_views() %} + view {{ snmp_view.name }} { + {% for oid_name, oid in snmp_view.oids.items() %} + oid {{ oid_name }} {% if oid.state is defined %}{{ oid.state }}{% endif %}; + {% endfor %} + } + {% endfor %} + {% endif %} + {% for community in snmp_communities %} + community {{ community.name }} { + authorization {{ community.authorization }}; + {% if community.clients is defined %} + clients { + {% for client in community.clients %} + {{ client.client }}; + {% endfor %} + } + {% endif %} + {% if community.view is defined %} + view {{ community.view }}; + {% endif %} + } + {% endfor %} + {% if snmp_trap_options is defined %} + trap-options { + {% for option, value in snmp_trap_options.items() %} + {{ option }} {{ value }}; + {% endfor %} + } + {% endif %} + + {% for trap_group in snmp_trap_groups %} + trap-group {{ trap_group.name }} { + {% if trap_group.version is defined %} + version {{trap_group.version}}; + {% endif %} + {% if trap_group.categories is defined %} + categories { + {% for category in trap_group.categories %} + {{ category }}; + {% endfor %} + } + {% endif %} + targets { + {% for target in trap_group.targets %} + {{ target.target }}; + {% endfor %} + } + } + {% endfor %} + {% if snmp_routing_instance_access is defined %} + routing-instance-access; + {% endif %} +} diff --git a/roles/base_config/templates/routers/system/general.j2 b/roles/base_config/templates/routers/system/general.j2 new file mode 100644 index 0000000000000000000000000000000000000000..0c822dc15035f713b246f318660e7c4ca1b010aa --- /dev/null +++ b/roles/base_config/templates/routers/system/general.j2 @@ -0,0 +1,53 @@ +{% set hostname_as_a_list= inventory_hostname.split('.')%} +{% set short_hostname= hostname_as_a_list[:3] | join('.')%} +system { + {% if ansible_net_has_2RE == false %} + replace: host-name {{ short_hostname }}.re0; + {% if cfg_backup_router_fxp_address is defined %} + replace: archival { + configuration { + transfer-on-commit; + archive-sites "scp://{{cfg_backup_username}}@{{cfg_backup_router_fxp_address }}:{{cfg_backup_path}}" password {{cfg_backup_password}}; + } + } + {% endif %} + {% endif %} + replace: commit { + synchronize ; + {% if ansible_net_has_2RE == true %} + fast-synchronize ; + {% endif %} + } + {% if ansible_net_has_2RE == true %} + switchover-on-routing-crash ; + {% endif %} + replace: authentication-order [ radius password ]; + {% if system_root_pwd is defined %} + replace: root-authentication { + encrypted-password {{ system_root_pwd }} ; + } + {% endif %} + {% if system_domain_name is defined %} + replace: domain-name {{ system_domain_name }} ; + {% endif %} + {% if system_time_zone is defined %} + replace: time-zone {{ system_time_zone }} ; + {% endif %} + dump-on-panic; + {% if system_time_zone is defined %} + replace: location country-code {{ site_country_code }} ; + {% endif %} + {% if system_domain_search is defined %} + replace: domain-search [ {% for domain in system_domain_search %}{{ domain }} {% endfor %} ]; + {% endif %} + {% if system_name_servers is defined %} + replace: name-server { + {%- for name_server in system_name_servers %} + {{ name_server }}; + {%- endfor %} + {% endif %} + } + replace: static-host-mapping { + lo0 inet {{ lo_ipv4_address }}; + } +} diff --git a/roles/base_config/templates/routers/system/login.j2 b/roles/base_config/templates/routers/system/login.j2 new file mode 100644 index 0000000000000000000000000000000000000000..2fc7e03bb803b11f579fa90b6b2daea28d6cdd31 --- /dev/null +++ b/roles/base_config/templates/routers/system/login.j2 @@ -0,0 +1,72 @@ +system { +replace: login { + idle-timeout 15; +{# classes #} + {% if system_login_classes is defined %} + {% for login_class in system_login_classes %} + class {{ login_class.name }} { + {% if login_class.idle_timeout is defined %} + idle-timeout {{ login_class.idle_timeout }}; + {% endif %} + {% if login_class.login_alarms is defined and login_class.login_alarms is sameas true %} + login-alarms; + {% endif %} + {% if login_class.permissions is defined %} + permissions [{% for permission in login_class.permissions %} {{ permission }}{% endfor %} ]; + {% endif %} + {% if login_class.allow_commands is defined %} + allow-commands "{{ login_class.allow_commands }}"; + {% endif %} + {% if login_class.deny_commands is defined %} + deny-commands "{{ login_class.deny_commands }}"; + {% endif %} + {% if login_class.allow_configuration_regexps is defined %} + allow-configuration-regexps [ {% for regex in login_class.allow_configuration_regexps %} "{{ regex }}"{% endfor %} ]; + {% endif %} + {% if login_class.deny_configuration_regexps is defined %} + deny-configuration-regexps [ {% for regex in login_class.deny_configuration_regexps %} "{{ regex }}"{% endfor %} ]; + {% endif %} + } + {% endfor %} + {% endif %} +{# users #} + {% if system_login_users is defined %} + {% for login_user in system_login_users %} + user {{ login_user.name }} { + {% if login_user.full_name is defined %} + full-name "{{ login_user.full_name }}"; + {% endif %} + {% if login_user.uid is defined %} + uid {{ login_user.uid }}; + {% endif %} + class {{ login_user.class }}; + {% if ( login_user.authentication is defined ) and ( ( login_user.authentication.ssh_dsa is defined ) or ( login_user.authentication.ssh_rsa is defined ) or ( login_user.authentication.encrypted_password is defined ) ) %} + authentication { + {% if login_user.authentication.ssh_dsa is defined %} {% for dsa_key in login_user.authentication.ssh_dsa %} + ssh-dsa "{{ dsa_key }}"; + {% endfor %} + {% endif %} + {% if login_user.authentication.ssh_rsa is defined %} {% for rsa_key in login_user.authentication.ssh_rsa %} + ssh-rsa "{{ rsa_key }}"; + {% endfor %} + {% endif %} + {% if login_user.authentication.encrypted_password is defined %} + encrypted-password "{{ login_user.authentication.encrypted_password }}"; + {% endif %} + } + {% endif %} + } + {% endfor %} + {% endif %} +{# options #} + {% if system_login_password_policies is defined %} + password { + {% for option in system_login_password_policies %} + {{ option.option }} {{ option.value }} ; + {% endfor %} + } + {% endif %} + message "----------------------------------------------------------------\n\n This is {{ inventory_hostname }} a GEANT Router in Cambridge UK \n Warning: Unauthorized access to this equipment is strictly forbidden and will lead to prosecution \n\n-------------------------------------------------------------\n"; + } +} + diff --git a/roles/base_config/templates/routers/system/ntp.j2 b/roles/base_config/templates/routers/system/ntp.j2 new file mode 100644 index 0000000000000000000000000000000000000000..b60ce08585953f92421eff2b7eb5e5f919aa840a --- /dev/null +++ b/roles/base_config/templates/routers/system/ntp.j2 @@ -0,0 +1,25 @@ +system { +replace: ntp { + {% if system_ntp.ntp_keys is defined %} + {% for ntp_key in system_ntp.ntp_keys %} + authentication-key {{ ntp_key.id }} type {{ ntp_key.type }} value {{ ntp_key.value }} ; + {% endfor %} + {% endif %} + {% if system_ntp.servers is defined %} + {% for ntp_server in system_ntp.servers %} + server {{ ntp_server.address }} {% if ntp_server.key is defined %} key {{ ntp_server.key }} {% endif %}; + {% endfor %} + {% endif %} + {% if '18' in ansible_net_version %} + {% if system_ntp.boot_server is defined %} + boot-server {{ system_ntp.boot_server }} ; + {%- endif %} + {% endif %} + {% if system_ntp.trusted_keys is defined %} + {% for trusted_key in system_ntp.trusted_keys %} + trusted-key {{ trusted_key }} ; + {% endfor %} + {% endif %} + source-address {{ system_ntp.source_address }} ; + } +} diff --git a/roles/base_config/templates/routers/system/radius-server.j2 b/roles/base_config/templates/routers/system/radius-server.j2 new file mode 100644 index 0000000000000000000000000000000000000000..f054917b088c3ba1071665e4308893c76018301f --- /dev/null +++ b/roles/base_config/templates/routers/system/radius-server.j2 @@ -0,0 +1,18 @@ +system { +{% if system_radius_servers is defined %} + replace: radius-server { + {%- for radius_server in system_radius_servers %} + {{ radius_server.host }} { + secret "{{ radius_server.secret }}"; + {% if radius_server.timeout is defined %} + timeout {{ radius_server.timeout }}; + {% endif %} + {% if radius_server.source_address is defined %} + source-address {{ radius_server.source_address }}; + {% endif %} + } + {%- endfor %} + {% endif %} + } +} + diff --git a/roles/base_config/templates/routers/system/services.j2 b/roles/base_config/templates/routers/system/services.j2 new file mode 100644 index 0000000000000000000000000000000000000000..0d8a25b7b3c4f395c8bbdb2a0a25f1fa81fd6d12 --- /dev/null +++ b/roles/base_config/templates/routers/system/services.j2 @@ -0,0 +1,52 @@ +system { +replace: services { + ssh { + root-login deny; + no-tcp-forwarding; + protocol-version v2; +{% if '18' not in ansible_net_version %} + sftp-server; +{% endif %} +{% if system_services_ssh_conf is defined %} + max-sessions-per-connection {{ system_services_ssh_conf.max_sessions_per_connection }} ; + {% if system_services_ssh_conf.ciphers is defined %} + ciphers [ {% for cipher in system_services_ssh_conf.ciphers %}"{{cipher}}" {% endfor %}]; + {% endif %} + {% if system_services_ssh_conf.key_exchanges is defined %} + key-exchange [ {% for key_exchange in system_services_ssh_conf.key_exchanges %}"{{key_exchange}}" {% endfor %}]; + {% endif %} + connection-limit {{ system_services_ssh_conf.connection_limit }}; + rate-limit {{ system_services_ssh_conf.rate_limit }}; +{% endif %} + } + {% if system_services_extension_service is defined %} + extension-service { + request-response { + grpc { + clear-text { + port {{ system_services_extension_service.request_response.port}}; + } + max-connections {{ system_services_extension_service.request_response.max_connections }}; + } + } + {% if system_services_extension_service.notification is defined %} + notification { + allow-clients { + address [ {% for client in system_services_extension_service.notification.allow_clients %} "{{ client }}"{% endfor %} ]; + } + } + {% endif %} + } + {% endif %} + {% if system_services_resource_monitor is defined %} + resource-monitor { + free-heap-memory-watermark {{ system_services_resource_monitor.free_heap_memory_watermark }}; + free-nh-memory-watermark {{ system_services_resource_monitor.free_nh_memory_watermark }}; + free-fw-memory-watermark {{ system_services_resource_monitor.free_fw_memory_watermark }}; + } + {% endif %} + netconf { + ssh; + } + } +} diff --git a/roles/base_config/templates/routers/system/syslog.j2 b/roles/base_config/templates/routers/system/syslog.j2 new file mode 100644 index 0000000000000000000000000000000000000000..e8867b368aa5c69991a636f0f6f30cec26d23bc0 --- /dev/null +++ b/roles/base_config/templates/routers/system/syslog.j2 @@ -0,0 +1,78 @@ +system { + replace: syslog { + user * { + any emergency; + } + {% if system_syslog_time_format_options is defined %} + time-format {% for syslog_time_format_option in system_syslog_time_format_options %}{{ syslog_time_format_option }} {% endfor %}; + {% endif %} + {% if system_syslog_servers is defined %} + {% for syslog_server in system_syslog_servers %} + host {{ syslog_server.address }} { + {% for facility in syslog_server.facilities %} + {{ facility.name }} {{ facility.level }}; + {% endfor %} + {% if syslog_server.match is defined %} + match "{{ syslog_server.match }}"; + {% endif %} + {% if syslog_server.port is defined %} + port {{ syslog_server.port }} + {% endif %} + {% if syslog_server.source_address is defined %} + source-address {{ syslog_server.source_address }} ; + {% endif %} + {% if syslog_server.structured_data is defined %} + {% if syslog_server.structured_data == "default" %} + structured-data; + {% elif syslog_server.structured_data == "brief" %} + structured-data brief; + {% endif %} + {% endif %} + {% if syslog_server.allow_duplicates is defined %} + {% if syslog_server.allow_duplicates == True %} + allow-duplicates ; + {% endif %} + {% endif %} + } + {% endfor %} +{# {%- else %} #} +{# {{ raise('ERROR: No syslog servers configured') }}#} + {% endif %} + {% if system_syslog_source_address is defined %} + source-address {{ system_syslog_source_address }} ; + {% endif %} + {% if system_syslog_files is defined %} + {% for syslog_file in system_syslog_files %} + file {{ syslog_file.filename }} { + {% for facility in syslog_file.facilities %} + {{ facility.name }} {{ facility.level }}; + {% endfor %} + {% if syslog_file.match is defined %} + match "{{ syslog_file.match }}"; + {% endif %} + {% if syslog_file.authorization is defined %} + authorization {{ syslog_file.authorization }}; + {% endif %} + {% if syslog_file.archive_options is defined %} + archive {% if syslog_file.archive_options.files is defined %} files {{ syslog_file.archive_options.files }} {% endif %} {% if syslog_file.archive_options.size is defined %} size {{ syslog_file.archive_options.size }} {% endif %} + {% endif %} + {% if syslog_file.structured_data is defined %} + {% if syslog_file.structured_data == "default" %} + structured-data ; + {% elif syslog_file.structured_data == "brief" %} + structured-data brief; + {% endif %} + {% endif %} + {% if syslog_file.allow_duplicates is defined %} + {% if syslog_file.allow_duplicates == True %} + allow-duplicates ; + {% endif %} + {% endif %} + } + {% endfor %} + {% endif %} + } +} + + + diff --git a/roles/base_config/templates/routers/system/system_global.j2 b/roles/base_config/templates/routers/system/system_global.j2 new file mode 100644 index 0000000000000000000000000000000000000000..b8e53953bff44ea31ac6e157fa08cb9d5e455205 --- /dev/null +++ b/roles/base_config/templates/routers/system/system_global.j2 @@ -0,0 +1,16 @@ +{% include 'system/general.j2' %} + +{% include 'system/login.j2' %} + + +{#{% include 'system/services.j2' %}#} + + +{% include 'system/syslog.j2' %} + + +{% include 'system/ntp.j2' %} + + +{% include 'system/radius-server.j2' %} + diff --git a/roles/base_config/tests/inventory b/roles/base_config/tests/inventory new file mode 100644 index 0000000000000000000000000000000000000000..878877b0776c44f55fc4e458f70840f31da5bb01 --- /dev/null +++ b/roles/base_config/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/roles/base_config/tests/test.yml b/roles/base_config/tests/test.yml new file mode 100644 index 0000000000000000000000000000000000000000..914b5e6b37a549dd16e5acd8a0d42d726eee42a2 --- /dev/null +++ b/roles/base_config/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - base_config diff --git a/roles/base_config/vars/main.yml b/roles/base_config/vars/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..932875ab1b8493a14216f2c9c553a269fc0110df --- /dev/null +++ b/roles/base_config/vars/main.yml @@ -0,0 +1,8 @@ +dryrun: "True" +is_base_config_run: "True" +mytemplates: + template_name: base_config + template_path: "routers/base_config.j2" +verbs: + - "compile" + - "deploy" diff --git a/roles/iptrunks/README.md b/roles/iptrunks/README.md new file mode 100644 index 0000000000000000000000000000000000000000..225dd44b9fc5b3abff7e9c68ff9e91d505cdd5f0 --- /dev/null +++ b/roles/iptrunks/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/roles/iptrunks/defaults/main.yml b/roles/iptrunks/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..472e7555521eacb1986bc0ccbaeb70e26177c065 --- /dev/null +++ b/roles/iptrunks/defaults/main.yml @@ -0,0 +1,2 @@ +--- +# defaults file for iptrunks diff --git a/roles/iptrunks/handlers/main.yml b/roles/iptrunks/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..841ad23e08be5fc44cf75581ff4350bc18ba1fdf --- /dev/null +++ b/roles/iptrunks/handlers/main.yml @@ -0,0 +1,2 @@ +--- +# handlers file for iptrunks diff --git a/roles/iptrunks/meta/main.yml b/roles/iptrunks/meta/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..c572acc9f8b466bea50f2799b0ca1956418b862c --- /dev/null +++ b/roles/iptrunks/meta/main.yml @@ -0,0 +1,52 @@ +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: + + # + # 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: [] + # 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/roles/iptrunks/tasks/iptrunks_compile_object.yaml b/roles/iptrunks/tasks/iptrunks_compile_object.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2388f458418da11eb7c5ee9a49b27d60a8718fe0 --- /dev/null +++ b/roles/iptrunks/tasks/iptrunks_compile_object.yaml @@ -0,0 +1,20 @@ +--- +#- name: Select the trunk based on trunkid + #debug: + ##msg: "Trunk data is: {{ trunks| selectattr('id', 'match', trunk_id ) | list }}" + #msg: "{{ trunks }}" + +- name: Create a folder for all the templates + ansible.builtin.file: + path: "/var/tmp/ansible_run_{{opid}}" + state: directory + mode: '0755' + +- name: Print the template in "/var/tmp/ansible_run_{{opid}}/{{config_object}}.conf" + template: + src: "{{ config_object }}.j2" + dest: "/var/tmp/ansible_run_{{opid}}/{{config_object}}.conf" + lstrip_blocks: yes + trim_blocks: yes + delegate_to: localhost + diff --git a/roles/iptrunks/tasks/iptrunks_deploy_object.yaml b/roles/iptrunks/tasks/iptrunks_deploy_object.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3bc94781b01eb49cfd45a2d007b92a77f3e6f0b2 --- /dev/null +++ b/roles/iptrunks/tasks/iptrunks_deploy_object.yaml @@ -0,0 +1,31 @@ +--- +- name: Deploy "{{config_object}}" [CHECK ONLY] + juniper_junos_config: + load: 'replace' + src: "/var/tmp/ansible_run_{{opid}}/{{config_object}}.conf" + format: text + config_mode: "private" + check: yes + commit: no + register: response + when: verb == "deploy" and dryrun | ansible.builtin.bool + +- name: Show DRY diff of "{{ config_object }}" + debug: + msg: "{{response}}" + when: verb == "deploy" and dryrun | ansible.builtin.bool + +- name: Deploy "{{config_object}}" [FOR REAL] + juniper_junos_config: + load: 'replace' + src: "/var/tmp/ansible_run_{{opid}}/{{config_object}}.conf" + format: text + config_mode: "private" + commit: yes + register: response + when: verb == "deploy" and not (dryrun | ansible.builtin.bool) + +- name: Show real diff of "{{ config_object }}" + debug: + msg: "{{response}}" + when: verb == "deploy" and not (dryrun | ansible.builtin.bool) diff --git a/roles/iptrunks/tasks/iptrunks_remove_trunk.yaml b/roles/iptrunks/tasks/iptrunks_remove_trunk.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f1fbe7cde856c83c2ba886ded21bfb6684e95986 --- /dev/null +++ b/roles/iptrunks/tasks/iptrunks_remove_trunk.yaml @@ -0,0 +1,31 @@ +--- +- name: Deploy "{{config_object}}" [CHECK ONLY] + juniper_junos_config: + load: merge + src: "/var/tmp/ansible_run_{{opid}}/{{config_object}}.conf" + format: set + config_mode: "private" + check: yes + commit: no + register: response + when: verb == "remove" and dryrun | ansible.builtin.bool + +- name: Show DRY diff of "{{ config_object }}" + debug: + msg: "{{response}}" + when: verb == "remove" and dryrun | ansible.builtin.bool + +- name: Deploy "{{config_object}}" [FOR REAL] + juniper_junos_config: + load: merge + src: "/var/tmp/ansible_run_{{opid}}/{{config_object}}.conf" + format: set + config_mode: "private" + commit: yes + register: response + when: verb == "remove" and not (dryrun | ansible.builtin.bool) + +- name: Show real diff of "{{ config_object }}" + debug: + msg: "{{response}}" + when: verb == "remove" and not (dryrun | ansible.builtin.bool) diff --git a/roles/iptrunks/tasks/main.yml b/roles/iptrunks/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..a0495c238ac09e440416a864d6f0456a0a51e8c3 --- /dev/null +++ b/roles/iptrunks/tasks/main.yml @@ -0,0 +1,37 @@ +--- +# tasks file for iptrunks +- name: Print the usage + debug: + msg: + - "Both 'verb' and 'config_object' are required." + - "Allowed verbs: 'compile', 'deploy'. Use: -e 'verb=$verb'" + - "Allowed objects: 'trunk_interface', 'isis', 'isis_interface', 'ldp_interface', 'lldp_interface'. Use: -e 'config_object=$config_object'" + - "'$trunk_id' must be defined for this role to work." + when: ((verb is not defined) or (config_object is not defined) or (trunk_id is not defined)) or (verb not in verbs) or (config_object not in config_objects) + +- meta: end_play + when: >- + ((verb is not defined) or + (config_object is not defined) or (trunk_id is not defined)) or (verb not in verbs) or (config_object not in config_objects) + +- name: Gather_facts + junipernetworks.junos.junos_facts: + gather_subset: all + +- set_fact: + opid: "{{ lookup('community.general.random_string', length=18, special=false) }}" + config_is_different: "False" + trunks: "{{ newtrunks }}" + +- name: Print the ID + debug: + msg: "{{opid}}" + +- include_tasks: iptrunks_compile_object.yaml + when: (verb in verbs) + +- include_tasks: iptrunks_deploy_object.yaml + when: verb == "deploy" + +- include_tasks: iptrunks_remove_trunk.yaml + when: verb == "remove" diff --git a/roles/iptrunks/templates/isis_interface.j2 b/roles/iptrunks/templates/isis_interface.j2 new file mode 100644 index 0000000000000000000000000000000000000000..a2f40ad302b34eb939c60b158d4fd071ebb042a7 --- /dev/null +++ b/roles/iptrunks/templates/isis_interface.j2 @@ -0,0 +1,34 @@ +{##} +{# Template to update the isis stanza with new interface #} +{# It is included in isis.j2 when the playbook calling is cic_isis #} +{##} +{% if ansible_play_name != 'cic_isis' %} +protocols { + isis { +{% endif %} + {% for trunk in trunks %} + {% if inventory_hostname == trunk.config.nodeA.name %} + {% set interface_name= trunk.config.nodeA.ae_name %} + {% set isis_metric= trunk.config.common.isis_metric %} + {% endif %} + {% if inventory_hostname == trunk.config.nodeB.name %} + {% set interface_name= trunk.config.nodeB.ae_name %} + {% set isis_metric= trunk.config.common.isis_metric %} + {% endif %} + {% if interface_name is defined %} +replace: interface {{ interface_name }}.0 { + point-to-point; + level 2 { + post-convergence-lfa { + node-protection; + } + metric {{ isis_metric }}; + } + } + + {% endif %} + {% endfor %} +{% if ansible_play_name != 'cic_isis' %} + } +} +{% endif %} diff --git a/roles/iptrunks/templates/ldp_interface.j2 b/roles/iptrunks/templates/ldp_interface.j2 new file mode 100644 index 0000000000000000000000000000000000000000..a74af1e22db1eecb195dd2e670aeddbc34b8a4fa --- /dev/null +++ b/roles/iptrunks/templates/ldp_interface.j2 @@ -0,0 +1,25 @@ +{##} +{# Template to update the ldp stanza with new interface #} +{# It is included in isis.j2 when the playbook calling is cic_isis #} +{##} +{% if ansible_play_name != 'cic_isis' %} +protocols { + ldp { +{% endif %} + {% for trunk in trunks %} + {% if inventory_hostname == trunk.config.nodeA.name %} + {% set interface_name= trunk.config.nodeA.ae_name %} + {% set isis_metric= trunk.config.common.isis_metric %} + {% endif %} + {% if inventory_hostname == trunk.config.nodeB.name %} + {% set interface_name= trunk.config.nodeB.ae_name %} + {% set isis_metric= trunk.config.common.isis_metric %} + {% endif %} + {% if interface_name is defined %} +replace: interface {{ interface_name }}.0 ; + {% endif %} + {% endfor %} +{% if ansible_play_name != 'cic_isis' %} + } +} +{% endif %} diff --git a/roles/iptrunks/templates/lldp_interface.j2 b/roles/iptrunks/templates/lldp_interface.j2 new file mode 100644 index 0000000000000000000000000000000000000000..0270e38ac63cf009db7648f275700ac6c4cbe572 --- /dev/null +++ b/roles/iptrunks/templates/lldp_interface.j2 @@ -0,0 +1,29 @@ +{##} +{# Template to update the isis stanza with new interface #} +{# It is included in isis.j2 when the playbook calling is cic_isis #} +{##} +{% if ansible_play_name != 'cic_isis' %} +protocols { + lldp { +{% endif %} +{% for trunk in trunks %} + {% if inventory_hostname == trunk.config.nodeA.name %} + {% set local= trunk.config.nodeA %} + {% set remote= trunk.config.nodeB %} + {% set common= trunk.config.common %} + {% endif %} + {% if inventory_hostname == trunk.config.nodeB.name %} + {% set local= trunk.config.nodeB %} + {% set remote= trunk.config.nodeA %} + {% set common= trunk.config.common %} + {% endif %} + + {% for member in local.members %} + replace: interface {{member}} ; + {% endfor %} + + {% endfor %} +{% if ansible_play_name != 'cic_isis' %} + } +} +{% endif %} diff --git a/roles/iptrunks/templates/trunk_deprovision.j2 b/roles/iptrunks/templates/trunk_deprovision.j2 new file mode 100644 index 0000000000000000000000000000000000000000..4d17cb89c33401b4be6bfd694b17fdd3523ea27c --- /dev/null +++ b/roles/iptrunks/templates/trunk_deprovision.j2 @@ -0,0 +1,19 @@ +{% for trunk in trunks %} + {% if trunk.id == trunk_id %} + {% if inventory_hostname == trunk.config.nodeA.name %} + {% set local= trunk.config.nodeA %} + {% endif %} + {% if inventory_hostname == trunk.config.nodeB.name %} + {% set local= trunk.config.nodeB %} + {% endif %} + {% if local is defined %} + delete protocols isis interface {{ local.ae_name }} + delete protocols ldp interface {{ local.ae_name }} + delete interfaces {{ local.ae_name }} + {% for iface in local.members %} + delete interfaces {{ iface }} + delete protocols lldp interface {{ iface }} + {% endfor %} + {% endif %} + {% endif %} +{% endfor %} diff --git a/roles/iptrunks/templates/trunk_interface.j2 b/roles/iptrunks/templates/trunk_interface.j2 new file mode 100644 index 0000000000000000000000000000000000000000..be1d0930195592cd8445c95a30c4f4249cfa4a6a --- /dev/null +++ b/roles/iptrunks/templates/trunk_interface.j2 @@ -0,0 +1,79 @@ +{##} +{# Template to deploy a trunk interface, takes care of configuring Aggregated Ethernet and the physical interface(s) contained #} +{# It is included in isis.j2 when the playbook calling is cic_isis #} +{##} +{% for trunk in trunks %} + {% if inventory_hostname == trunk.config.nodeA.name %} + {% set local= trunk.config.nodeA %} + {% set remote= trunk.config.nodeB %} + {% set common= trunk.config.common %} + {% endif %} + {% if inventory_hostname == trunk.config.nodeB.name %} + {% set local= trunk.config.nodeB %} + {% set remote= trunk.config.nodeA %} + {% set common= trunk.config.common %} + {% endif %} + + {% if local is defined %} + {##} + {# I need to sort the source and the destination alfabetically #} + {% set trunk_direction_name = [ local.name.split(".")[1] | upper, remote.name.split(".")[1] | upper ] %} + {% set trunk_direction_name_sorted = trunk_direction_name|sort %} + {##} + interfaces { + replace: {{local.ae_name}} { + description "LAG INFRASTRUCTURE BACKBONE ${{ local.port_sid }} | {{ trunk_direction_name_sorted[0] }}-{{ trunk_direction_name_sorted[1] }}"; + mtu 9192; + aggregated-ether-options { + bfd-liveness-detection { + minimum-interval 3000; + neighbor {{ hostvars[remote.name]['lo_ipv4_address'] }}; + local-address {{lo_ipv4_address}}; + } + minimum-links {{common.minimum_links}}; + {#link-speed {{common.link_speed}};#} + lacp { + active; + periodic fast; + } + } + unit 0 { + description "SRV_GLOBAL INFRASTRUCTURE BACKBONE #{{ trunk_direction_name_sorted[0] }}-{{ trunk_direction_name_sorted[1] }}-IPTRUNK ${{ trunk.id }}| {{ trunk_direction_name_sorted[0] }}-{{ trunk_direction_name_sorted[1] }}"; + family inet { + accounting { + source-class-usage { + input; + } + } + mtu 9000; + filter { + input bone-in; + output bone-out; + } + address {{local.ipv4_address}}; + } + family iso; + family inet6 { + mtu 9000; + filter { + input bone6-in; + output bone6-out; + } + address {{local.ipv6_address}}; + } + family mpls { + maximum-labels 5; + } + } + } + {% for member in local.members %} + replace: {{member}} { + description "PHY INFRASTRUCTURE BACKBONE P_{{local.ae_name}} | {{ trunk_direction_name_sorted[0] }}-{{ trunk_direction_name_sorted[1] }}"; + gigether-options { + 802.3ad {{local.ae_name}}; + } + } + {% endfor %} + } + {% endif %} +{% endfor %} diff --git a/roles/iptrunks/tests/inventory b/roles/iptrunks/tests/inventory new file mode 100644 index 0000000000000000000000000000000000000000..878877b0776c44f55fc4e458f70840f31da5bb01 --- /dev/null +++ b/roles/iptrunks/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/roles/iptrunks/tests/test.yml b/roles/iptrunks/tests/test.yml new file mode 100644 index 0000000000000000000000000000000000000000..b5d07419dc3229229c1b5c571ce003f60dc138ce --- /dev/null +++ b/roles/iptrunks/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - iptrunks diff --git a/roles/iptrunks/vars/main.yml b/roles/iptrunks/vars/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..9db90dcf8598896a426b4b0f4d173a3b2e3f5f50 --- /dev/null +++ b/roles/iptrunks/vars/main.yml @@ -0,0 +1,16 @@ +--- +# vars file for iptrunks +dryrun: "True" +### Here I am selecting the single trunk I want to deploy +newtrunks: "{{ trunks | selectattr('id', 'match', trunk_id ) | list }}" +verbs: + - "compile" + - "deploy" + - "remove" +config_objects: + - "trunk_interface" + - "isis" + - "isis_interface" + - "ldp_interface" + - "lldp_interface" + - "trunk_deprovision"