{"id":169199,"date":"2026-06-19T08:32:06","date_gmt":"2026-06-19T05:32:06","guid":{"rendered":"https:\/\/computingforgeeks.com\/?p=169199"},"modified":"2026-06-19T08:32:06","modified_gmt":"2026-06-19T05:32:06","slug":"install-ansible-opensuse-leap","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/install-ansible-opensuse-leap\/","title":{"rendered":"Install Ansible on openSUSE Leap 16"},"content":{"rendered":"<p>You want to automate a few openSUSE boxes without hand-editing config on each one. Ansible is the clean way to do it: agentless, push over SSH, and the control node is the only machine that needs anything installed. This guide covers how to install Ansible on openSUSE Leap 16, run an ad-hoc command, and execute a real playbook, with the actual output from a Leap 16 control node.<\/p>\n\n<p>Leap 16 carries Ansible in its own repositories, so there is no PPA or pip dance to get a working setup. Every command below was run on a Leap 16 machine before writing it up.<\/p>\n\n<p><em>Ran through this on openSUSE Leap 16 in June 2026; the playbook is idempotent end to end.<\/em><\/p>\n\n<h2>1. Install Ansible<\/h2>\n\n<p>The package is in <code>repo-oss<\/code>, the default repository, so a single zypper command pulls in Ansible and its dependencies:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>sudo zypper install ansible<\/code><\/pre>\n\n\n<p>This installs two things worth knowing about: <code>ansible-core<\/code> (the engine and CLI) and the larger <code>ansible<\/code> package (the community bundle of collections on top). Confirm what you got:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>ansible --version<\/code><\/pre>\n\n\n<p>The control node reports the core version and the Python it will use:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>ansible [core 2.18.3]\n  config file = None\n  python version = 3.13<\/code><\/pre>\n\n\n<p>With the control node ready, give it something to do.<\/p>\n\n<h2>2. Run your first ad-hoc command<\/h2>\n\n<p>Before writing a playbook, prove Ansible can reach a host and run a module. The simplest target is the control node itself with a local connection. The <code>ping<\/code> module here is not ICMP; it checks that Ansible can log in and run Python on the target:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>ansible -i 'localhost,' localhost -m ping -c local<\/code><\/pre>\n\n\n<p>You get a green SUCCESS with a <code>pong<\/code>, alongside a warning about Python interpreter discovery that we come back to in troubleshooting:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>[WARNING]: Platform linux on host localhost is using the discovered Python\ninterpreter at \/usr\/bin\/python3.13, but future installation of another Python\ninterpreter could change the meaning of that path.\nlocalhost | SUCCESS => {\n    \"changed\": false,\n    \"ping\": \"pong\"\n}<\/code><\/pre>\n\n\n<p>For real work you point Ansible at remote hosts over SSH instead of a local connection. That means an inventory file listing the hosts and an SSH key the control node can use to reach them, which is exactly what the next step sets up.<\/p>\n\n<h2>3. Write and run a playbook<\/h2>\n\n<p>Create a working directory and an inventory file. For this walkthrough the inventory points at the local machine, but the same file scales to a list of remote hosts under a group:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>mkdir -p ~\/ansible-demo &amp;&amp; cd ~\/ansible-demo\nprintf '[local]\\nlocalhost ansible_connection=local\\n' &gt; inventory.ini<\/code><\/pre>\n\n\n<p>Now the playbook. Open a new file:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>vim site.yml<\/code><\/pre>\n\n\n<p>Add a play with two tasks: one that prints a fact Ansible gathered about the host, and one that writes a file. The file task is the kind of thing you will use constantly:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>---\n- name: Demo play on openSUSE Leap 16\n  hosts: local\n  gather_facts: true\n  tasks:\n    - name: Show the distribution\n      ansible.builtin.debug:\n        msg: \"Running on {{ ansible_distribution }} {{ ansible_distribution_version }}\"\n\n    - name: Create a marker file\n      ansible.builtin.copy:\n        content: \"Managed by Ansible on openSUSE Leap 16\\n\"\n        dest: \"{{ ansible_env.HOME }}\/ansible-demo\/managed.txt\"\n        mode: '0644'<\/code><\/pre>\n\n\n<p>Run it against the inventory:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>ansible-playbook -i inventory.ini site.yml<\/code><\/pre>\n\n\n<p>Ansible gathers facts, prints the distribution from a variable, creates the file, and ends with a recap. The <code>changed=1<\/code> is the marker file being written:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>TASK [Show the distribution] ***************************************************\nok: [localhost] =&gt; {\n    \"msg\": \"Running on openSUSE Leap 16.0\"\n}\n\nTASK [Create a marker file] ****************************************************\nchanged: [localhost]\n\nPLAY RECAP *********************************************************************\nlocalhost  : ok=3  changed=1  unreachable=0  failed=0<\/code><\/pre>\n\n\n<p>The thing that makes Ansible worth using is idempotency. Run the exact same playbook again and the file task reports no change, because the file already matches what you asked for:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>PLAY RECAP *********************************************************************\nlocalhost  : ok=3  changed=0  unreachable=0  failed=0<\/code><\/pre>\n\n\n<p>The screenshot below shows the version check, the ad-hoc ping, and the playbook run together.<\/p>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"980\" height=\"560\" src=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-ansible-playbook-run-opensuse-leap.png\" alt=\"ansible --version ad-hoc ping and playbook PLAY RECAP on openSUSE Leap 16\" class=\"wp-image-169198\" title=\"\" srcset=\"https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-ansible-playbook-run-opensuse-leap.png 980w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-ansible-playbook-run-opensuse-leap-300x171.png 300w, https:\/\/computingforgeeks.com\/wp-content\/uploads\/2026\/06\/wm-ansible-playbook-run-opensuse-leap-768x439.png 768w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><\/figure>\n\n\n<p>Modules like the copy task come from collections, and the full install ships a large set of them.<\/p>\n\n<h2>4. Use Ansible Galaxy collections<\/h2>\n\n<p>The big advantage of installing the full <code>ansible<\/code> package rather than just <code>ansible-core<\/code> is that it ships hundreds of modules grouped into collections. List what came bundled:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>ansible-galaxy collection list<\/code><\/pre>\n\n\n<p>You already have the workhorses, including the Docker and general-purpose collections:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>ansible.posix       1.6.2\nansible.utils       5.1.2\ncommunity.docker    4.4.0\ncommunity.general   10.4.0<\/code><\/pre>\n\n\n<p>When you need something not bundled, pull it from Galaxy. This installs the cryptography collection used for managing certificates and keys:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>ansible-galaxy collection install community.crypto<\/code><\/pre>\n\n\n<p>If a collection is already part of the bundle, Galaxy tells you there is nothing to do rather than reinstalling it. That is why the <code>community.docker<\/code> collection pairs cleanly with a <a href=\"https:\/\/computingforgeeks.com\/install-docker-podman-opensuse-leap\/\">Docker setup on the same host<\/a>.<\/p>\n\n<h2>Troubleshooting<\/h2>\n\n<p>Two snags come up on a fresh Leap 16 control node, and both are quick.<\/p>\n\n<h3>The Python interpreter discovery warning<\/h3>\n\n<p>Every run prints a warning that Ansible discovered Python at <code>\/usr\/bin\/python3.13<\/code> and that a future install could change that path. It is harmless, but it clutters output. Silence it by telling Ansible exactly which interpreter to use, either per-host in the inventory or globally. Add this line to the host or group in <code>inventory.ini<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>localhost ansible_connection=local ansible_python_interpreter=\/usr\/bin\/python3.13<\/code><\/pre>\n\n\n<p>The second snag is about defaults rather than noise.<\/p>\n\n<h3>No config file by default<\/h3>\n\n<p>On a fresh install, <code>ansible --version<\/code> shows <code>config file = None<\/code>. Ansible runs fine without one, but you lose a place to set sensible defaults. Drop a project-local <code>ansible.cfg<\/code> in your working directory so it is picked up automatically:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>vim ansible.cfg<\/code><\/pre>\n\n\n<p>A minimal config that points at your inventory and quiets the interpreter warning for the whole project:<\/p>\n\n\n<pre class=\"wp-block-code code\"><code>[defaults]\ninventory = .\/inventory.ini\ninterpreter_python = \/usr\/bin\/python3.13\nhost_key_checking = False<\/code><\/pre>\n\n\n<p>With that in place you can drop the <code>-i inventory.ini<\/code> from every command. From here, point the inventory at your real fleet and Ansible manages them all from this one control node. If you are still setting up the box, the <a href=\"https:\/\/computingforgeeks.com\/opensuse-leap-initial-server-setup\/\">initial server setup<\/a> guide covers the SSH keys those remote hosts will need.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You want to automate a few openSUSE boxes without hand-editing config on each one. Ansible is the clean way to do it: agentless, push over SSH, and the control node is the only machine that needs anything installed. This guide covers how to install Ansible on openSUSE Leap 16, run an ad-hoc command, and execute &#8230; <a title=\"Install Ansible on openSUSE Leap 16\" class=\"read-more\" href=\"https:\/\/computingforgeeks.com\/install-ansible-opensuse-leap\/\" aria-label=\"Read more about Install Ansible on openSUSE Leap 16\">Read more<\/a><\/p>\n","protected":false},"author":7,"featured_media":169200,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[606,329,299,47],"tags":[314,282,9986],"cfg_series":[39887],"class_list":["post-169199","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ansible","category-automation","category-how-to","category-linux","tag-ansible","tag-linux","tag-opensuse","cfg_series-opensuse-leap-16"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/169199","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=169199"}],"version-history":[{"count":1,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/169199\/revisions"}],"predecessor-version":[{"id":169223,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/169199\/revisions\/169223"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/169200"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=169199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=169199"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=169199"},{"taxonomy":"cfg_series","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/cfg_series?post=169199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}