{"id":36594548,"url":"https://github.com/sipgate/ansible-juniper-cookbook","last_synced_at":"2026-01-12T08:26:29.618Z","repository":{"id":42393309,"uuid":"309319208","full_name":"sipgate/ansible-juniper-cookbook","owner":"sipgate","description":"Automate your Juniper Devices with Ansible","archived":false,"fork":false,"pushed_at":"2023-12-15T08:39:11.000Z","size":21,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":19,"default_branch":"main","last_synced_at":"2024-04-14T11:56:50.766Z","etag":null,"topics":["ansible","juniper"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sipgate.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-11-02T09:25:18.000Z","updated_at":"2024-04-14T11:56:50.767Z","dependencies_parsed_at":"2023-12-05T09:55:22.331Z","dependency_job_id":null,"html_url":"https://github.com/sipgate/ansible-juniper-cookbook","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sipgate/ansible-juniper-cookbook","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipgate%2Fansible-juniper-cookbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipgate%2Fansible-juniper-cookbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipgate%2Fansible-juniper-cookbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipgate%2Fansible-juniper-cookbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sipgate","download_url":"https://codeload.github.com/sipgate/ansible-juniper-cookbook/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sipgate%2Fansible-juniper-cookbook/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28337593,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T06:09:07.588Z","status":"ssl_error","status_checked_at":"2026-01-12T06:05:18.301Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","juniper"],"created_at":"2026-01-12T08:26:29.114Z","updated_at":"2026-01-12T08:26:29.611Z","avatar_url":"https://github.com/sipgate.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ansible Juniper Automation Cookbook\n\nThis repository serves as a cookbook/skeleton für Juniper network device automation. It shows you how to...\n\n- ...merge configuration snippets into your Juniper device\n- ...query and evaluate the state of your Juniper device\n- ...use a test driven approach to template development\n- ...validate your `host_vars` and `group_vars` YAML files\n\nHowever, it does not...\n\n- ...try to be a guide to Juniper device configuration - the configuration snippets are only meant to illustrate the automation itself\n- ...assume this is the only way to automate Juniper devices\n\n**Some if not all aspects of this cookbook should also work with other network vendors.**\n\n## Local Prerequisites\n\nThe content of this repository has been tested against Ansible 2.9 and 2.10. You need `ncclient` (the netconf client package) for the Juniper modules to work. To make your life easier, use Python 3 and a virtual environment for your Ansible setup:\n```shell\napt install python3-virtualenv\n\nmkdir -p ~/venv\n\nvirtualenv ~/venv/ansible-netconf\nsource ~/venv/ansible-netconf/bin/activate\n\npip install ansible ncclient netaddr\n```\n\nIf you want to use YAML schema validation, we need the yamale package as well:\n```shell\npip install yamale\n```\n\nIf you want to use the test driven template development apporach, we need pytest and docker:\n```shell\napt install docker.io\npip install pytest docker\n```\n\nYou also need to build the junoser container image locally. The following command will retrieve the XSD configuration definition of the specified JunOS device (using `scp`) and build the image with it. You can optionally use the `-p` parameter to push the image to a specified docker registry, but you need to adapt the [testing code](tests/conftest.py) to reflect the image's location afterwards.\n\n```shell\ncd junoser-container\n./build-docker-container.sh -d your-junos-device.example.com\n```\n\n\n\nThis repository makes use of Ansible collections. To install all dependencies, navigate to the top directory of this repository and issue:\n```shell\nansible-galaxy collection install -r collections/requirements.yml\n```\n\n## Remote Prerequisites\n\nTo start using Ansible you only need very few settings on your Juniper device:\n- a minimal user configuration, e.g. `root` user with a password (do not forget to enable root login!)\n- connectivity for your management interface (e.g. configure an IP address and set a default route if required)\n- enable SSH + netconf:\n```\nset system services ssh \nset system services netconf ssh\n```\n\nIf you use the `root` user for your initial deployment, **do not forget to disable root login after putting your real user configuration in place**! Ideally this would be part of your device's base configuration role in Ansible.\n\n## How to Run a Playbook\n\nIf all requirements are met, you can simply run the following (don't forget to activate your virtual env!):\n```shell\nansible-playbook -i inventory -u root -k access_switch.yml\n```\nThis will asssume you want to login with `root` and it will ask you interactively for your password (`-k`). You can omit `-u` to use your local username instead and of cause also omit `-k` if you authenticate through other means (e.g. SSH keys).\n\nYou can limit the execution of your playbook using `-t` (only run tasks with a given tag) or `-l` (limit to a device group or certain devices):\n```shell\n# only deploy NTP and DNS configuration\nansible-playbook -i inventory -u root -k -t dns,ntp access_switch.yml\n\n# only deploy access-switch01.dc-one.example.com\nansible-playbook -i inventory -u root -k -l access-switch01.dc-one.example.com access_switch.yml\n\n# only deploy vlans to access switches in DC one\nansible-playbook -i inventory -u root -k -t vlans -l dc-one access_switch.yml\n```\n\n## Structure of This Repository\n\n```shell\n.\n├── collections     # contains Ansible collection requirements file\n├── group_vars      # Ansible group variables, e.g. common to a site/location\n├── host_vars       # Ansible host variables, e.g. per device\n├── roles           # Ansible roles\n├── inventory       # Main inventory file for Ansible\n└── *.yml           # Ansible playbooks for device configuration\n```\n\n## General Idea of Device Configuration\n\nInstead of maintaining the entire device configuration in one single template, we make the use of multiple smaller templates. Juniper supports different strategies of applying configuration changes. We use `merge`, where the uploaded configuration gets merged into the currently running configuration. You can give hints to the parser so that it exclusively replaces a subsection but merged everything else: \n```\ninterfaces {\n    replace:\n    ge-0/0/0 {\n        unit 0 {\n            family inet {...}\n        }\n    }\n}\n```\nThe above example will be merged into the existing configuration (e.g. will keep all other interfaces) - but will make sure that the interface `ge-0/0/0` gets replaced with the new configuration. This has advantages as well as disadvantages:\n\n- :heavy_plus_sign: smaller templates are easier to maintain and understand\n- :heavy_plus_sign: reuse template code for multiple types of devices (e.g. use a common baseline configuration)\n- :heavy_minus_sign: it is harder to remove parts of the configuration: if you remove e.g. an interface from your YAML data it will not be part of your template - but it will also not be removed from the device unless you use `replace` on the entire `interfaces` section (which might collide with other roles/templates also configuration interfaces). This is not impossible to solve, but will complicate your templates.\n- :heavy_minus_sign: you need to carefully decidce where to use `replace` - otherwise your roles/templates might overwrite each other\n- :warning: especially older devices tend to have long `commit` times - having many templates/commits in your playbooks will make the deployment a major pain. However, we use the `assemble` module of Ansible to merge all templates clientside before commiting which serves as a good workaround\n  \n## YAML Schema Validation\n\nWe use the `yamale` Python module to define schema files for our `host_vars` and `group_vars`. This way we can make sure to have all required variables present before we actually start the configuration deployment. Ansible is not able to detect missing variables before jinja2 tries to access them while rendering the templates (and hence will error out in the middle of your playbook run). At the same time, this will also help us to get rid of unused variables (e.g. which have been removed from templates but kept in the YAML structures). `yamale` also uses YAML to describe the structure/data in your real YAML files, which is documented [here](https://pypi.org/project/yamale/). It comes with predefined validators for basic types like integers, strings, lists, regexes, IP addresses etc.\n\n### Integration into Playbooks\n\nWe use [this Ansible module](https://github.com/sipgate/ansible-module-yamale) to validate all YAML files as `pre_tasks` in our Playbooks. You can find examples for its usage in the [playbooks included in this repoyitory](access_switch.yml).\n\n### Integration into Test Suites\n\nYou can also use a test suite like `pytest` to run schema validation tests - the offical [documentation](https://pypi.org/project/yamale/) has code examples available.\n\n## Test Driven Template Development\n\nWe can use `pytest` and the Ruby gem `junoser` to locally validate and test jinja2 templates for Juniper devices. `junoser` will do the heavy lifting in this case:\n- syntax-check the generated configuration\n- convert to JunOS `set` syntax to have a normalized view for comparing\n\n### How is this Test Driven?\n\nWe can establish a workflow along these lines:\n- define/generate your configuration on a lab device (e.g. the `interfaces` block or only parts of it) and store this as the expected result\n- build a template from this configuration and add it to one of your roles\n- define sample data which can be used to render your template to the desired configuration in step 1\n- integrate the new template into the testsuite\n\nWhen the test passes and you need to change your configuration, follow these steps:\n- adapt your desired configuration to the new needs (and hence break the test)\n- adapt the template (and sample data) until the test passes\n\n### Structure / Assumptions / How to Use?\n\n- templates are stored as usual, e.g. `roles/${role-name}/templates/${template-name}.j2`\n- sample data goes to: `tests/${role-name}/${template-name}.yml`\n- reference/desired output goes to: `tests/${role-name}/${template-name}.conf`\n- adapt [test_templates.py](tests/test_templates.py) to pick up your new template\n- run `pytest` (or use the integrated pytest support in IDEs like PyCharm or Visual Studio Code)\n\n### How does it work underneath?\n\nThe test definition in [test_templates.py](test_templates.py) runs the same procedure on all configured templates:\n- read the YAML configuration file\n- render the jinja2 template with the sample data to a temporary file\n- syntax-check the rendered file with junoser\n- convert both the rendered file and the stored reference configuration to the JunOS `set` syntax and do a string comparison\n\nIf any of the above steps fails, the test for the current template will fail.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsipgate%2Fansible-juniper-cookbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsipgate%2Fansible-juniper-cookbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsipgate%2Fansible-juniper-cookbook/lists"}