Skip to content
Snippets Groups Projects
Commit 8f8e94ce authored by Simone Spinelli's avatar Simone Spinelli
Browse files

Initial commit

parents
No related branches found
No related tags found
No related merge requests found
Pipeline #84112 failed
Showing
with 464 additions and 0 deletions
skip_list:
- 'name[template]' # Jinja templates should only be at the end of ‘name’.
- 'role-name[path]' # Avoid using paths when importing roles.
- 'meta-runtime[unsupported-version]' # requires_ansible key must be set to a supported version.
- 'meta-unsupported-ansible' # Required ansible version in meta/runtime.yml must be a supported version.
.vscode
\ No newline at end of file
# This file is a template, and might need editing before it works on your project.
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
# it uses echo commands to simulate the pipeline execution.
#
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
# Stages run in sequential order, but jobs within stages run in parallel.
#
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
#
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
#
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
variables:
release_branch: "release"
target_branche: "main"
stages: # List of stages for jobs, and their order of execution
- setup
- test
- build
- publish
#publish-job: # This job runs in the build stage, which runs first.
# stage: publish
# script:
# - cd geant
# - ansible-galaxy collection publish ops_ansible --api-key $ANSIBLE_VARIABLE_API_KEY
# tags:
# - ansible
# - lab
# rules:
# - if: $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME =~ /^feature/ && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main"
#build-job: # This job runs in the build stage, which runs first.
# stage: build
# script:
# - cd geant
# - ansible-galaxy collection build ops_ansible
# tags:
# - ansible
# - lab
# artifacts:
# paths:
# - ./*.tar.gz
# only:
# - main
lint-test-job: # This job also runs in the test stage.
stage: test # It can run at the same time as unit-test-job (in parallel).
script:
- /home/gitlab-runner/.local/bin/ansible-lint geant/ops_ansible
tags:
- ansible
- lab
install-dependencies:
stage: setup
script:
- ansible-galaxy role install Juniper.junos
tags:
- ansible
- lab
\ No newline at end of file
# geant-ops-ansible
An ansible collection for day by day use and the necessary to install it.
Documentation is available here: TBD.
# Changelog
## 1.0.4 2023-08-04
- Changes in the role 'cic_generic':
- Added support for fixing a stanza: a new verb 'fix' to work with the fix_template.
- Added support for Junos 'system_login' stanza.
## 1.0.3 2023-08-02
- Added cic_generic role to manage the test of arbitrary templates against the network.
- Config push strategy is now template-dependant: you should decide if you want a replace or a merge
- Added email generation for test runs that generates differences
# Ansible Collection - geant.ops_ansible
Documentation is compiled and available here: TBD
# geant.ops_ansible.manage_global_prefix_lists
Role to manage prefix lists that are part of base config and so present in all routers
### REQUIRED
# The namespace of the collection. This can be a company/brand/organization or product namespace under which all
# content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with
# underscores or numbers and cannot contain consecutive underscores
namespace: geant
# The name of the collection. Has the same character restrictions as 'namespace'
name: ops_ansible
# The version of the collection. Must be compatible with semantic versioning
version: 1.0.4
# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
readme: README.md
# A list of the collection's content authors. Can be just the name or in the format 'Full Name <email> (url)
# @nicks:irc/im.site#channel'
authors:
- Simone Spinelli <simone.spinelli@geant.org>
- Aleksandr Kurbatov <aleksandr.kurbatov@geant.org>
### OPTIONAL but strongly recommended
# A short summary description of the collection
description: An Ansible Collection for day to day use
# Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only
# accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file'
license:
- GPL-2.0-or-later
# The path to the license file for the collection. This path is relative to the root of the collection. This key is
# mutually exclusive with 'license'
license_file: ''
# A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character
# requirements as 'namespace' and 'name'
tags: [networking]
# Collections that this collection requires to be installed for it to be usable. The key of the dict is the
# collection label 'namespace.name'. The value is a version range
# L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version
# range specifiers can be set and are separated by ','
dependencies: {}
# The URL of the originating SCM repository
repository: http://example.com/repository
# The URL to any online docs
documentation: http://docs.gap.geant.org
# The URL to the homepage of the collection/project
homepage: http://geant.org
# The URL to the collection issue tracker
issues: http://jira.software.geant.org
# A list of file glob-like patterns used to filter any files or directories that should not be included in the build
# artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This
# uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry',
# and '.git' are always filtered
build_ignore: []
requires_ansible: ">=2.10"
File added
from ansible_merge_vars import ActionModule
- name: Manage global prefix lists
hosts: routers
gather_facts: false
roles:
- Juniper.junos
- ../roles/cic_generic
- name: Manage global prefix lists
hosts: routers
gather_facts: false
roles:
- Juniper.junos
- ../roles/manage_global_prefix_lists
# Collections Plugins Directory
This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that
is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that
would contain module utils and modules respectively.
Here is an example directory of the majority of plugins currently supported by Ansible:
```
└── plugins
├── action
├── become
├── cache
├── callback
├── cliconf
├── connection
├── filter
├── httpapi
├── inventory
├── lookup
├── module_utils
├── modules
├── netconf
├── shell
├── strategy
├── terminal
├── test
└── vars
```
A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.13/plugins/plugins.html).
Configuration Integrity Check - CiC Generic
===========================================
The role is used to check portions of configuration (stanzas)
Requirements
------------
gap_ansible collections should be installed
Role Variables
--------------
Dependencies
------------
Example Playbook
----------------
License
-------
BSD
Author Information
------------------
simone.spinelli@geant.org
ak@geant.org
---
- 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: "{{ config_object }}.j2"
dest: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf"
lstrip_blocks: true
trim_blocks: true
mode: '0755'
delegate_to: localhost
---
- name: Fix "{{ config_object }}" [COMMIT]
juniper_junos_config:
load: "{{ config_objects[config_object].strategy }}"
src: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf"
format: text
config_mode: "private"
check: true
commit: true
comment: "{{ commit_comment }}"
register: response
when: verb == "fix" and not (dry_run | ansible.builtin.bool)
- name: Show diff of "{{ config_object }}"
ansible.builtin.debug:
msg: "{{ response }}"
when: verb == "fix" and not (dry_run | ansible.builtin.bool)
---
# tasks file for cic_generic
- name: Print the usage
ansible.builtin.debug:
msg:
- "Both 'verb' and 'config_object' are required."
- "Allowed verbs: 'compile', 'test'. Use: -e 'verb=$verb'"
- "Allowed objects: 'class_of_service'. Use: -e 'config_object=$config_object'"
when: ((verb is not defined) or (config_object is not defined)) or (verb not in verbs) or (config_object not in config_objects.keys())
- name: Fail if arguments are not correct
ansible.builtin.meta: end_play
when: ((verb is not defined) or (config_object is not defined)) or (verb not in verbs) or (config_object not in config_objects.keys())
- 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: Print the ID
ansible.builtin.debug:
msg: "{{ opid }}"
- name: Include compiling the template
ansible.builtin.include_tasks: compile_template.yaml
when: (verb in verbs)
- name: Include the test tasks if specified
ansible.builtin.include_tasks: test_template.yaml
when: verb == "test"
---
- name: Verify "{{ config_object }}" [CHECK ONLY]
juniper_junos_config:
load: "{{ config_objects[config_object].strategy }}"
src: "/var/tmp/ansible_run_{{ opid }}/{{ config_object }}.conf"
format: text
config_mode: "private"
check: true
commit: false
register: response
when: verb == "test" and (dry_run | ansible.builtin.bool)
- name: Show DRY diff of "{{ config_object }}"
ansible.builtin.debug:
msg: "{{ response }}"
when: verb == "test" and (dry_run | ansible.builtin.bool) and (response.changed | ansible.builtin.bool)
- name: Send an e-mail using Geant SMTP servers
community.general.notification.mail:
host: "{{ cic_alerts_mail_host }}"
port: "{{ cic_alerts_smtp_port }}"
sender: "{{ cic_alerts_sender }}"
to: "{{ cic_alerts_recipient }}"
subject: "Config Integrity Check failed for {{ inventory_hostname }} on {{ config_object }}"
body: "{{ lookup('ansible.builtin.template', 'mail_body.j2') }}"
delegate_to: localhost
when: (response.changed | ansible.builtin.bool) and (send_email | ansible.builtin.bool)
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 %}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment