{"id":4336,"library":"ansible-runner","title":"Ansible Runner","description":"Ansible Runner is a Python library and command-line tool designed to provide a consistent and stable interface for executing Ansible directly or as part of another system. It abstracts away the complexities of managing Ansible execution, handling artifact storage, and providing event-driven output. This makes it ideal for embedding Ansible within CI/CD platforms, web applications, or other automation tooling. The current version is 2.4.3, with an active development and release cadence, often aligning with updates to the broader Ansible ecosystem.","status":"active","version":"2.4.3","language":"en","source_language":"en","source_url":"https://github.com/ansible/ansible-runner","tags":["ansible","automation","orchestration","runner","containerization","execution-environment","api"],"install":[{"cmd":"pip install ansible-runner","lang":"bash","label":"Install from PyPI"}],"dependencies":[{"reason":"Ansible Runner executes Ansible commands; therefore, an Ansible installation (typically ansible-core) is required in the environment where ansible-runner is run. This might be a local installation or within a containerized execution environment.","package":"ansible-core","optional":false}],"imports":[{"note":"This is the primary function for executing Ansible playbooks or ad-hoc commands.","symbol":"run","correct":"from ansible_runner import run"},{"note":"Used for more advanced, fine-grained control over the Ansible execution lifecycle and access to results. The `run` function is a helper around this class.","symbol":"Runner","correct":"from ansible_runner.runner import Runner"}],"quickstart":{"code":"import ansible_runner\nimport os\nimport tempfile\nimport shutil\n\n# Create a temporary directory for ansible-runner's private_data_dir\nwith tempfile.TemporaryDirectory() as private_data_dir:\n    # Create project/ and inventory/ subdirectories\n    project_dir = os.path.join(private_data_dir, 'project')\n    inventory_dir = os.path.join(private_data_dir, 'inventory')\n    os.makedirs(project_dir, exist_ok=True)\n    os.makedirs(inventory_dir, exist_ok=True)\n\n    # Write a simple Ansible playbook\n    playbook_content = '''\n- name: Test playbook\n  hosts: localhost\n  connection: local\n  tasks:\n    - name: Print a message\n      ansible.builtin.debug:\n        msg: \"Hello from Ansible Runner!\"\n    - name: Verify an environment variable (optional)\n      ansible.builtin.debug:\n        msg: \"TEST_VAR is {{ lookup('env', 'TEST_VAR') }}\"\n      when: lookup('env', 'TEST_VAR') | length > 0\n'''\n    with open(os.path.join(project_dir, 'test_playbook.yml'), 'w') as f:\n        f.write(playbook_content)\n\n    # Write a simple inventory file\n    inventory_content = '''\nlocalhost ansible_connection=local\n'''\n    with open(os.path.join(inventory_dir, 'hosts'), 'w') as f:\n        f.write(inventory_content)\n\n    # Set an optional environment variable for the playbook to consume\n    os.environ['TEST_VAR'] = os.environ.get('MY_ANSIBLE_RUNNER_TEST_VAR', 'DefaultValueFromRunner')\n\n    print(f\"Running Ansible playbook in: {private_data_dir}\")\n\n    # Run the playbook using ansible-runner\n    r = ansible_runner.run(\n        private_data_dir=private_data_dir,\n        playbook='test_playbook.yml',\n        quiet=False # Set to True to suppress stdout from Ansible process\n    )\n\n    print(f\"\\nAnsible Runner Status: {r.status}\")\n    print(f\"Ansible Runner Return Code: {r.rc}\")\n\n    if r.stdout:\n        print(\"\\n--- Ansible Playbook Output ---\")\n        # You can access stdout as a file-like object or iterate through events\n        # For simplicity, let's print the entire stdout content\n        stdout_path = os.path.join(r.artifact_dir, 'stdout')\n        if os.path.exists(stdout_path):\n            with open(stdout_path, 'r') as f:\n                print(f.read())\n        else:\n            print(\"Stdout file not found.\")\n\n    if r.stderr:\n        print(\"\\n--- Ansible Playbook Error Output ---\")\n        stderr_path = os.path.join(r.artifact_dir, 'stderr')\n        if os.path.exists(stderr_path):\n            with open(stderr_path, 'r') as f:\n                print(f.read())\n        else:\n            print(\"Stderr file not found.\")\n\n    # Clean up the environment variable\n    del os.environ['TEST_VAR']\n","lang":"python","description":"This quickstart demonstrates how to use `ansible_runner.run` to execute a simple Ansible playbook. It sets up a temporary `private_data_dir` with a basic project and inventory structure, runs a playbook that prints a debug message, and then reports the execution status and output."},"warnings":[{"fix":"Ensure your Python environment is version 3.9 or later before installing or upgrading `ansible-runner`.","message":"Ansible Runner 2.4.0 and later requires Python 3.9 or newer. Older versions supported Python 3.8 and earlier. Attempting to use newer `ansible-runner` versions with older Python interpreters will result in errors.","severity":"breaking","affected_versions":"2.4.0+"},{"fix":"Review existing container volume mounts, especially those involving non-existent source paths, and test behavior with your chosen container engine. Adjust as needed for Docker vs. Podman specifics.","message":"Starting with Ansible Runner 2.4.1, the `container-volume-mount` option now passes volume specifications directly to the underlying container engine (Docker/Podman) unverified and unmodified. This change allows mounting individual files or non-existing source volumes, but the behavior for non-existing sources now depends on the specific container engine (Docker creates, Podman errors).","severity":"breaking","affected_versions":"2.4.1+"},{"fix":"Consult the `ansible-runner` changelog and documentation for `2.4.3` regarding callback plugin API changes and update your custom callback plugins to use the `get_option` API correctly.","message":"Ansible Runner 2.4.3 introduced changes in how custom callback plugins should use the `get_option` API. If you have custom callback plugins, they might need updates to align with this new API usage, potentially causing issues with older implementations.","severity":"breaking","affected_versions":"2.4.3+"},{"fix":"Always organize your Ansible content within the `private_data_dir` according to `ansible-runner`'s expected hierarchy. Refer to the official documentation for the complete structure.","message":"Ansible Runner expects a specific directory structure within the `private_data_dir` (e.g., `project/` for playbooks and roles, `inventory/` for hosts, `env/` for extra vars, passwords, etc.). Misconfigurations in this structure are a common source of 'file not found' or 'playbook not found' errors.","severity":"gotcha","affected_versions":"All"},{"fix":"If SSH issues arise with Execution Environments, consider explicitly mounting your `~/.ssh/` directory or ensuring that any symlinked SSH keys are within mounted paths using the `container_volume_mounts` API option or CLI flags.","message":"When using `ansible-runner` with containerized Execution Environments, SSH agent forwarding (`SSH_AUTH_SOCK`) might not work as expected if `~/.ssh/` files are symlinked to unmounted directories. Manual volume mounting might be necessary.","severity":"gotcha","affected_versions":"All (when using containerization)"}],"env_vars":null,"last_verified":"2026-04-12T00:00:00.000Z","next_check":"2026-07-11T00:00:00.000Z"}