<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: George Shuklin</title>
    <description>The latest articles on DEV Community by George Shuklin (@amarao).</description>
    <link>https://dev.to/amarao</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3231800%2F204ce328-635f-4193-a4b5-732cbd93fd47.png</url>
      <title>DEV Community: George Shuklin</title>
      <link>https://dev.to/amarao</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/amarao"/>
    <language>en</language>
    <item>
      <title>The tiny twitch which wretch</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Sat, 04 Apr 2026 08:53:52 +0000</pubDate>
      <link>https://dev.to/amarao/the-tiny-twitch-which-wretch-5aln</link>
      <guid>https://dev.to/amarao/the-tiny-twitch-which-wretch-5aln</guid>
      <description>&lt;p&gt;Is Go a good language? (a can of worms opens and closes).&lt;/p&gt;

&lt;p&gt;No, I mean, for the end-user? It turned out that there is one stupid thing which was done odd at argument parsing which makes Go a 'snowflake' language.&lt;/p&gt;

&lt;p&gt;Single-dashed arguments. I presume there were some arguments from developers to allow back single-dash long args (&lt;code&gt;-hello&lt;/code&gt;) instead of double-dash ones (&lt;code&gt;--hello&lt;/code&gt;), but it's just made it... special.&lt;/p&gt;

&lt;p&gt;In a bad way. We accept tar madness (&lt;code&gt;tar vxzf&lt;/code&gt;) out of grand-dad respect, and the same for &lt;code&gt;ar&lt;/code&gt;. But why does a modern language deviate? To set a new standard? Okay, they did it. Now we have a 'go-specific snowflake standard' vs the rest of the software stack. Why? Just because someone thought it would be a good idea to do it ...differently. Now, we have a set of software that has special needs.&lt;/p&gt;

&lt;p&gt;Every time I look up which language a new thing was written in, Go is always, like, 'meh'. Only and only because of their stupid argument parsing library.&lt;/p&gt;

&lt;p&gt;... And gotemplates, but this is more rare and more app-specific. But arguments are... like, why? -why?&lt;/p&gt;

</description>
      <category>go</category>
      <category>linux</category>
    </item>
    <item>
      <title>The most useful command in the age of agentic</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Fri, 27 Mar 2026 10:45:13 +0000</pubDate>
      <link>https://dev.to/amarao/the-most-useful-command-in-the-age-of-agentic-f87</link>
      <guid>https://dev.to/amarao/the-most-useful-command-in-the-age-of-agentic-f87</guid>
      <description>&lt;p&gt;I love when this 'thing' do stuff while I'm doing something else. We discussed, corrected plan, or it is in the middle of investigation, anyway, it's 5+ minutes. And I want to close the lid of the laptop, but continue this thing to work.&lt;/p&gt;

&lt;p&gt;The modern systemd allows me that. This simple script prevent laptop to go to sleep by timeout or by closed lid, as long as it's running. Press Ctrl-C to terminate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemd-inhibit &lt;span class="nt"&gt;--what&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;handle-lid-switch:idle &lt;span class="nt"&gt;--who&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'manual'&lt;/span&gt; &lt;span class="nt"&gt;--why&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'nosleep script'&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;infinity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bingo, you can close lid and have stuff continue to be done.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>ai</category>
    </item>
    <item>
      <title>Someone draw a picture, I updated it</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Thu, 12 Mar 2026 14:37:15 +0000</pubDate>
      <link>https://dev.to/amarao/someone-draw-a-picture-i-updated-2c92</link>
      <guid>https://dev.to/amarao/someone-draw-a-picture-i-updated-2c92</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x9nf7zidje8rqxrs1kp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2x9nf7zidje8rqxrs1kp.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The main difference between computer science and real computers is side effects</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Sat, 17 Jan 2026 09:12:27 +0000</pubDate>
      <link>https://dev.to/amarao/the-main-difference-between-computer-science-and-real-computers-is-side-effects-2poo</link>
      <guid>https://dev.to/amarao/the-main-difference-between-computer-science-and-real-computers-is-side-effects-2poo</guid>
      <description>&lt;p&gt;(from a comment)&lt;/p&gt;

&lt;p&gt;The main difference between computer science models for computers and actual computers is side effects.&lt;/p&gt;

&lt;p&gt;Side effects is what make you able to observe results of computation. There is nothing in CS which allows you to have 'an observer'. Even 'tape' in Turing machine is something you observe, it's a side effect, but it's so perfect, that it always works, there are no jams, no IO timeouts, etc, so it's accepted as perfection (it's also infinite). Same for the final state of machine, which you somehow magically 'observed'.&lt;/p&gt;

