{"id":20022914,"url":"https://github.com/lfkdev/ansible-link","last_synced_at":"2025-05-05T01:31:40.686Z","repository":{"id":245884814,"uuid":"819443965","full_name":"lfkdev/ansible-link","owner":"lfkdev","description":"RESTful API for executing Ansible playbooks remotely","archived":false,"fork":false,"pushed_at":"2024-07-02T22:06:47.000Z","size":296,"stargazers_count":18,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-08T15:04:48.647Z","etag":null,"topics":["ansible","ansible-playbook","cicd","flask-restx","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lfkdev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-24T14:11:23.000Z","updated_at":"2024-12-09T18:11:09.000Z","dependencies_parsed_at":"2024-06-24T17:06:48.453Z","dependency_job_id":null,"html_url":"https://github.com/lfkdev/ansible-link","commit_stats":null,"previous_names":["lfkdev/ansible-link"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfkdev%2Fansible-link","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfkdev%2Fansible-link/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfkdev%2Fansible-link/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lfkdev%2Fansible-link/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lfkdev","download_url":"https://codeload.github.com/lfkdev/ansible-link/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252423319,"owners_count":21745567,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","ansible-playbook","cicd","flask-restx","python"],"created_at":"2024-11-13T08:43:46.862Z","updated_at":"2025-05-05T01:31:39.333Z","avatar_url":"https://github.com/lfkdev.png","language":"Python","readme":"\u003cdiv align=\"center\" style=\"display: flex; align-items: center;\"\u003e\n  \u003cimg src=\"logo.png\" alt=\"Ansible Link Logo\" width=\"100\" height=\"100\" style=\"margin-right: 20px;\"\u003e\n  \u003cdiv\u003e\n    \u003ch1\u003eANSIBLE LINK\u003c/h1\u003e\n    \u003cp\u003e\n      RESTful API for executing Ansible playbooks remotely\n    \u003c/p\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Python-3.7%2B-blue\" alt=\"Python\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Platform-Linux-lightgrey\" alt=\"Linux\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Flask--RESTx-Swagger-green\" alt=\"Flask-RESTx\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Ansible--Runner-1.4-red\" alt=\"Ansible Runner\"\u003e\n\u003c/p\u003e\n\n## Features\n- **Playbook Execution** Asynchronous playbook executions with real-time status updates.\n- **Playbook History** Keep track of playbook executions and their status.\n- **API Documentation** Swagger UI documentation for easy exploration of the API endpoints.\n- **Metrics** Exposes Prometheus metrics for playbook runs, durations, and active jobs.\n- **Webhook Notifications** Send notifications to Slack, Discord, or custom webhooks for job events.\n\n\u003cb\u003eNOTE\u003c/b\u003e Project is usable but still in early development.\n\n## Motivation\nSearched 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](https://github.com/ansible/ansible-runner).\n\n## Prerequisites\n* Ansible CLI installed\n* Your playbooks and inventory files\n\n## Installation\nThe fastest way to set up Ansible-Link is by using the provided `install.sh` script:\n\n**Download and run the install script:**\n```shell\nwget https://raw.githubusercontent.com/lfkdev/ansible-link/main/install.sh\nsudo bash install.sh\n```\n\nThis script will:\n- Check for necessary dependencies and install them if missing.\n- Download and install Ansible-Link.\n- Set up a Python virtual environment.\n- Configure a systemd service for Ansible-Link.\n\nAfter 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`\n\n```yaml\nplaybook_dir: '/etc/ansible/'\ninventory_file: '/etc/ansible/environments/hosts'\n...\n```\n\nTo add more workers or change the user, modify `/etc/systemd/system/ansible-link.service`\n\u003e ⚠️ **Note:** Currently, only Ubuntu versions 16.04 and higher, or Debian versions 9 and higher are officially supported. \n\u003e 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.\n\n## API Documentation\nThe API documentation is available via the Swagger UI.\n\n\u003cimg src=\"docs.png\" alt=\"Ansible Link Docs\"\u003e\n\n## API Endpoints\n\n* \u003ccode\u003ePOST /ansible/playbook: Execute a playbook\u003c/code\u003e\n* \u003ccode\u003eGET /ansible/jobs: List all jobs\u003c/code\u003e\n* \u003ccode\u003eGET /ansible/job/\u003cjob_id\u003e: Get job status\u003c/code\u003e\n* \u003ccode\u003eGET /ansible/job/\u003cjob_id\u003e/output: Get job output\u003c/code\u003e\n* \u003ccode\u003eGET /health: Health check endpoint\u003c/code\u003e\n\n## Configuration\nThe API configuration is stored in the `config.yml` file. \nIf you move your config to a different location you can use `ANSIBLE_LINK_CONFIG_PATH` \n```shell\n$ export ANSIBLE_LINK_CONFIG_PATH='/etc/ansible-link/config.yml'\n```\n\nYou can customize the following settings:\n\n```yaml\n# webhook\n# webhook:\n#   url: \"https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK\"\n#   type: \"slack\" # \"slack\", \"discord\" or \"generic\" supported\n#   timeout: 5  # optional, default 5 seconds\n\n# flask\nhost: '127.0.0.1'\nport: 5001\ndebug: false\n\n# ansible-runner\nsuppress_ansible_output: false\nomit_event_data: false\nonly_failed_event_data: false\n\n# promtetheus\nmetrics_port: 9090\n\n# general\nplaybook_dir: '/etc/ansible/'\ninventory_file: '/etc/ansible/environments/hosts'\njob_storage_dir: '/var/lib/ansible-link/job-storage'\nlog_level: 'INFO'\n\n# ansible-link\nplaybook_whitelist: []\n# playbook_whitelist:\n#   - monitoring.yml\n#   - mariadb.yml\n```\n\nThe whitelist supports \u003cb\u003efull regex\u003c/b\u003e, you could go wild:\n```yaml\nplaybook_whitelist:\n  # Allow all playbooks in the 'test' directory\n  - ^test/.*\\.ya?ml$\n\n  # Allow playbooks starting with 'prod_' or 'dev_'\n  - ^(prod|dev)_.*\\.ya?ml$\n\n  # Allow specific playbooks\n  - ^(backup|restore|maintenance)\\.ya?ml$\n```\nLeave empty to allow all playbooks. This is for the backend, you could also use the `limit` arg from ansible-runner in the request directly.\n\n## Prod environment\n\nYou can use the install script `install.sh` to get a production-ready environment for Ansible-Link.\n\nThe install script will:\n- Set up a Python VENV\n- Configure a systemd service to manage Ansible-Link\n- Utilize Gunicorn as the WSGI server\n- Start Ansible-Link to liste only on localhost\n\nYou can use a webserver like Caddy to add Basic Authentication and TLS to your Ansible-Link setup.\n\nAlso, if you're using a webserver, you can change Gunicorn to use sockets instead. For example:\n```shell\nExecStart=$VENV_DIR/bin/gunicorn --workers 1 --bind unix:$INSTALL_DIR/ansible_link.sock -m 007 wsgi:application\n```\n\n\n### unitD example\n```\n[Unit]\nDescription=Ansible Link Service\nAfter=network.target\n\n[Service]\nExecStart=$VENV_DIR/bin/gunicorn --workers 1 --bind 127.0.0.1:$ANSIBLE_LINK_PORT wsgi:application\nWorkingDirectory=$INSTALL_DIR\nRestart=always\nUser=root\n\n[Install]\nWantedBy=multi-user.target\n```\n\n### Example setup:\n```\n├── etc/\n│   └── ansible/\n│       ├── playbooks/\n│       │   └── some_playbooks.yml\n│       └── inventory/\n│           ├── production\n│           └── staging\n│\n├── opt/\n│   └── ansible-link/\n│       ├── ansible-link.py\n│       └── config.yml\n│\n└── var/\n    └── lib/\n        └── ansible-link/\n            └── job-storage/\n                └── playbook_name_20230624_130000_job_id.json\n```\n\n## Webhook Configuration\nAnsible-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:\n\n```yaml\nwebhook:\n  url: \"https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK\"\n  type: \"slack\"  # Options: slack, discord, generic\n  timeout: 5  # Optional, defaults to 5 seconds\n```\n\nor leave it commented out to disable webhooks\n\n* **url** The webhook URL for your chosen platform.\n* **type** The type of webhook (slack, discord, or generic).\n* **timeout** The timeout for webhook requests in seconds (optional, default is 5 seconds).\n\nOnly Slack and Discord are supported for now, you can also use `generic` which will send the base JSON payload:\n\n```json\n{\n    \"event_type\": event_type,\n    \"job_id\": job_data['job_id'],\n    \"playbook\": job_data['playbook'],\n    \"status\": job_data['status'],\n    \"timestamp\": datetime.now().isoformat()\n}\n```\n\nThe following notifcations are sent:\n\n* Job Started\n* Job Completed (success or failure)\n* Job Error\n\nView `webhook.py` for more info.\n\n## Usage\n\nBelow are examples demonstrating how to use ansible-link API compared to Ansible CLI.\n\n---\n```bash\n$ ansible-playbook site.yml\n```\n\n```json\n{\n  \"playbook\": \"site.yml\"\n}\n```\n\n```bash\ncurl -X POST http://your-ansible-link-server/ansible/playbook \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"playbook\": \"site.yml\"}'\n```\n---\n\n```bash\n$ ansible-playbook deploy.yml -e version=1.5.0 environment=staging\n```\n\n```json\n{\n  \"playbook\": \"deploy.yml\",\n  \"vars\": {\n    \"version\": \"1.5.0\",\n    \"environment\": \"staging\"\n  }\n}\n```\n---\n\n```bash\n$ ansible-playbook site.yml --tags \"update,packages\" -vv\n```\n\n```json\n{\n  \"playbook\": \"site.yml\",\n  \"tags\": \"update,packages\",\n  \"verbosity\": 2\n}\n```\n---\n\n```bash\n$ ansible-playbook restore.yml --limit \"databases\" --forks 3\n```\n\n```json\n{\n  \"playbook\": \"restore.yml\",\n  \"limit\": \"databases\",\n  \"forks\": 3\n}\n```\n\n---\n```bash\n$ ansible-playbook site.yml -i custom_inventory.ini -e '{\"key1\": \"value1\", \"key2\": \"value2\"}' --tags \"provision,configure\" --skip-tags \"cleanup\" --limit \"webservers:\u0026staged\" --forks 10 -vvv\n```\n\n```json\n{\n  \"playbook\": \"site.yml\",\n  \"inventory\": \"custom_inventory.ini\",\n  \"vars\": {\n    \"key1\": \"value1\",\n    \"key2\": \"value2\"\n  },\n  \"tags\": \"provision,configure\",\n  \"skip_tags\": \"cleanup\",\n  \"limit\": \"webservers:\u0026staged\",\n  \"forks\": 10,\n  \"verbosity\": 3\n}\n```\n\n--- \n\n```bash\n$ ansible-playbook site.yml -i custom_inventory.ini -e environment=production --diff --check\n```\n\n```json\n{\n  \"playbook\": \"site.yml\",\n  \"inventory\": \"custom_inventory.ini\",\n  \"vars\": {\n    \"environment\": \"production\"\n  },\n  \"cmdline\": \"--diff --check\"\n}\n```\nAnsible-Link supports the following native parameters:\n\n* playbook: The name of the playbook to run (required)\n* inventory: Path to the inventory file\n* vars (extravars): A dictionary of additional variables to pass to the playbook\n* limit: A host pattern to further constrain the list of hosts\n* verbosity: Control the output level of ansible-playbook\n* forks: Specify number of parallel processes to use\n* tags: Only run plays and tasks tagged with these values\n* skip_tags: Only run plays and tasks whose tags do not match these values\n* cmdline: Any additional command line options to pass to ansible-playbook\n\nWhich means you can always use cmdline if your arg is not natively supported, like:\n\n```json\n{\n  \"playbook\": \"site.yml\",\n  \"cmdline\": \"--diff --check -e environment=production -i /etc/ansible/test/custom_inventory.ini\"\n}\n```\n\n### Output\nAnsible-Link will save each job as .json with the following info (from ansible-runner):\n```json\n{\n  \"status\": \"successfull\",\n  \"playbook\": \"\u003cplaybook_name\u003e\",\n  \"inventory\": null,\n  \"vars\": {\n    \"customer\": \"emind\"\n  },\n \"start_time\": \"2024-06-24T15:32:35.380662\",\n  \"stdout\": \"\u003cANSIBLE PLAYBOOK OUTPUT\u003e\",\n  \"stderr\": \"\",\n  \"stats\": {\n    \"skipped\": {\n      \"\u003cplaybook_name\u003e\": 8\n    },\n    \"ok\": {\n      \"\u003cplaybook_name\u003e\": 28\n    },\n    \"dark\": {},\n    \"failures\": {\n      \"\u003cplaybook_name\u003e\": 1\n    },\n    \"ignored\": {},\n    \"rescued\": {},\n    \"processed\": {\n      \"\u003cplaybook_name\u003e\": 1\n    },\n    \"changed\": {}\n  }\n}\n```\nessentially showing everything ansible-playbook would display.\n\n\u003cb\u003eNote\u003c/b\u003e 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/\u003cjob_id\u003e and /ansible/job/\u003cjob_id\u003e/output endpoints respectively.\n\n## Metrics\nAnsible-Link exposes the following metrics:\n\n```python\nPLAYBOOK_RUNS = Counter('ansible_link_playbook_runs_total', 'Total number of playbook runs', ['playbook', 'status'])\nPLAYBOOK_DURATION = Histogram('ansible_link_playbook_duration_seconds', 'Duration of playbook runs in seconds', ['playbook'])\nACTIVE_JOBS = Gauge('ansible_link_active_jobs', 'Number of currently active jobs')\n```\n\nThe metrics can be used to set alerts, track the history of jobs, monitor performance and so on\n\n## Security Considerations\n* Use TLS in production\n* Add basic auth\n\n## Contributing\nContributions are always welcome - if you find any issues or have suggestions for improvements, please open an issue or submit a pull request.\n\n## License\nThis project is licensed under the MPL2 License. See the LICENSE file for more information.\n\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flfkdev%2Fansible-link","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flfkdev%2Fansible-link","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flfkdev%2Fansible-link/lists"}