{"id":9488,"date":"2025-02-06T01:05:00","date_gmt":"2025-02-06T06:05:00","guid":{"rendered":"https:\/\/www.both.org\/?p=9488"},"modified":"2025-02-06T06:11:56","modified_gmt":"2025-02-06T11:11:56","slug":"fixing-ansible-playbooks","status":"publish","type":"post","link":"https:\/\/www.both.org\/?p=9488","title":{"rendered":"Fixing Ansible playbooks"},"content":{"rendered":"<div class=\"pld-like-dislike-wrap pld-template-1\">\r\n    <div class=\"pld-like-wrap  pld-common-wrap\">\r\n    <a href=\"javascript:void(0)\" class=\"pld-like-trigger pld-like-dislike-trigger  \" title=\"\" data-post-id=\"9488\" data-trigger-type=\"like\" data-restriction=\"cookie\" data-already-liked=\"0\">\r\n                        <i class=\"fas fa-thumbs-up\"><\/i>\r\n                <\/a>\r\n    <span class=\"pld-like-count-wrap pld-count-wrap\">    <\/span>\r\n<\/div><\/div>\n<p>I&#8217;ve been using <a href=\"https:\/\/www.both.org\/?p=4262\" data-type=\"link\" data-id=\"https:\/\/www.both.org\/?p=4262\" target=\"_blank\" rel=\"noreferrer noopener\">Ansible<\/a> for several years to perform different tasks on my many physical and virtual hosts. It&#8217;s an excellent tool for defining the state to be set on a number of computers. <\/p>\n\n\n\n<p>I have several playbooks I use frequently, one of which I use to perform post-installation personalization and configuration of physical and virtual Linux hosts. This PostInstall.yml playbook has worked well for several years. Until recently when it began throwing errors.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The problem<\/h2>\n\n\n\n<p>The first time I would run it on a host, it would work as it should. But, if after a few weeks of testing and research on that host, I would run the playbook again to restore the configuration items in the playbook to their desired state, it would fail with this error.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>TASK &#91;Install command line tools] ****************************************************\nfatal: &#91;testvm1]: FAILED! =&gt; {\"changed\": false, \"failures\": &#91;\"Packages for argument 'task' available, but not installed.\"], \"msg\": \"Failed to install some of the specified packages\", \"rc\": 1}<\/code><\/pre>\n\n\n\n<p>I inspected the failing task, reproduced here in part, but could find no problems with the structure or syntax.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install command line tools\n- name: Install command line tools\n  dnf:\n    name:\n      - apcupsd\n      - atop\n      - bc\n      - clamav\n      - ddrescue\n&lt;SNIP&gt;\n      - whois\n    state: latest<\/code><\/pre>\n\n\n\n<p>I tried a number of different things to resolve the problem and none of them worked. Thinking that one of the packages was causing the problem,I even tried installing all of the packages using DNF on the command line. They all installed correctly with no problems.<\/p>\n\n\n\n<p>I&#8217;d been searching the Internet for clues and found one indication that this problem is due to an issue between DNF5 and the fact that the python3-libdnf5 package should be installed by default, but was not on the new installations. Installing that did not resolve the problem. <\/p>\n\n\n\n<p>Further research led me to a new (to me) tool.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">ansible-lint<\/h2>\n\n\n\n<p>The <a href=\"https:\/\/ansible.readthedocs.io\/projects\/lint\/\" data-type=\"link\" data-id=\"https:\/\/ansible.readthedocs.io\/projects\/lint\/\" target=\"_blank\" rel=\"noreferrer noopener\">ansible-lint<\/a> tool, like most lint-style tools, is designed to promote best practices in syntax, tool usage, and structure. I installed it easily as it it&#8217;s in the Fedora repo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># <strong>dnf -y install python3-ansible-lint<\/strong><\/code><\/pre>\n\n\n\n<p>I immediately ran this tool against my playbook and it reported over 200 errors. Some were simple format errors that didn&#8217;t seem to effect the results, but were egregious offenses against the strict YAML formatting, such as improper indentation, trailing spaces, and more. Other failures turned out to be the ones causing my problem. <\/p>\n\n\n\n<p>I&#8217;ve only included a small bit of the output from this command here, but it gives you a good idea of what you&#8217;ll see in the output data stream. I used the &#8211;nocolor option to eliminate all the escape characters that contaminate the data, and the -p option to make the data stream easier to read. I&#8217;m using the original version of my file here with all its errors.  The revised version doesn&#8217;t have the &#8220;X-&#8221; prepending it. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$ ansible-lint --nocolor -p X-PostInstall.yml 2&amp;&gt; ansible.log\n&lt;SNIP&gt;\nX-PostInstall.yml:150: fqcn&#91;action-core]: Use FQCN for builtin module actions (copy).\nX-PostInstall.yml:154: yaml&#91;octal-values]: Forbidden implicit octal value \"0774\"\nX-PostInstall.yml:158: yaml&#91;indentation]: Wrong indentation: expected 8 but found 10\nX-PostInstall.yml:168: fqcn&#91;action-core]: Use FQCN for builtin module actions (systemd).\nX-PostInstall.yml:172: yaml&#91;trailing-spaces]: Trailing spaces\nX-PostInstall.yml:172: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:173: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:175: fqcn&#91;action-core]: Use FQCN for builtin module actions (systemd).\nX-PostInstall.yml:179: yaml&#91;trailing-spaces]: Trailing spaces\nX-PostInstall.yml:179: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:180: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:183: fqcn&#91;action-core]: Use FQCN for builtin module actions (systemd).\nX-PostInstall.yml:187: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:188: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:203: fqcn&#91;action-core]: Use FQCN for builtin module actions (copy).\nX-PostInstall.yml:203: risky-octal: `mode: 644` should have a string value with leading zero `mode: \"01204\"` or use symbolic mode.\nX-PostInstall.yml:207: yaml&#91;colons]: Too many spaces after colon\nX-PostInstall.yml:207: yaml&#91;trailing-spaces]: Trailing spaces\nX-PostInstall.yml:212: fqcn&#91;action-core]: Use FQCN for builtin module actions (command).\nX-PostInstall.yml:212: no-changed-when: Commands should not change things if nothing needs doing.\nX-PostInstall.yml:217: fqcn&#91;action-core]: Use FQCN for builtin module actions (systemd).\nX-PostInstall.yml:221: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:228: fqcn&#91;action-core]: Use FQCN for builtin module actions (systemd).\nX-PostInstall.yml:232: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:233: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:235: fqcn&#91;action-core]: Use FQCN for builtin module actions (systemd).\nX-PostInstall.yml:239: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:240: yaml&#91;truthy]: Truthy value should be one of\nX-PostInstall.yml:249: fqcn&#91;action-core]: Use FQCN for builtin module actions (copy).\nX-PostInstall.yml:249: risky-octal: `mode: 644` should have a string value with leading zero `mode: \"01204\"` or use symbolic mode.\nX-PostInstall.yml:253: yaml&#91;colons]: Too many spaces after colon\nX-PostInstall.yml:257: fqcn&#91;action-core]: Use FQCN for builtin module actions (copy).\nX-PostInstall.yml:257: risky-octal: `mode: 754` should have a string value with leading zero `mode: \"01362\"` or use symbolic mode.\nX-PostInstall.yml:261: yaml&#91;colons]: Too many spaces after colon\n&lt;SNIP&gt;\nX-PostInstall.yml:1066: fqcn&#91;action-core]: Use FQCN for builtin module actions (reboot).\nX-PostInstall.yml:1066: yaml&#91;trailing-spaces]: Trailing spaces\nRead documentation for instructions on how to ignore specific rule violations.\n\nRule Violation Summary\ncount tag                     profile    rule associated tags\n    1 load-failure&#91;not-found] min        core, unskippable\n    1 no-free-form            basic      syntax, risk\n    1 name&#91;missing]           basic      idiom\n    5 var-naming&#91;pattern]     basic      idiom\n    6 yaml&#91;colons]            basic      formatting, yaml\n    1 yaml&#91;comments]          basic      formatting, yaml\n    7 yaml&#91;indentation]       basic      formatting, yaml\n    1 yaml&#91;octal-values]      basic      formatting, yaml\n   39 yaml&#91;trailing-spaces]   basic      formatting, yaml\n   28 yaml&#91;truthy]            basic      formatting, yaml\n   12 name&#91;casing]            moderate   idiom\n   16 package-latest          safety     idempotency\n    5 risky-octal             safety     formatting\n    7 no-changed-when         shared     command-shell, idempotency\n   67 fqcn&#91;action-core]       production formatting\n\nFailed: 217 failure(s), 0 warning(s) on 2 files.\n                                              <\/code><\/pre>\n\n\n\n<p>The acronym FQCN stands for &#8220;fully qualified command name.&#8221; These messages are telling us to use the long Ansible commands such as ansible.builtin.copy instead of just copy. Without the -p option, we get more explicit descriptions that even indicate what we need to do to fix the error. The line numbers, 180, 183, and 187, allowed me to zero in on the errors very quickly.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>yaml&#91;truthy]: Truthy value should be one of &#91;false, true]\nX-PostInstall.yml:180\n\nfqcn&#91;action-core]: Use FQCN for builtin module actions (systemd).\nX-PostInstall.yml:183 Use `ansible.builtin.systemd` or `ansible.legacy.systemd` instead.\n\nyaml&#91;truthy]: Truthy value should be one of &#91;false, true]\nX-PostInstall.yml:187<\/code><\/pre>\n\n\n\n<p>The &#8220;Truthy&#8221; errors are due to my use of &#8220;yes&#8221; or &#8220;no&#8221; instead of &#8220;true&#8221; or &#8220;false&#8221; in some of the logic variables and comparison tests. Because there are a lot of similar errors of each of the different types listed, I can use <strong>Vim<\/strong> or <strong><a href=\"https:\/\/www.both.org\/?p=9447\" data-type=\"link\" data-id=\"https:\/\/www.both.org\/?p=9447\" target=\"_blank\" rel=\"noreferrer noopener\">sed<\/a><\/strong> regular expressions to fix all like errors at once rather than dealing with them one at a time. <\/p>\n\n\n\n<p>The error that was causing the problem I encountered was when I used <strong>state: latest<\/strong> when installing new packages. I switched to <strong>state: present<\/strong>, added <strong>skip_broken: true<\/strong> to each task, and used the FQCN, <strong>ansible.builtin.dnf<\/strong>:. It now works perfectly both for new installs and old installs that needed a reset to the beginning state. The task now looks like this..<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Install command line tools\n- name: Install command line tools\n  ansible.builtin.dnf:\n    name:\n      - apcupsd\n      - atop\n      - bc\n      - clamav\n      - ddrescue\n&lt;SNIP&gt;\n      - whois\n    state: present\n    skip_broken: true<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Final comments<\/h2>\n\n\n\n<p>After fixing the problem &#8212; and many of the less critical errors &#8212; there were still many errors left in my playbook. I&#8217;m still working my way through all of them to ensure they&#8217;re all fixed and can&#8217;t cause future issues.<\/p>\n\n\n\n<p>The ansible-lint tool is easy to use and can find those pesky issues that can&#8217;t be easily seen by the mark I Eyeball. It also helped me learn to code my playbooks using syntax like FQCN for commands rather than short names, and using the present state rather than latest. It&#8217;s those cool little things that I needed to know that helped the most.<\/p>\n\n\n\n<p>Be sure to read the ansible-lint documentation becuase it has some interesting options including one that can allegedly fix many of the errors it encounters. I say &#8220;allegedly&#8221; because I haven&#8217;t yet tried this option. <\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Resources<\/h2>\n\n\n\n<p>I wrote the following articles here on Both.org to help you get started with Ansible if you haven&#8217;t already. <\/p>\n\n\n\n<ol id=\"block-684fc464-bc24-484a-8d52-65344c9047d3\" class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.both.org\/?p=4262\">Ansible #1: My first day using Ansible<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.both.org\/?p=5087\">Ansible #2 How to create an Ansible Playbook<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.both.org\/?p=5179\">Ansible #3: Finishing our Ansible playbook to manage workstation and server updates<\/a><\/li>\n<\/ol>\n\n\n\n<p>Here&#8217;s some articles to get you started with regular expressions (REGEX).<\/p>\n\n\n\n<ol id=\"block-684fc464-bc24-484a-8d52-65344c9047d3\" class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.both.org\/?p=5117\" data-type=\"link\" data-id=\"https:\/\/www.both.org\/?p=5117\" target=\"_blank\" rel=\"noreferrer noopener\">Regular Expressions #1: Introduction<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.both.org\/?p=5154\" target=\"_blank\" rel=\"noreferrer noopener\">Regular Expressions #2: An example<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.both.org\/?p=5190\" target=\"_blank\" rel=\"noreferrer noopener\">Regular Expressions #3: grep \u2014 Data flow and building blocks<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.both.org\/?p=5213\">Regular Expressions #4: Pulling it all together<\/a><\/li>\n<\/ol>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&rsquo;ve been using Ansible for several years to perform different tasks on my many physical and virtual hosts.<\/p>\n","protected":false},"author":2,"featured_media":2813,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_lmt_disableupdate":"","_lmt_disable":"","footnotes":""},"categories":[295,5,158],"tags":[296,702,701],"class_list":["post-9488","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ansible","category-linux","category-open-source","tag-ansible","tag-ansible-lint","tag-yaml"],"modified_by":"David Both","_links":{"self":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/9488","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=9488"}],"version-history":[{"count":28,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/9488\/revisions"}],"predecessor-version":[{"id":9524,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/posts\/9488\/revisions\/9524"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=\/wp\/v2\/media\/2813"}],"wp:attachment":[{"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=9488"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=9488"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.both.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=9488"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}