&lt;p&gt;So, computer science study computing. And then there are real things out there doing mostly side-effects. For which 'less computation is better'. The more side effects you do (compare to the computations), the better is your program. If you can print (side effect) the answer in 1ms, your program is superior to the program which do computer science things (compute) for 1 minute before printing the same result .&lt;/p&gt;

&lt;p&gt;No one wants computing, we want side effects. We tolerate computing only because there is no other way to make lights to blink in the proper order. &lt;a href="https://xkcd.com/722/" rel="noopener noreferrer"&gt;https://xkcd.com/722/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, every reasoning in CS does not really care about side effects (even if they are studied), CS is all about computing, and computer application is all about side effects.&lt;/p&gt;

&lt;p&gt;So, there is a gap in terminology, different focus, different values, different everything. It is the reason software engineering (the computer part of it, humans aside) is so different from academia writings in any programming language (incl. programming languages itself). &lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>discuss</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vector's VRL introduction (chapter 2)</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Sat, 11 Oct 2025 07:32:40 +0000</pubDate>
      <link>https://dev.to/amarao/vectors-vrl-introduction-chapter-2-14ho</link>
      <guid>https://dev.to/amarao/vectors-vrl-introduction-chapter-2-14ho</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/amarao/vectors-vrl-introduction-chapter-1-30p1"&gt;a previous chapter&lt;/a&gt; we learned how to run VRL and made our first "Hello World" application.&lt;/p&gt;

