{"library":"ansible-core","title":"Ansible Core","description":"Ansible Core is the foundational software package that provides the core language, runtime, and built-in plugins for IT automation. It enables configuring systems, deploying software, and orchestrating advanced IT tasks. As of the current version 2.20.4, ansible-core is actively maintained with minor releases occurring approximately every four weeks, and new major versions released roughly twice a year.","status":"active","version":"2.20.4","language":"en","source_language":"en","source_url":"https://github.com/ansible/ansible","tags":["automation","configuration management","orchestration","devops","agentless"],"install":[{"cmd":"pip install ansible-core","lang":"bash","label":"Install with pip"},{"cmd":"pipx install ansible-core","lang":"bash","label":"Install with pipx (recommended for isolation)"}],"dependencies":[{"reason":"Templating engine for playbooks and modules.","package":"Jinja2","optional":false},{"reason":"Used for parsing and emitting YAML, the language for playbooks and inventory.","package":"PyYAML","optional":false},{"reason":"Dependency of Jinja2, used for string formatting and HTML/XML escaping.","package":"MarkupSafe","optional":false}],"imports":[{"note":"Essential for writing custom Ansible modules to handle arguments, return values, and interact with the Ansible runtime.","symbol":"AnsibleModule","correct":"from ansible.module_utils.basic import AnsibleModule"},{"note":"Part of the internal Python API for executing tasks programmatically. Generally, `ansible-runner` is recommended for external programmatic execution.","symbol":"TaskQueueManager","correct":"from ansible.executor.task_queue_manager import TaskQueueManager"},{"note":"Used in the internal Python API to define and execute plays within a playbook programmatically.","symbol":"Play","correct":"from ansible.playbook.play import Play"},{"note":"Base class for creating custom callback plugins to process Ansible execution results.","symbol":"CallbackBase","correct":"from ansible.plugins.callback import CallbackBase"}],"quickstart":{"code":"import json\nimport shutil\nimport os\n\nimport ansible.constants as C\nfrom ansible.executor.task_queue_manager import TaskQueueManager\nfrom ansible.inventory.manager import InventoryManager\nfrom ansible.parsing.dataloader import DataLoader\nfrom ansible.playbook.play import Play\nfrom ansible.plugins.callback import CallbackBase\nfrom ansible.vars.manager import VariableManager\nfrom ansible import context\n\n# NOTE: The Ansible Python API is for internal use and not officially supported for external applications.\n# For robust programmatic execution of playbooks and modules, consider using 'ansible-runner'.\n\n# --- Minimal example to run a simple ad-hoc command --- \n\n# Configure Ansible context (optional, but good practice)\ncontext.CLIARGS = ['ansible', 'all', '-m', 'ping', '-i', 'localhost,'] # Mimics command line args\n\nclass ResultsCollectorJSONCallback(CallbackBase):\n    def __init__(self):\n        self.host_ok = {}\n        self.host_failed = {}\n        self.host_unreachable = {}\n    \n    def v2_runner_on_ok(self, result, **kwargs):\n        self.host_ok[result._host.get_name()] = result._result\n\n    def v2_runner_on_failed(self, result, **kwargs):\n        self.host_failed[result._host.get_name()] = result._result\n\n    def v2_runner_on_unreachable(self, result, **kwargs):\n        self.host_unreachable[result._host.get_name()] = result._result\n\n# initialize needed objects\nloader = DataLoader()\ninv_data = 'localhost ansible_connection=local'\ninventory = InventoryManager(loader=loader, sources=[inv_data])\nvariable_manager = VariableManager(loader=loader, inventory=inventory)\n\n# instantiate our callback plugin\nresults_callback = ResultsCollectorJSONCallback()\n\n# create play with tasks\nplay_source = dict(\n    name=\"Ansible Ad-hoc Ping\",\n    hosts='all',\n    gather_facts='no',\n    tasks=[\n        dict(action=dict(module='ping'), register='ping_result')\n    ]\n)\nplay = Play().load(play_source, variable_manager=variable_manager, loader=loader)\n\n# run it\nt = TaskQueueManager(\n    inventory=inventory,\n    variable_manager=variable_manager,\n    loader=loader,\n    options=context.CLIARGS,\n    passwords={},\n    stdout_callback=results_callback,\n)\n\ntry:\n    status = t.run(play)\nfinally:\n    # cleanup after ourselves\n    if t is not None:\n        t.cleanup()\n    if loader: # DataLoader may delete tmpdir on exit, ensure it's removed if exists\n        if hasattr(loader, '_tempdir') and os.path.exists(loader._tempdir):\n            shutil.rmtree(loader._tempdir)\n\nprint(\"\\n--- Ad-hoc Ping Results ---\")\nprint(f\"OK: {json.dumps(results_callback.host_ok, indent=4)}\")\nprint(f\"Failed: {json.dumps(results_callback.host_failed, indent=4)}\")\nprint(f\"Unreachable: {json.dumps(results_callback.host_unreachable, indent=4)}\")\n","lang":"python","description":"This quickstart demonstrates how to programmatically execute a simple 'ping' ad-hoc command using ansible-core's internal Python API. It sets up an in-memory inventory, defines a simple play, and uses a custom callback to capture results. Note that the Ansible Python API is primarily for internal use, and `ansible-runner` is generally recommended for external programmatic integration."},"warnings":[{"fix":"Review the official porting guides for `ansible-core 2.19` and `Ansible 12` to identify and update affected playbooks and roles.","message":"The `ansible-core 2.19` (and by extension `Ansible 12`) release introduced significant templating changes which may break existing playbooks and roles that relied on previously silently ignored incorrect behavior. You must validate content for compatibility.","severity":"breaking","affected_versions":">=2.19.0"},{"fix":"Explicitly define facts you intend to use as variables in your playbooks or roles, rather than relying on their implicit injection. Consult the `ansible-core 2.20` porting guide.","message":"The `INJECT_FACTS_AS_VARS` feature was deprecated in `ansible-core 2.20`. Relying on injected facts as variables without explicit definition will eventually lead to breakage.","severity":"deprecated","affected_versions":">=2.20.0"},{"fix":"Ensure your control node uses Python 3.9 or newer. The `requires_python` field for `ansible-core` is `>=3.12`.","message":"Support for Python 3.8 on control nodes was removed in `ansible-core 2.20`. Environments running older Python versions will need to be upgraded.","severity":"breaking","affected_versions":">=2.20.0"},{"fix":"For robust programmatic interaction with Ansible (e.g., executing playbooks), consider using `ansible-runner` which provides a stable and supported API.","message":"The Python API of `ansible-core` is primarily intended for internal use and is not officially supported for external applications. Backward compatibility is not guaranteed, and changes may occur at any time.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Explicitly set the `mode` parameter in your `copy`, `file`, and `template` tasks to ensure desired file permissions.","message":"Behavior of `copy`, `file`, and `template` modules regarding file permissions (`mode` vs. `umask`) changed in `Ansible 2.10` and was backported to `2.8.14` and `2.9.12`. This could lead to unexpected file permissions.","severity":"breaking","affected_versions":"2.8.14+, 2.9.12+, >=2.10.0"},{"fix":"When using the `ansible-core` Python API, avoid multi-threaded contexts or implement proper process isolation (e.g., using `multiprocessing`) to prevent unexpected behavior. `ansible-runner` might offer more robust options for concurrent execution.","message":"The `ansible-core` Python API is not thread-safe due to its reliance on forking processes.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-06T20:04:18.711Z","next_check":"2026-07-05T00:00:00.000Z"}