{"id":7716,"date":"2024-11-05T09:34:52","date_gmt":"2024-11-05T15:34:52","guid":{"rendered":"https:\/\/gregsowell.com\/?p=7716"},"modified":"2024-11-05T09:34:52","modified_gmt":"2024-11-05T15:34:52","slug":"ansible-import-vs-include-whats-the-real-difference","status":"publish","type":"post","link":"https:\/\/gregsowell.com\/?p=7716","title":{"rendered":"Ansible Import Vs Include&#8230;What&#8217;s The Real Difference?"},"content":{"rendered":"<p>There are three module types that can be either imported or included which are: import\/include_task, import\/include_role, or import\/include_playbook.<br \/>\nWhile these are mostly the same there are some subtle differences&#8230;so subtle in fact that I couldn&#8217;t really figure out what the difference was, so why not share what I&#8217;ve learned \ud83d\ude42<\/p>\n<p>So the textbook difference between the two is that:<br \/>\n<strong>Import<\/strong> is static.  This means they are fully loaded before playbook execution begins.<br \/>\n<strong>Include<\/strong> is dynamic.  This means they are parsed during execution as they are reached.<\/p>\n<p>I&#8217;m not sure how this reads to you, but my understanding was that variables and the like would be interpreted strangely for imports&#8230;kind of like whatever the value of a variable was at load would somehow dictate their inclusion or reaction&#8230;which was wrong.  Here&#8217;s a playbook I wrote to try and test:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\"># playbook.yml\r\n---\r\n- name: A demo on using include vs import in Ansible with incorrect info\r\n  hosts: localhost\r\n  gather_facts: false\r\n  vars:\r\n    testvar: &quot;Initial Value&quot;  # Initial value for the variable\r\n  tasks:\r\n    - name: Display initial testvar value\r\n      ansible.builtin.debug:\r\n        msg: &quot;Before import_tasks and include_tasks: testvar is {{ testvar }}&quot;\r\n\r\n    - name: Use import_tasks (static)\r\n      import_tasks: tasks\/import-tasks.yml\r\n\r\n    - name: Update testvar to &quot;Updated Value&quot;\r\n      set_fact:\r\n        testvar: &quot;Updated Value&quot;\r\n\r\n    - name: Use include_tasks (dynamic)\r\n      include_tasks: tasks\/include-tasks.yml\r\n\r\n    - name: Re-run import_tasks after update\r\n      import_tasks: tasks\/import-tasks.yml<\/code><\/pre>\n<p>Here are the two task files it calls(really they are just spitting out debug info&#8230;nothing special here):<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\"># tasks\/import-tasks.yml\r\n- name: Import Task Display testvar if it is &quot;Updated Value&quot;\r\n  ansible.builtin.debug:\r\n    msg: &quot;Import Task: testvar is {{ testvar }}&quot;\r\n  when: testvar == &quot;Updated Value&quot;<\/code><\/pre>\n<pre class=\"gs-code\"><code class=\"language-plaintext\"># tasks\/include-tasks.yml\r\n- name: Include Task Display testvar if it is &quot;Updated Value&quot;\r\n  ansible.builtin.debug:\r\n    msg: &quot;Include Task: testvar is {{ testvar }}&quot;\r\n  when: testvar == &quot;Updated Value&quot;<\/code><\/pre>\n<p>I was thinking that in the above example it wouldn&#8217;t run any of the imports(as at runtime the variable would have been set incorrectly).  Take a look at the job output, though:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">PLAY [A demo on using include vs import in Ansible with incorrect info] ********\r\nTASK [Display initial testvar value] *******************************************\r\nok: [localhost] =&gt; {\r\n    &quot;msg&quot;: &quot;Before import_tasks and include_tasks: testvar is Initial Value&quot;\r\n}\r\nTASK [Import Task Display testvar if it is &quot;Updated Value&quot;] ********************\r\nskipping: [localhost]\r\nTASK [Update testvar to &quot;Updated Value&quot;] ***************************************\r\nok: [localhost]\r\nTASK [Use include_tasks (dynamic)] *********************************************\r\nincluded: \/runner\/project\/tasks\/include-tasks.yml for localhost\r\nTASK [Include Task Display testvar if it is &quot;Updated Value&quot;] *******************<\/code><\/pre>\n<p>I tried all kinds of variations, but no matter what, I couldn&#8217;t get it to fail.  It ignored the first import as one would expect, but when I reset the variable it went ahead and ran the second import&#8230;So, I surrender trying to make it functionally display their differences.  There are a few things that are definetly different as per <a href=\"https:\/\/docs.ansible.com\/ansible\/2.9\/user_guide\/playbooks_reuse.html#tradeoffs-and-pitfalls-between-includes-and-imports\">this documentation<\/a>:<\/p>\n<p><strong>Using include* <\/strong>does have some limitations when compared to import* statements:<\/p>\n<li>Tags which only exist inside a dynamic include will not show up in &#8211;list-tags output.<\/li>\n<li>Tasks which only exist inside a dynamic include will not show up in &#8211;list-tasks output.<\/li>\n<li>You cannot use notify to trigger a handler name which comes from inside a dynamic include (see note below).<\/li>\n<li>You cannot use &#8211;start-at-task to begin execution at a task inside a dynamic include.<\/li>\n<ul> <\/ul>\n<ul> <\/ul>\n<p><strong>Using import*<\/strong> can also have some limitations when compared to dynamic includes:<\/p>\n<li>As noted above, loops cannot be used with imports at all.<\/li>\n<li>When using variables for the target file or role name, variables from inventory sources (host\/group vars, etc.) cannot be used.<\/li>\n<li>Handlers using import* will not be triggered when notified by their name, as importing overwrites the handler\u2019s named task with the imported task list.<\/li>\n<ul> <\/ul>\n<ul> <\/ul>\n<p>Looking at the plus&#8217; and minus&#8217; of each, <strong>just go with include by default<\/strong>.<br \/>\nMost of the shortcomings of include are things I never run into, so not really a problem.<br \/>\nThe shortcomings of import are much more impactful: not being able to use it with loops and losing inventory source variables.<\/p>\n<h2>Conclusion<\/h2>\n<p>In short, <strong>use include<\/strong> and just ignore the import stuff.<br \/>\nIf you have any other topics of interest, let me know.  If you would tweak or tune this, drop me a note on that too.<br \/>\nGood luck out there; happy automating, and happy including!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are three module types that can be either imported or included which are: import\/include_task, import\/include_role, or import\/include_playbook. While these are mostly the same\u2026<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49],"tags":[],"class_list":["post-7716","post","type-post","status-publish","format-standard","hentry","category-ansible"],"_links":{"self":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7716","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7716"}],"version-history":[{"count":12,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7716\/revisions"}],"predecessor-version":[{"id":7728,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7716\/revisions\/7728"}],"wp:attachment":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7716"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7716"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7716"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}