&lt;p&gt;It was mostly trivial, except for the unusual use of a "dot" (e.g., &lt;code&gt;.message&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dot
&lt;/h2&gt;

&lt;p&gt;The VRL program is a bit different from usual programming languages. The main convention is that there is a &lt;code&gt;.&lt;/code&gt; variable, which contains the event (for which the VRL application is running). The value of &lt;code&gt;.&lt;/code&gt; at the end of the program execution is the return value.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;.&lt;/code&gt; is not just a variable name. As you've noticed, you can access it the way you do in most other programming languages (&lt;code&gt;object.property&lt;/code&gt;), but when you access the content of the dot, you don't need to write &lt;code&gt;..message&lt;/code&gt;; you write just &lt;code&gt;.message&lt;/code&gt;. By the way, in VRL, if you have other variables, you can do &lt;code&gt;variable_name.property&lt;/code&gt; too.&lt;/p&gt;

&lt;p&gt;Let's look at our previous program, which was cleaning stuff from the dot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.message = "Hello World"
del(.timestamp)
del(.host)
del(.source_type)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are modifying the event. But we can do better.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. = {"message": "Hello World"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. = {}
.message = "Hello World"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In those two examples we are not modifying &lt;code&gt;.&lt;/code&gt;; we are replacing it with new content consisting of the object (also called a dictionary, if you are coming from a Python background). We either construct it in place (JSON notation) or create an empty object and set (create) a key &lt;code&gt;message&lt;/code&gt; with the value "Hello World".&lt;/p&gt;

&lt;h2&gt;
  
  
  Assignment and Reassignment
&lt;/h2&gt;

&lt;p&gt;Reassignment rules allow using &lt;code&gt;.&lt;/code&gt; in expressions that replace &lt;code&gt;.&lt;/code&gt; (or any other variable).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. = {"message": "Hello World", "old_message": .message}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run it with input &lt;code&gt;test&lt;/code&gt;, we get the expected result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"old_message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also can create new variables with a simple &lt;code&gt;=&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;old_dot = .
. = {}
.message = "Hello World"
.old_message = old_dot.message
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each assignment is a deep copy (that means, it copies all data recursively).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;temp = .
. = {}
.message = "Hello World"
.old_dot = temp
temp.message = "replaced"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the same input (&lt;code&gt;test&lt;/code&gt;) we get this output. Note, there is no "replaced" in the output, because we copied &lt;code&gt;temp&lt;/code&gt; into &lt;code&gt;.old_dot&lt;/code&gt; before changing &lt;code&gt;temp.message&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;World"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;old_dot"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message"&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test"&lt;/span&gt;
  &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Some ergonomic hints
&lt;/h2&gt;

&lt;p&gt;You can try those examples from the console, with the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vector --config example.yaml  -q|jq .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(put code examples into &lt;code&gt;example.yaml&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;You also can try the VRL playground: &lt;a href="https://playground.vrl.dev/" rel="noopener noreferrer"&gt;https://playground.vrl.dev/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that my initial example contains this source:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sources:
  stdin:
    type: "stdin"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it internally creates an object with a few fields: &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;message&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;source_type&lt;/code&gt;, &lt;code&gt;stdin&lt;/code&gt;, &lt;code&gt;timestamp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you decide to run code from the playground, you need to create an event (not just the word &lt;code&gt;test&lt;/code&gt;), so the minimal input for the playground is &lt;code&gt;{"message": "test"}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There can be a bit of confusion between not-a-JSON input and the event object at the VRL start, but it's easy to explain and understand:&lt;/p&gt;

&lt;p&gt;Everything Vector passes between sources, transforms, and sinks is always an object. Sources can take non-structured input (like &lt;code&gt;stdin&lt;/code&gt; or &lt;code&gt;exec&lt;/code&gt;), but they wrap unstructured text into an object. They also append metadata; that's how you get &lt;code&gt;timestamp&lt;/code&gt; and &lt;code&gt;host&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Second: VRL allows you to put spaces and newlines in most places (but not all!).&lt;/p&gt;

&lt;p&gt;These are two equivalent programs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. = {
        "message": "Hello World",
        "old_dot": .
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. = {"message": "Hello World", "old_dot": .}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this is NOT a proper VRL program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
  = 
    {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also can have a trailing comma in objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. = {
        "message": "Hello World",
        "old_dot": .,
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may be silly at first glance, but it makes &lt;code&gt;git diff&lt;/code&gt; much cleaner if you decide to add a line after the last one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;. = {
        "message": "Hello World",
        "old_dot": .,
        "something": "else",
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My advice is to use a trailing comma because it reduces syntax errors when you move lines around or add/remove them.&lt;/p&gt;

&lt;p&gt;In the next chapter we will discuss types, fallibility, and progressive typing.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>vector</category>
      <category>monitoring</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Vector's VRL introduction (chapter 1)</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Thu, 09 Oct 2025 18:16:25 +0000</pubDate>
      <link>https://dev.to/amarao/vectors-vrl-introduction-chapter-1-30p1</link>
      <guid>https://dev.to/amarao/vectors-vrl-introduction-chapter-1-30p1</guid>
      <description>&lt;h2&gt;
  
  
  Preface
&lt;/h2&gt;

&lt;p&gt;There is a program to process events (metrics, logs, traces) from different sources (files, scripts, scraping, HTTP servers, syslogs, etc.) into different sinks (Prometheus exporter, remote HTTP, files, etc.), while transforming it in different ways.&lt;/p&gt;

&lt;p&gt;It's called Vector. And it is amazing by all means, except one: there is no tutorial for VRL. There are docs on transforms, sinks, sources; there is a language reference; but there is no proper tutorial for the main feature of that program, the built-in language to do transformations, called Vector Remap Language.&lt;/p&gt;

&lt;p&gt;I found myself in a situation when I needed to write a complicated transformation (~0.05 kloc), and to do so I learned VRL for real.&lt;/p&gt;

&lt;p&gt;Because I found no introductions to VRL, I decided to write my own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal required onboarding into Vector
&lt;/h2&gt;

&lt;p&gt;While I won't talk much about other transforms, sinks, and sources, I need to give enough background about them to use VRL.&lt;/p&gt;

&lt;p&gt;Vector has sources, transforms, and sinks. Events flow from sources, through transforms, into sinks. Events are always moving forward. They can be "fanned out" into multiple transforms/sinks or can come from multiple sources/transforms, but they never create a loop (never go back). It's called a DAG (directed acyclic graph).&lt;/p&gt;

&lt;p&gt;Each transform or sink has a list of "inputs" to previous sources or transforms.&lt;/p&gt;

&lt;p&gt;This is an over-engineered &lt;code&gt;cat&lt;/code&gt; command. It reads data from the stdin source and writes it to the stdout sink:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stdin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdin"&lt;/span&gt;

&lt;span class="na"&gt;sinks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stdout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;console"&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdin"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;codec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run it we run Vector &lt;code&gt;--config example.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Everything we put into stdin gets output to stdout (but will be normalized in terms of Unicode characters, so it's not a true &lt;code&gt;cat&lt;/code&gt; program).&lt;/p&gt;

&lt;p&gt;This is almost enough for our goals. One more thing: we will create a &lt;code&gt;remap&lt;/code&gt; transforms in the middle. A VRL description is coming, but for now just believe me that empty text is a valid VRL program: it changes nothing, and the incoming event is passed further.&lt;/p&gt;

&lt;p&gt;This is our tutorial setup; we will use it to learn VRL. The actual VRL program is written inside the &lt;code&gt;source&lt;/code&gt; stanza of the &lt;code&gt;our_example&lt;/code&gt; transforms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stdin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdin"&lt;/span&gt;

&lt;span class="na"&gt;transforms&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;our_example&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdin"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;remap&lt;/span&gt;
    &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;span class="na"&gt;sinks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stdout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;console"&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;our_example"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;codec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a very simple DAG: &lt;code&gt;stdin-&amp;gt;our_example-&amp;gt;stdout&lt;/code&gt;. In this chain of articles we will focus on the &lt;code&gt;source&lt;/code&gt; part of &lt;code&gt;our_example&lt;/code&gt;. This is where VRL happens. (Note: you can have multiple remap transforms, and each will have its own VRL program.)&lt;/p&gt;

&lt;p&gt;Note: we changed the codec for sink &lt;code&gt;stdout&lt;/code&gt; to &lt;code&gt;json&lt;/code&gt;; this will help us see what exactly we have done.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is 'event'?
&lt;/h2&gt;

&lt;p&gt;If you run the previous program, you will see this as output (plus some log info from Vector itself; ignore it). I split lines into a few, but you will see it as a single line if you run it yourself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"shuttle1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"stdin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"1985-10-09T17:43:54.287916009Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I typed &lt;code&gt;test&lt;/code&gt; into stdin and got this output. This is an event, and it has type &lt;code&gt;log&lt;/code&gt; (we will talk about logs vs. metrics a bit later).&lt;/p&gt;

&lt;p&gt;Note that I typed only &lt;code&gt;test&lt;/code&gt;, but we got a lot of metadata — hostname, timestamp, source information — and the &lt;code&gt;message&lt;/code&gt;, the stuff I typed.&lt;/p&gt;

&lt;p&gt;Events come from sources. If they pass through a transforms of type &lt;code&gt;remap&lt;/code&gt;, the corresponding VRL program from the &lt;code&gt;source&lt;/code&gt; will run. A single event contains either a log line, or a sample for a series, or a trace. VRL programs never run by themselves; they always require an event to come from a source.&lt;/p&gt;

&lt;p&gt;To save myself on long listings I won't show the full config for Vector anymore, only the content of the &lt;code&gt;source&lt;/code&gt; (the VRL program).&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello world
&lt;/h2&gt;

&lt;p&gt;Because we can't just "run" a VRL program, we need to pass something into stdin. To make it easier, I run it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'test'|vector --config example.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or even like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo 'test'|vector --config example.yaml -q
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(the latter removes most of the logs from output)&lt;/p&gt;

&lt;p&gt;So, let's write a hello world program. (Note, I show only the &lt;code&gt;source&lt;/code&gt; content for the transforms &lt;code&gt;our_example&lt;/code&gt;.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.message = "Hello world"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: YAML allows writing multiline strings, so my transform looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transforms:
  our_example:
    inputs: ["stdin"]
    type: remap
    source: |
        .message = "Hello World"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(just keep indentation correct and you may pretend YAML does not exist)&lt;/p&gt;

&lt;p&gt;If we run it with a command line (see above), we get...&lt;/p&gt;

&lt;p&gt;As expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shuttle1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stdin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1985-10-09T18:02:33.317302641Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's run Vector without an &lt;code&gt;echo |&lt;/code&gt; before:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vector --config example.yaml  -q|jq .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and type two lines of some text (in my case &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;no!&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test
{
  "host": "shuttle1",
  "message": "Hello World",
  "source_type": "stdin",
  "timestamp": "1985-10-09T18:03:51.444177436Z"
}
no!
{
  "host": "shuttle1",
  "message": "Hello World",
  "source_type": "stdin",
  "timestamp": "1985-10-09T18:03:52.829102974Z"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, every input line caused a new run of our VRL program, which replaced the message with "Hello World".&lt;/p&gt;

&lt;p&gt;Note: we kept our metadata intact. And we got a timestamp.&lt;/p&gt;

&lt;p&gt;Let's clean it a bit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.message = "Hello World"
del(.timestamp)
del(.host)
del(.source_type)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, if we type two lines, we get only the message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test
{
  "message": "Hello World"
}
test
{
  "message": "Hello World"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will learn about VRL in the next chapter. Also, the thing I did (removing almost all metadata) is not recommended; it can break many sinks. We do it here just to get a taste of how VRL looks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Basics of the basics of VRL
&lt;/h1&gt;

&lt;p&gt;As you can see, the VRL program consists of zero or more expressions. There is no ';' , and spaces are not important. If we call a function, arguments are in brackets , strings are in quotes, &lt;code&gt;=&lt;/code&gt; is the assignment operator. There is something fishy about &lt;code&gt;.&lt;/code&gt; at the beginning of things, but that's the topic for the next chapter.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/amarao/vectors-vrl-introduction-chapter-2-14ho"&gt;the next chapter&lt;/a&gt;: The Dot, variable assignment.&lt;/p&gt;

</description>
      <category>vector</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Good practices for Just: no '../' in paths.</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Sat, 06 Sep 2025 09:57:37 +0000</pubDate>
      <link>https://dev.to/amarao/good-practices-for-just-no-in-pathes-3b2c</link>
      <guid>https://dev.to/amarao/good-practices-for-just-no-in-pathes-3b2c</guid>
      <description>&lt;p&gt;If you don't know, Just is &lt;a href="https://just.systems/" rel="noopener noreferrer"&gt;https://just.systems/&lt;/a&gt;, the beautiful well-thought replacement for make as 'small scale executor'. It does not replace make as a build tool (handling creation dates for files, etc), but it does so for every &lt;code&gt;.phony&lt;/code&gt; stuff from a Makefile.&lt;/p&gt;

&lt;p&gt;As for most tools, the usage starts small, but starts to spiral into chaos as line count grows. My current project I work on has about 300 lines in Justfiles. Very dense lines, with average recipe about 3–5 lines, and the magic living between recipes (one recipe is calling other or dependent on other recipes).&lt;/p&gt;

&lt;p&gt;The chaos must be resisted with order and rules. A good rule is the best practice.&lt;/p&gt;

&lt;p&gt;I don't have 100% assurance in things I write now, but I feel, I can call them at least 'good practices'. There are few now, but they start to accumulate as I correct my previous design mistakes and see arising problems.&lt;/p&gt;

&lt;h1&gt;
  
  
  Rule 1: No ..
&lt;/h1&gt;

&lt;p&gt;We start with cwd (current working directory) been set to the path where used Justfile is placed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Justfile
├── somedir
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We go into somedir, type just myrecipe and our working directory is the dirictory where Justfile is, not 'somedir'.&lt;/p&gt;

&lt;p&gt;This is nice and we can use it for relative pathes. There is nothing bad in writing something like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deploy:
  ansible-playbook playbooks/deploy.yaml -i inventory/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if we are calling &lt;code&gt;just deploy&lt;/code&gt; in the &lt;code&gt;playbooks&lt;/code&gt; directory it will work as expected, we will go 'up' to run this command and all pathes will point to the expected files.&lt;/p&gt;

&lt;p&gt;There are also &lt;code&gt;[no-cd]&lt;/code&gt; and &lt;code&gt;[cd dir]&lt;/code&gt; attributes.&lt;/p&gt;

&lt;p&gt;But... Sometimes we need to change directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deploy:
   cd ansible &amp;amp;&amp;amp; ansible-playbook playbooks/deploy.yaml -i ../inventory/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We changed the structure. Now there is &lt;code&gt;ansible/playbooks/&lt;/code&gt; and &lt;code&gt;/inventory&lt;/code&gt; and we need to &lt;code&gt;cd&lt;/code&gt; to &lt;code&gt;ansible&lt;/code&gt; before running Ansible (because there is ansible.cfg there and all other stuff).&lt;/p&gt;

&lt;p&gt;But inventory is outside of &lt;code&gt;ansible&lt;/code&gt; (for whatever reasons). And we need it.&lt;/p&gt;

&lt;p&gt;Simple solution is '..'. Which quickly become:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd production/deploy/ansible &amp;amp;&amp;amp; ANSIBLE_INVENTORY=$(realpath inventory/),$(realpath ../environments/{{ environment }}/ansible/inventory) -e @../../../sources/data {{ args }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Can you see the problem? Too many &lt;code&gt;..&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you decide to move stuff around during refactoring, you will have to recalculate those '..', and it's hard, because you need to reason on state machine jumping between directories.&lt;/p&gt;

&lt;p&gt;Solution? Use &lt;code&gt;{{ justfile_directory() }}&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is the absolute path. Except when you need relative path for external reasons, it's always pointing to the proper place, even if you pass it as an argument to the utility which run from a different directory.&lt;/li&gt;
&lt;li&gt;It is the relative path in sense, than clonning a repo into a different directory or moving stuff around keeps relative links unbroken.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Best of both worlds.&lt;/p&gt;

&lt;p&gt;Let's look to the good practice of using &lt;code&gt;{{ justfile_directory() }}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd production/deploy/ansible &amp;amp;&amp;amp; ANSIBLE_INVENTORY={{ justfile_directory() }}/production/deploy/ansible/inventory,{{ justfile_directory() }}/production/environments/{{ environment }}/ansible/inventory) -e @{{ justfile_directory }}/sources/data {{ args }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(I may made some relative mistakes while writing it, it hurts my brain to think about original paths).&lt;/p&gt;

&lt;p&gt;Result is much more readable (although, longer). We always can see where file is relative to the justfile, and there is no 'relativity' of (working directory after cd, relative paths for Ansible, etc, etc).&lt;/p&gt;

&lt;p&gt;For every utility it is absolute path, no thinking required.&lt;/p&gt;

&lt;p&gt;For developer it's all relative paths, relative to a single location - the placement of the Justfile.&lt;/p&gt;

&lt;p&gt;If we decide to remove 'production' from the path, we don't need to think which ../.. to reduce and which to keep. It all stays intact.&lt;/p&gt;

&lt;p&gt;I will post more good practices as I find the specific cases.&lt;/p&gt;

</description>
      <category>just</category>
    </item>
    <item>
      <title>Getting pure output from Ansible</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Sat, 09 Aug 2025 13:01:48 +0000</pubDate>
      <link>https://dev.to/amarao/getting-pure-output-from-ansible-4g5a</link>
      <guid>https://dev.to/amarao/getting-pure-output-from-ansible-4g5a</guid>
      <description>&lt;p&gt;There are moments when you want Ansible to stop printing anything own and just to show output of the remote command.&lt;/p&gt;

&lt;p&gt;Like &lt;code&gt;ssh user@server command&lt;/code&gt;, but with all Ansible bells and whistles, with custom ssh arguments, transports, etc, etc.&lt;/p&gt;

&lt;p&gt;I'm talking about the &lt;code&gt;ansibile&lt;/code&gt; binary, not the &lt;code&gt;ansible-playbook&lt;/code&gt;, although, with some tinkering, it's possible to use this trick with &lt;code&gt;ansible-playbook&lt;/code&gt; too.&lt;/p&gt;

&lt;p&gt;Foundation for tricks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use raw module (disaANSIBLE_LOAD_CALLBACK_PLUGINS=1 ANSIBLE_STDOUT_CALLBACK=json ansible -i localhost, -m raw -a 'cat /etc/passwd' all -c local | jq -r '.plays[].tasks[].hosts | to_entries[] | "(.key):\n(.value.stdout)\n"'bles AnsiballZ mechanism)&lt;/li&gt;
&lt;li&gt;Use json output (which allow to extract stdout without using unsound grep expressions).&lt;/li&gt;
&lt;li&gt;Process it with jq.&lt;/li&gt;
&lt;li&gt;Ask jq not to print quotes for string value.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here it is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ANSIBLE_LOAD_CALLBACK_PLUGINS=1 \
ANSIBLE_STDOUT_CALLBACK=json \
ansible -i localhost, -m raw -a 'cat /etc/passwd' all -c local \
| jq -r '.plays[].tasks[].hosts[]?.stdout'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Env variables says ansible to load callback plugins and to use json callback plugin (output).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-i localhost,&lt;/code&gt; and &lt;code&gt;-c local&lt;/code&gt; are not important. Use a proper inventory here if you need. localhost here just for an example.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-m raw -a command&lt;/code&gt; is usual ansible invocation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-r&lt;/code&gt; for jq removes quotes from a string.&lt;/li&gt;
&lt;li&gt;Expression &lt;code&gt;.plays[].tasks[].hosts[]?.stdout&lt;/code&gt; scans all hosts in all tasks for all plays and prints stdout.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why do you need it?&lt;/p&gt;

&lt;p&gt;Well, the thing I wanted to do was to get a secret file from a remote server and encrypt it locally on the host using sops. I can use &lt;code&gt;community.sops.sops_encrypt&lt;/code&gt; module, but it require multiple steps to do, and secrets are nasty to debug, so I don't want to do those steps.&lt;/p&gt;

&lt;p&gt;A 'simple' ansible call with &lt;code&gt;| sops -e&lt;/code&gt; is require less attention.&lt;/p&gt;

&lt;p&gt;But, it requires this 'pristine output' from ansible to avoid mangling the content, so, I had to invent this quirk.&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>How to retry block in Ansible</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Tue, 05 Aug 2025 09:19:13 +0000</pubDate>
      <link>https://dev.to/amarao/how-to-retry-block-in-ansible-2end</link>
      <guid>https://dev.to/amarao/how-to-retry-block-in-ansible-2end</guid>
      <description>&lt;p&gt;Normally you can't. But, if you really want, you can.&lt;/p&gt;

&lt;p&gt;Here is how.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move that block into separate tasklist. E.g. &lt;code&gt;foo.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;import it: &lt;code&gt;- import_tasks: foo.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, the magic. The content of the foo.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- block:
  - set_fact:
      count: "{{ count | d(0) + 1 }}"
  - name: Arbitrary number of tasks here which can fial
    command: /bin/false
    ...
  rescue:
    - fail:
      when: count &amp;gt; 3
    - include_tasks: foo.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How it works.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;foo is run.&lt;/li&gt;
&lt;li&gt;set fact set counter to 0 (because there is no counter)&lt;/li&gt;
&lt;li&gt;your tasks run. If they finish, block finish and everything is good.&lt;/li&gt;
&lt;li&gt;If any of your task fails, rescue part will be executed. If counter is less than 3, fail is skipped and foo is included. It is  the same file as you imported, this is self-recursion.&lt;/li&gt;
&lt;li&gt;Counter become + 1&lt;/li&gt;
&lt;li&gt;Try again.
...&lt;/li&gt;
&lt;li&gt;If count is too high, fail is executed and recursion stop.&lt;/li&gt;
&lt;li&gt;If at any count (before fail) block succeed, rescue section finishes, and recursion returns back and it continue to run as it wasn't failed at all (the desired property of the retry).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is terrible, but beautiful.&lt;/p&gt;

</description>
      <category>ansible</category>
    </item>
    <item>
      <title>Double force reboot</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Sat, 02 Aug 2025 08:48:24 +0000</pubDate>
      <link>https://dev.to/amarao/double-force-reboot-1j2c</link>
      <guid>https://dev.to/amarao/double-force-reboot-1j2c</guid>
      <description>&lt;p&gt;Today I've learned that systemd, actually, supports hard reboots.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl reboot --force --force
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the man page:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If &lt;code&gt;--force&lt;/code&gt; is specified twice, the operation is immediately executed without terminating any processes or unmounting any file systems. This may result in data loss. Note that when &lt;code&gt;--force&lt;/code&gt; is specified twice the halt operation is executed by systemctl itself, and the system manager is not contacted. This means the command should succeed even when the system manager has crashed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the closest equivalent of &lt;code&gt;echo b &amp;gt; /proc/sysrq-trigger&lt;/code&gt; I can find.&lt;/p&gt;

</description>
      <category>systemd</category>
      <category>linux</category>
    </item>
    <item>
      <title>Elegant way to assert if env variable is defined for a single recipe in Just</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Thu, 17 Jul 2025 11:19:58 +0000</pubDate>
      <link>https://dev.to/amarao/elegant-way-to-assert-if-env-variable-is-defined-for-a-single-recipe-in-just-31i8</link>
      <guid>https://dev.to/amarao/elegant-way-to-assert-if-env-variable-is-defined-for-a-single-recipe-in-just-31i8</guid>
      <description>&lt;p&gt;I found the way, which I think, is the most elegant, to check if environment variable is defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;foo:
  @test {{ env("FOO") }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If FOO is not defined, it will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error: Call to function `env` failed: environment variable `FOO` not present
  ——▶ Justfile:2:12
  │
2 │   @test {{ env("FOO") }}
  │            ^^^             
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maybe there is a build-in way, but I wasn't able to find it. I want it to be checked for a single recipe, not for the whole file.&lt;/p&gt;

</description>
      <category>just</category>
    </item>
    <item>
      <title>from poetry to uv</title>
      <dc:creator>George Shuklin</dc:creator>
      <pubDate>Sat, 28 Jun 2025 08:44:58 +0000</pubDate>
      <link>https://dev.to/amarao/poetry-uv-3l32</link>
      <guid>https://dev.to/amarao/poetry-uv-3l32</guid>
      <description>&lt;p&gt;I've done my fourth project conversion from Poetry (or a plain pip) to uv.&lt;/p&gt;

&lt;p&gt;Results: absolutely zero issues.&lt;/p&gt;

&lt;p&gt;Moreover, I have an interesting imrovement. The real reproducible CI image (debian with terraform, just, ansible, sops).&lt;/p&gt;

&lt;p&gt;Sizes for tar files for a Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- poetry (ci image size 264M, build time 2:17-2:26)
+ uv (ci image size 235M, build time 1:30-1:50)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Python application takes additional ~30MB more in archived state. Why? Because of dependencies. A lot of them. Uv is not small (44MB, but Python one is enormous).&lt;/p&gt;

&lt;p&gt;Also, you can see how faster image build become. Most of the build time is Ansible collection installation time (I can't reduce that one), but installation time for all python stack (mostly Ansible and it's dependencies) shrunk from significant to negligible.&lt;/p&gt;

&lt;p&gt;Build process spend now more time on apt than on python packages. With poetry and pip, those times were comparable.&lt;/p&gt;

&lt;p&gt;I identified two different ways to use uv in the CI image: with uv and without.&lt;/p&gt;

&lt;p&gt;If uv is present in the image, you need install it, and you need &lt;code&gt;pyproject.toml&lt;/code&gt; and &lt;code&gt;uv.lock&lt;/code&gt; files.&lt;/p&gt;

&lt;p&gt;If uv is not used, you need to use some other process (usually, the operator) to export dependencies into requirements.txt (with hashes) via uv export. And you can skip copying pyproject.toml file completely.&lt;/p&gt;

&lt;p&gt;After trying both ways I more inclined to use &lt;code&gt;with uv&lt;/code&gt; (because it's faster, way, way faster). It also removes hassle for creating venv as separate comand. A simple &lt;code&gt;uv sync&lt;/code&gt; do the job.&lt;/p&gt;

&lt;p&gt;Also, in &lt;code&gt;with uv&lt;/code&gt; I can skip python3-pip package, which alleviate some of the size price from adding uv.&lt;/p&gt;

&lt;p&gt;Three projects I migrated by hands.&lt;/p&gt;

&lt;p&gt;On my fourth project I found even faster way to do it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uvx migrate-to-uv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It does not exclude CI work (images, etc), but reduce cognitive load on converting pyproject.toml.&lt;/p&gt;

&lt;h1&gt;
  
  
  ... Why not poetry?
&lt;/h1&gt;

&lt;p&gt;Even without 'speed' factor I got two big issues with poetry.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;They started well, got into modern distributions (&lt;code&gt;apt-get install python3-poetry&lt;/code&gt;), but they broke compatibility in 1.6-2.0, in such a way, that you can't have &lt;code&gt;pyproject.toml&lt;/code&gt; been compatible with both. It's moving too fast and breaks too many things to be a packet manager.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I found odd situation that it flips random write bits on installed packets. I build reproducible images, so I have runs, where diffoscope see something odd, like 0754 in one image and 0757 in another. I rune out everything but poetry, and poetry does this. Maybe I should file a bug for this? But I have no definitive proofs (it's probabilistic, random file at random run), and I know how much time I would spend reporting this thing. I already lost few days of my work time nailing problem down. Instead I move from poetry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There was time when it was possible to use poetry without poetry (&lt;code&gt;poetry export&lt;/code&gt;) but they decided it's too easy to use and moved into separate package, deprecating and removing function from the main package. They have reasons. To make things more complex than they should be. I have reasons. To move on.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All this leads to 'should we try uv?', and I tried. Project #1 was simple and migration was trivial. Project #2 was simple and migration was okay (because of CI nuances and internal policies on artifacts). Project #3 (where I tried &lt;code&gt;uv export&lt;/code&gt; was okay, but I had to add an additional job to check if uv export is not stale. I didn't liked it. Project #4 was converted in less than hour (including Hadolint nitpicking), and it was straightforward and simple.&lt;/p&gt;

&lt;p&gt;And it was reproducible from the first attempt. No more odd caches rm at the end of stage (poetry still leaves some randomness even with --no-cache), just simple &lt;code&gt;uv sync --no-cache&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What I miss is a docker image with uv. Writing 'copy --from' in the Dockerfile is much nicer than my current UV downloading code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"curl -L https://github.com/astral-sh/uv/releases/download/0.7.16/uv-x86_64-unknown-linux-musl.tar.gz | tar xz --wildcards */uv"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mv &lt;/span&gt;uv-x86_64-unknown-linux-musl/uv /usr/local/bin &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;6538516743f9c33aec8e53398730dcc55c6bbcbe2f660a7757c10d358b85e675  /usr/local/bin/uv | &lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;compare to my TF code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# from hashicorp/terraform:1.12 at 2025-06-22
FROM hashicorp/terraform@sha256:f5ac787eee9d292b6a3b97d40f04019ce08189d356233fc73d5ec7ef8529cce2 as terraform
...
COPY --from=terraform /bin/terraform /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Yep, price for hash pinning is high).&lt;/p&gt;

</description>
      <category>python</category>
    </item>
  </channel>
</rss>
