<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>A Witchy Chant</title>
    <link>https://witchychant.com/</link>
    <description>Recent content on A Witchy Chant</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <copyright>All rights reserved.</copyright>
    <lastBuildDate>Mon, 20 Jun 2022 15:55:21 -0400</lastBuildDate>
    <atom:link href="https://witchychant.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Ansible Pitfall: Accessing Variables using vars</title>
      <link>https://witchychant.com/ansible-pitfall-vars-variable/</link>
      <pubDate>Mon, 20 Jun 2022 15:55:21 -0400</pubDate>
      <guid>https://witchychant.com/ansible-pitfall-vars-variable/</guid>
      <description>&lt;p&gt;tl;dr: &lt;code&gt;vars&lt;/code&gt; is an undocumented internal variable with surprising&#xA;behaviour. Use &lt;code&gt;foo&lt;/code&gt; instead of &lt;code&gt;vars[&#39;foo&#39;]&lt;/code&gt; and &lt;code&gt;lookup(&#39;vars&#39;, &#39;foo&#39; ~ bar)&lt;/code&gt; instead of &lt;code&gt;vars[&#39;foo&#39; ~ bar]&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;For a long time the only supported way of retrieving&#xA;variables based on an expression was to &lt;a href=&#34;https://docs.ansible.com/ansible-core/2.12/reference_appendices/faq.html#how-do-i-access-a-variable-name-programmatically&#34;&gt;use&#xA;hostvars&lt;/a&gt;.&#xA;This generally works, but not all variables that are in scope are&#xA;present in &lt;code&gt;hostvars&lt;/code&gt;. At some point people learned that you could use&#xA;a dictionary called &lt;code&gt;vars&lt;/code&gt; to access more variables than are present&#xA;in &lt;code&gt;hostvars[inventory_hostname]&lt;/code&gt;:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ansible Hall of Shame: Jinja Loop Counter</title>
      <link>https://witchychant.com/ansible-hall-of-shame-jinja-loop-counter/</link>
      <pubDate>Mon, 10 May 2021 20:23:57 -0400</pubDate>
      <guid>https://witchychant.com/ansible-hall-of-shame-jinja-loop-counter/</guid>
      <description>&lt;p&gt;Someone was working with a Jinja template that they hadn&amp;rsquo;t created and having&#xA;difficulty understanding it, so they brought it to the #ansible IRC channel and&#xA;I hated it so much I had to preserve it for posterity.&lt;/p&gt;&#xA;&lt;p&gt;A slightly simplified version:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{% set count = [1] %}&#xA;{% for item in [&amp;#39;a&amp;#39;, &amp;#39;b&amp;#39;, &amp;#39;c&amp;#39;] %}&#xA;{% for node in [&amp;#39;d&amp;#39;, &amp;#39;e&amp;#39;] %}&#xA;{{ node }}:{{ item }} {{ count | regex_replace(&amp;#39;\[&amp;#39;, &amp;#39;&amp;#39;) | regex_replace(&amp;#39;\]&amp;#39;, &amp;#39;&amp;#39;) }}&#xA;{% if count.append(count.pop() + 1) %}{% endif %}&#xA;{% endfor %}&#xA;{% endfor %}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This produces:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ansible Pattern: Templated Dictionary Keys</title>
      <link>https://witchychant.com/ansible-templated-dictionary-keys/</link>
      <pubDate>Wed, 03 Feb 2021 13:57:34 -0500</pubDate>
      <guid>https://witchychant.com/ansible-templated-dictionary-keys/</guid>
      <description>&lt;p&gt;Except for cases like &lt;code&gt;set_fact&lt;/code&gt; where this functionality has been&#xA;specifically implemented, Ansible does not template dictionary keys.&#xA;This means you cannot do things like this:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Create a frobnitz&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;frobnitz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;frobnicators&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;{{ foo }}&amp;#34;: &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;bar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;templating-dictionaries&#34;&gt;Templating Dictionaries&lt;a href=&#34;#templating-dictionaries&#34; class=&#34;anchor&#34; aria-hidden=&#34;true&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;&lt;path d=&#34;M15 7h3a5 5 0 01 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3&#34;&gt;&lt;/path&gt;&lt;line x1=&#34;8&#34; y1=&#34;12&#34; x2=&#34;16&#34; y2=&#34;12&#34;&gt;&lt;/line&gt;&lt;/svg&gt;&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;As a workaround you can template the entire dictionary. In the&#xA;simplest cases it isn&amp;rsquo;t unbearably ugly to do this inline:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ansible Pattern: Cumulative Inventory Variables</title>
      <link>https://witchychant.com/ansible-cumulative-inventory-variables/</link>
      <pubDate>Sat, 29 Aug 2020 18:00:00 -0400</pubDate>
      <guid>https://witchychant.com/ansible-cumulative-inventory-variables/</guid>
      <description>&lt;p&gt;This is something I&amp;rsquo;ve never actually used, but has come up multiple&#xA;times in #ansible, e.g. &amp;ldquo;I want to add on to a list variable in N places, but&#xA;writing &lt;code&gt;foo: &amp;quot;{{ foo1 + (foo2 | default([])) + (fooN | default([])) }}&amp;quot;&lt;/code&gt;&#xA;is horrible and clunky and I have to know all of the variable names ahead of&#xA;time.&amp;rdquo; Well, we can fix that.&lt;/p&gt;&#xA;&lt;h2 id=&#34;appended-lists&#34;&gt;Appended Lists&lt;a href=&#34;#appended-lists&#34; class=&#34;anchor&#34; aria-hidden=&#34;true&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;&lt;path d=&#34;M15 7h3a5 5 0 01 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3&#34;&gt;&lt;/path&gt;&lt;line x1=&#34;8&#34; y1=&#34;12&#34; x2=&#34;16&#34; y2=&#34;12&#34;&gt;&lt;/line&gt;&lt;/svg&gt;&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;You want to define a base list (e.g. of packages to install), but&#xA;allow membership in a group to add items on to that list? Here&amp;rsquo;s&#xA;an example YAML inventory that does that (you can do this with any&#xA;inventory using &lt;code&gt;group_vars/&lt;/code&gt;, but it&amp;rsquo;s easier to demo in a single&#xA;file):&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ansible Pitfall: Quotes and Strings</title>
      <link>https://witchychant.com/ansible-pitfall-quotes-strings/</link>
      <pubDate>Tue, 28 Jan 2020 14:51:41 -0500</pubDate>
      <guid>https://witchychant.com/ansible-pitfall-quotes-strings/</guid>
      <description>&lt;p&gt;There are at least two levels of parsing that happen when Ansible&#xA;playbooks are run, and the interaction between YAML parsing and Jinja&#xA;causes a lot of confusion.&lt;/p&gt;&#xA;&lt;p&gt;A common inductive leap is to see syntax like &lt;code&gt;foo: &amp;quot;{{ bar }}&amp;quot;&lt;/code&gt; in&#xA;existing Ansible code and conclude that Jinja cares whether your value&#xA;is enclosed in quotes. The truth is that Ansible&amp;rsquo;s Jinja templating&#xA;does not know those quotes existed, because they are part of the&#xA;YAML syntax and do not survive past the initial parsing into a data&#xA;structure.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Jinja FAQ: Nested Moustaches?</title>
      <link>https://witchychant.com/jinja-nested-moustaches/</link>
      <pubDate>Wed, 21 Aug 2019 00:00:00 -0400</pubDate>
      <guid>https://witchychant.com/jinja-nested-moustaches/</guid>
      <description>&lt;p&gt;If you&amp;rsquo;re already in a Jinja statement or expression, you should not use a&#xA;second set of delimiters to set off expressions.&lt;/p&gt;&#xA;&lt;p&gt;Wrong:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ foo[{{ bar }}] }}&#xA;{{ hostvars[&amp;#39;{{ &amp;#39;myhost-&amp;#39; + {{ foo }}&amp;#39;][&amp;#39;bar&amp;#39;] }}&#xA;{{ &amp;#39;{{ foo }}&amp;#39; if bar else &amp;#39;baz&amp;#39; }}&#xA;&#xA;{% set foo == &amp;#34;{{ bar }}foo&amp;#34; %}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Right:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{{ foo[bar] }}&#xA;{{ hostvars[&amp;#39;myhost-&amp;#39; ~ foo][&amp;#39;bar&amp;#39;] }}&#xA;{{ foo if bar else &amp;#39;baz&amp;#39; }}&#xA;&#xA;{% set foo = bar ~ &amp;#39;foo&amp;#39; %}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=&#34;conditionals&#34;&gt;Conditionals&lt;a href=&#34;#conditionals&#34; class=&#34;anchor&#34; aria-hidden=&#34;true&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 24 24&#34; fill=&#34;none&#34; stroke=&#34;currentColor&#34; stroke-width=&#34;2&#34; stroke-linecap=&#34;round&#34; stroke-linejoin=&#34;round&#34;&gt;&lt;path d=&#34;M15 7h3a5 5 0 01 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3&#34;&gt;&lt;/path&gt;&lt;line x1=&#34;8&#34; y1=&#34;12&#34; x2=&#34;16&#34; y2=&#34;12&#34;&gt;&lt;/line&gt;&lt;/svg&gt;&lt;/a&gt;&#xA;&lt;/h1&gt;&#xA;&lt;p&gt;An Ansible-specific twist is that conditional statements are implicitly a&#xA;Jinja context, so you rarely want to include Jinja delimiters in them.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Jinja FAQ: What&#39;s the deal with &#39;~&#39;?</title>
      <link>https://witchychant.com/jinja-faq-concatenation/</link>
      <pubDate>Sun, 06 May 2018 00:00:00 -0400</pubDate>
      <guid>https://witchychant.com/jinja-faq-concatenation/</guid>
      <description>&lt;p&gt;&lt;code&gt;~&lt;/code&gt; is the string concatenation operator. It coerces both sides to strings, then concatenates them.&lt;/p&gt;&#xA;&lt;p&gt;Follow-up question: &amp;ldquo;Doesn&amp;rsquo;t &lt;code&gt;+&lt;/code&gt; concatenate strings? Why not just use that?&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;+&lt;/code&gt; is the addition operator, which is overloaded to mean concatenation when both sides of the expression are strings. While they&amp;rsquo;re often interchangeable, developing a habit of using the concatenation operator means that you don&amp;rsquo;t have to worry about or code around the situations where they&amp;rsquo;re not.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ansible Pitfall: File Modes</title>
      <link>https://witchychant.com/ansible-pitfall-file-modes/</link>
      <pubDate>Mon, 27 Nov 2017 00:00:00 -0500</pubDate>
      <guid>https://witchychant.com/ansible-pitfall-file-modes/</guid>
      <description>&lt;p&gt;tl;dr: To avoid unexpected behaviour, always quote your file modes in&#xA;Ansible tasks and variables.&lt;/p&gt;&#xA;&lt;p&gt;Ansible often exhibits unintuitive behaviour for people who are&#xA;unfamiliar with the intricacies of YAML syntax and parsing, so today&#xA;we&amp;rsquo;re going to explore some of those intricacies by setting a trap for&#xA;the unwary:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- &lt;span class=&#34;nt&#34;&gt;copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;src&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/dev/null&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;dest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/var/tmp/foo&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;mode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0755&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre&gt;&#xA;&lt;span class=&#34;blue &#34;&gt;$&lt;/span&gt; ls -lh /var/tmp/foo&#xA;-rwxr-xr-x 1 root root 0 Nov 27 17:58 &lt;span class=&#34;bold green &#34;&gt;/var/tmp/foo&lt;/span&gt;&#xA;&lt;/pre&gt;&#xA;&lt;p&gt;This is a perfectly valid Ansible task that sets the mode to exactly&#xA;what you would expect. A week later your coworker comes along and&#xA;copies your code, but wants their file to be setuid:&lt;/p&gt;</description>
    </item>
    <item>
      <title>You should use Zstandard for log file compression</title>
      <link>https://witchychant.com/you-should-use-zstandard-for-log-file-compression/</link>
      <pubDate>Thu, 03 Aug 2017 00:00:00 -0400</pubDate>
      <guid>https://witchychant.com/you-should-use-zstandard-for-log-file-compression/</guid>
      <description>&lt;p&gt;(Never heard of Zstandard? Read&#xA;&lt;a href=&#34;https://facebook.github.io/zstd/&#34;&gt;this&lt;/a&gt; after looking at my fancy&#xA;charts.)&lt;/p&gt;&#xA;&lt;p&gt;We ship our logs to a popular log analysis tool that provides a web&#xA;interface and cool data mangling tools, but we also store plaintext&#xA;copies that we occasionally need to refer to. Logs used to be archived&#xA;on individual servers, but during a recent architecture shift we set&#xA;up a centralised aggregation service to preserve logs from ephemeral&#xA;instances. Centralising log storage also centralises log processing,&#xA;and the choice of compression tool matters a lot more than it used&#xA;to when compression and decompression were done in parallel across a&#xA;whole fleet of machines.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
