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

Initial commit

parents
Branches
Tags
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