- Playbook Execution Asynchronous playbook executions with real-time status updates.
- Playbook History Keep track of playbook executions and their status.
- API Documentation Swagger UI documentation for easy exploration of the API endpoints.
- Metrics Exposes Prometheus metrics for playbook runs, durations, and active jobs.
- Webhook Notifications Send notifications to Slack, Discord, or custom webhooks for job events.
NOTE Project is usable but still in early development.
Searched for a way to run our playbooks automated without the need of AWX or other big projects while still being more stable and less error-prone than custom bash scripts. So I made Ansible-Link. This projects aims to be a KISS way to run ansible jobs remotely. Essentially a RESTful API sitting on top of ansible-runner.
- Ansible CLI installed
- Your playbooks and inventory files
The fastest way to set up Ansible-Link is by using the provided install.sh script:
Download and run the install script:
wget https://raw.githubusercontent.com/lfkdev/ansible-link/main/install.sh sudo bash install.shThis script will:
- Check for necessary dependencies and install them if missing.
- Download and install Ansible-Link.
- Set up a Python virtual environment.
- Configure a systemd service for Ansible-Link.
After the installation, you can start using Ansible-Link immediately. You probably need to change some config values for your ansible environment /opt/ansible-link/config.yml
playbook_dir: '/etc/ansible/' inventory_file: '/etc/ansible/environments/hosts' ...To add more workers or change the user, modify /etc/systemd/system/ansible-link.service
⚠️ Note: Currently, only Ubuntu versions 16.04 and higher, or Debian versions 9 and higher are officially supported. Other operating systems might also work but have not been tested. You can clone the repository and perform a manual installation if you are using a different OS.
The API documentation is available via the Swagger UI.
POST /ansible/playbook: Execute a playbookGET /ansible/jobs: List all jobsGET /ansible/job/<job_id>: Get job statusGET /ansible/job/<job_id>/output: Get job outputGET /health: Health check endpoint
The API configuration is stored in the config.yml file. If you move your config to a different location you can use ANSIBLE_LINK_CONFIG_PATH
$ export ANSIBLE_LINK_CONFIG_PATH='/etc/ansible-link/config.yml'You can customize the following settings:
# webhook # webhook: # url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK" # type: "slack" # "slack", "discord" or "generic" supported # timeout: 5 # optional, default 5 seconds # flask host: '127.0.0.1' port: 5001 debug: false # ansible-runner suppress_ansible_output: false omit_event_data: false only_failed_event_data: false # promtetheus metrics_port: 9090 # general playbook_dir: '/etc/ansible/' inventory_file: '/etc/ansible/environments/hosts' job_storage_dir: '/var/lib/ansible-link/job-storage' log_level: 'INFO' # ansible-link playbook_whitelist: [] # playbook_whitelist: # - monitoring.yml # - mariadb.ymlThe whitelist supports full regex, you could go wild:
playbook_whitelist: # Allow all playbooks in the 'test' directory - ^test/.*\.ya?ml$ # Allow playbooks starting with 'prod_' or 'dev_' - ^(prod|dev)_.*\.ya?ml$ # Allow specific playbooks - ^(backup|restore|maintenance)\.ya?ml$Leave empty to allow all playbooks. This is for the backend, you could also use the limit arg from ansible-runner in the request directly.
You can use the install script install.sh to get a production-ready environment for Ansible-Link.
The install script will:
- Set up a Python VENV
- Configure a systemd service to manage Ansible-Link
- Utilize Gunicorn as the WSGI server
- Start Ansible-Link to liste only on localhost
You can use a webserver like Caddy to add Basic Authentication and TLS to your Ansible-Link setup.
Also, if you're using a webserver, you can change Gunicorn to use sockets instead. For example:
ExecStart=$VENV_DIR/bin/gunicorn --workers 1 --bind unix:$INSTALL_DIR/ansible_link.sock -m 007 wsgi:application[Unit] Description=Ansible Link Service After=network.target [Service] ExecStart=$VENV_DIR/bin/gunicorn --workers 1 --bind 127.0.0.1:$ANSIBLE_LINK_PORT wsgi:application WorkingDirectory=$INSTALL_DIR Restart=always User=root [Install] WantedBy=multi-user.target ├── etc/ │ └── ansible/ │ ├── playbooks/ │ │ └── some_playbooks.yml │ └── inventory/ │ ├── production │ └── staging │ ├── opt/ │ └── ansible-link/ │ ├── ansible-link.py │ └── config.yml │ └── var/ └── lib/ └── ansible-link/ └── job-storage/ └── playbook_name_20230624_130000_job_id.json Ansible-Link supports sending webhook notifications for job events. You can configure webhooks for Slack, Discord, or a generic endpoint. Add the following to your config.yml:
webhook: url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK" type: "slack" # Options: slack, discord, generic timeout: 5 # Optional, defaults to 5 secondsor leave it commented out to disable webhooks
- url The webhook URL for your chosen platform.
- type The type of webhook (slack, discord, or generic).
- timeout The timeout for webhook requests in seconds (optional, default is 5 seconds).
Only Slack and Discord are supported for now, you can also use generic which will send the base JSON payload:
{ "event_type": event_type, "job_id": job_data['job_id'], "playbook": job_data['playbook'], "status": job_data['status'], "timestamp": datetime.now().isoformat() }The following notifcations are sent:
- Job Started
- Job Completed (success or failure)
- Job Error
View webhook.py for more info.
Below are examples demonstrating how to use ansible-link API compared to Ansible CLI.
$ ansible-playbook site.yml{ "playbook": "site.yml" }curl -X POST http://your-ansible-link-server/ansible/playbook \ -H "Content-Type: application/json" \ -d '{"playbook": "site.yml"}'$ ansible-playbook deploy.yml -e version=1.5.0 environment=staging{ "playbook": "deploy.yml", "vars": { "version": "1.5.0", "environment": "staging" } }$ ansible-playbook site.yml --tags "update,packages" -vv{ "playbook": "site.yml", "tags": "update,packages", "verbosity": 2 }$ ansible-playbook restore.yml --limit "databases" --forks 3{ "playbook": "restore.yml", "limit": "databases", "forks": 3 }$ ansible-playbook site.yml -i custom_inventory.ini -e '{"key1": "value1", "key2": "value2"}' --tags "provision,configure" --skip-tags "cleanup" --limit "webservers:&staged" --forks 10 -vvv{ "playbook": "site.yml", "inventory": "custom_inventory.ini", "vars": { "key1": "value1", "key2": "value2" }, "tags": "provision,configure", "skip_tags": "cleanup", "limit": "webservers:&staged", "forks": 10, "verbosity": 3 }$ ansible-playbook site.yml -i custom_inventory.ini -e environment=production --diff --check{ "playbook": "site.yml", "inventory": "custom_inventory.ini", "vars": { "environment": "production" }, "cmdline": "--diff --check" }Ansible-Link supports the following native parameters:
- playbook: The name of the playbook to run (required)
- inventory: Path to the inventory file
- vars (extravars): A dictionary of additional variables to pass to the playbook
- limit: A host pattern to further constrain the list of hosts
- verbosity: Control the output level of ansible-playbook
- forks: Specify number of parallel processes to use
- tags: Only run plays and tasks tagged with these values
- skip_tags: Only run plays and tasks whose tags do not match these values
- cmdline: Any additional command line options to pass to ansible-playbook
Which means you can always use cmdline if your arg is not natively supported, like:
{ "playbook": "site.yml", "cmdline": "--diff --check -e environment=production -i /etc/ansible/test/custom_inventory.ini" }Ansible-Link will save each job as .json with the following info (from ansible-runner):
{ "status": "successfull", "playbook": "<playbook_name>", "inventory": null, "vars": { "customer": "emind" }, "start_time": "2024-06-24T15:32:35.380662", "stdout": "<ANSIBLE PLAYBOOK OUTPUT>", "stderr": "", "stats": { "skipped": { "<playbook_name>": 8 }, "ok": { "<playbook_name>": 28 }, "dark": {}, "failures": { "<playbook_name>": 1 }, "ignored": {}, "rescued": {}, "processed": { "<playbook_name>": 1 }, "changed": {} } }essentially showing everything ansible-playbook would display.
Note After submitting a request to the API, you will receive a job ID. You can use this job ID to check the status and retrieve the output of the playbook run using the /ansible/job/<job_id> and /ansible/job/<job_id>/output endpoints respectively.
Ansible-Link exposes the following metrics:
PLAYBOOK_RUNS = Counter('ansible_link_playbook_runs_total', 'Total number of playbook runs', ['playbook', 'status']) PLAYBOOK_DURATION = Histogram('ansible_link_playbook_duration_seconds', 'Duration of playbook runs in seconds', ['playbook']) ACTIVE_JOBS = Gauge('ansible_link_active_jobs', 'Number of currently active jobs')The metrics can be used to set alerts, track the history of jobs, monitor performance and so on
- Use TLS in production
- Add basic auth
Contributions are always welcome - if you find any issues or have suggestions for improvements, please open an issue or submit a pull request.
This project is licensed under the MPL2 License. See the LICENSE file for more information.

