<?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>The Ops Community ⚙️: Alexey Melezhik</title>
    <description>The latest articles on The Ops Community ⚙️ by Alexey Melezhik (@melezhik).</description>
    <link>https://community.ops.io/melezhik</link>
    <image>
      <url>https://community.ops.io/images/5jefILRAjNTOFIK7tREd99scLewzhG9URcNcBAfVpGI/rs:fill:90:90/g:sm/mb:500000/ar:1/aHR0cHM6Ly9jb21t/dW5pdHkub3BzLmlv/L3JlbW90ZWltYWdl/cy91cGxvYWRzL3Vz/ZXIvcHJvZmlsZV9p/bWFnZS8xMTIvYWZj/MjVmNzYtMjc1Yy00/MDY2LTg4ODQtNTYw/ODA0ZTRhNmRkLmpw/ZWc</url>
      <title>The Ops Community ⚙️: Alexey Melezhik</title>
      <link>https://community.ops.io/melezhik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://community.ops.io/feed/melezhik"/>
    <language>en</language>
    <item>
      <title>SparrowCI - DSL is dead, long live DSL!</title>
      <dc:creator>Alexey Melezhik</dc:creator>
      <pubDate>Tue, 25 Oct 2022 22:11:43 +0000</pubDate>
      <link>https://community.ops.io/melezhik/sparrowci-dsl-is-dead-long-live-dsl-58pm</link>
      <guid>https://community.ops.io/melezhik/sparrowci-dsl-is-dead-long-live-dsl-58pm</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on dev.to - &lt;a href="https://dev.to/melezhik/sparrowci-dsl-is-dead-long-live-dsl-4l1b"&gt;https://dev.to/melezhik/sparrowci-dsl-is-dead-long-live-dsl-4l1b&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;TL;DR - How to write YAML DSL pipelines without frustration.&lt;/p&gt;




&lt;p&gt;To be honest, I am not in favor of modern DSL based tools.&lt;/p&gt;

&lt;p&gt;At least, I am not in favor of them when people try to use those tools for the things they are not &lt;em&gt;very well designed for&lt;/em&gt; ( which starts to happen pretty quickly ).&lt;/p&gt;

&lt;p&gt;Starting from Ansible the course of declarative style DSL languages seems has taken the market, while it does not always mean those tools are easy to use and maintain. &lt;/p&gt;




&lt;p&gt;Well, for simple, typical cases ala &lt;code&gt;make &amp;amp;&amp;amp; sudo make install&lt;/code&gt; this approach works really well, while for more complex scenarios where a pipeline logic implies &lt;em&gt;some data flow and sharing states between steps&lt;/em&gt; the idea of confining everything into a declarative (none imperative) approach results in ugly and hard to maintain code.&lt;/p&gt;

&lt;p&gt;Consider this simple example of GH actions pipeline of setting 2 variables in 2 steps and using them in downstream code:&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;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task1&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "::set-output name=test::hello"&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task2&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "::set-output name=test::world"&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt; 
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;echo "Task1 returns: ${{ steps.task1.outputs.test }}"&lt;/span&gt;
      &lt;span class="s"&gt;echo "Task2 returns: ${{ steps.task2_outputs.test }}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IMHO here we have a code that is hard to read (we use none relevant print statements to set a step output), and thus to maintain.&lt;/p&gt;

&lt;p&gt;These typical question would pop up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If I use high level general purpose programming languages why should I use print statements to declare return output ?&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How could a step return structured, complex object data?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And the last but not the least - how to pass &lt;em&gt;arbitrary&lt;/em&gt; configuration as a task input?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This is why ( well partly because of that ) I've created &lt;a href="https://ci.sparrowhub.io"&gt;SparrowCI&lt;/a&gt; - super fun and flexible CI system with many programming languages support&lt;/p&gt;




&lt;p&gt;SparrowCI DSL still allows one to write pipeline code as YAML based steps, however, every step essentially is a function written in a language of choice and thus accepting some input parameters and returning some output values.&lt;/p&gt;

&lt;p&gt;That is it.&lt;/p&gt;

&lt;p&gt;In SparrowCI have a good balance of YAML based pipelines for people not willing to go imperative path and do any serious coding and flexibility and freedom to express elementary units of pipeline logic as functions written on regular programming languages:&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;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;
      &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task1&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;print("task1 start")&lt;/span&gt;
        &lt;span class="s"&gt;print(f"you passed {config()['message']}")&lt;/span&gt;
        &lt;span class="s"&gt;update_state({"test": "hello"})&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task2&lt;/span&gt;
      &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;print("task2 start")&lt;/span&gt;
        &lt;span class="s"&gt;print(f"you passed {config()['message']}")&lt;/span&gt;
        &lt;span class="s"&gt;update_state({"test": "world"})&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
      &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Python&lt;/span&gt;
      &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;depends&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="pi"&gt;-&lt;/span&gt; 
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task1&lt;/span&gt;
          &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello task1&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; 
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task2&lt;/span&gt;
          &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hello task2&lt;/span&gt;
      &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;print(f"Task1 returns: {config()["tasks"]["task1"]["state"]["test"]}")&lt;/span&gt;
        &lt;span class="s"&gt;print(f"Task2 returns: {config()["tasks"]["task2"]["state"]["test"]}")&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;So, with that being said - DSL(YAML) is dead, long live DSL(YAML)!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cicd</category>
      <category>pipelines</category>
      <category>dsl</category>
    </item>
    <item>
      <title>One Tomtit to make it!</title>
      <dc:creator>Alexey Melezhik</dc:creator>
      <pubDate>Wed, 25 May 2022 19:47:17 +0000</pubDate>
      <link>https://community.ops.io/melezhik/one-tomtit-to-make-it-17ee</link>
      <guid>https://community.ops.io/melezhik/one-tomtit-to-make-it-17ee</guid>
      <description>&lt;p&gt;&lt;a href="https://community.ops.io/images/BDdCu9fKGIvaI5GbI44WHp20RholHemNEgD6gIQeyqk/w:880/mb:500000/ar:1/aHR0cHM6Ly93d3cu/Z29vZGZyZWVwaG90/b3MuY29tL2FsYnVt/cy9hbmltYWxzL2Jp/cmRzL3RvbXRpdC1z/dG9jay1waG90by5q/cGc" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/BDdCu9fKGIvaI5GbI44WHp20RholHemNEgD6gIQeyqk/w:880/mb:500000/ar:1/aHR0cHM6Ly93d3cu/Z29vZGZyZWVwaG90/b3MuY29tL2FsYnVt/cy9hbmltYWxzL2Jp/cmRzL3RvbXRpdC1z/dG9jay1waG90by5q/cGc" alt="tomtit photo from goodfreephotos.com" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Photo via &lt;a href="https://www.goodfreephotos.com/"&gt;Good Free Photos&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/DhZyL7Ze1ChtSWwMYIFBb-rWaYiH2Qdj2p6QuwEr8EY/w:880/mb:500000/ar:1/aHR0cHM6Ly9yYXcu/Z2l0aHVidXNlcmNv/bnRlbnQuY29tL21l/bGV6aGlrL3RvbXRp/dC9tYXN0ZXIvdG9t/dGl0LW91dHB1dC5w/bmc" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/DhZyL7Ze1ChtSWwMYIFBb-rWaYiH2Qdj2p6QuwEr8EY/w:880/mb:500000/ar:1/aHR0cHM6Ly9yYXcu/Z2l0aHVidXNlcmNv/bnRlbnQuY29tL21l/bGV6aGlrL3RvbXRp/dC9tYXN0ZXIvdG9t/dGl0LW91dHB1dC5w/bmc" alt="tomtic console output" width="880" height="482"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://github.com/melezhik/tomtit"&gt;Tomtit&lt;/a&gt; is a Raku task runner with dozens of plugins, you can use it as alternative for many task runners.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it shapes best for Raku developers as it written on Raku&lt;/li&gt;
&lt;li&gt;it has programmatic API for Raku language &lt;/li&gt;
&lt;li&gt;it has shortcuts for many common tasks - running Bash scripts, creation of files and starting/stoping services - &lt;a href="https://github.com/melezhik/sparrowdo/blob/master/core-dsl.md"&gt;https://github.com/melezhik/sparrowdo/blob/master/core-dsl.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;it has dozens of plugins - &lt;a href="https://sparrowhub.io"&gt;https://sparrowhub.io&lt;/a&gt; - to solve more specific tasks&lt;/li&gt;
&lt;li&gt;it's extendible - you can take your favourite language and write a new plugin to address your specific needs.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a bottom line it helps you to get things done with a minimal of fuss, yet not limited you to a static DSL but allow you to orchestrate your scenarios in modern and powerful language &lt;a href="https://raku.org/"&gt;Raku&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, are you ready to get closer?&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;Tomtit is installed as Raku module.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;zef install Tomtit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once successfully installed Tomcat provides &lt;code&gt;tom&lt;/code&gt; - command line client to execute scenarios. &lt;/p&gt;

&lt;h1&gt;
  
  
  Tomtit workflow
&lt;/h1&gt;

&lt;p&gt;Your usual workflow with tomtit is when you define scenarios and then run them. It works especially nice with &lt;em&gt;project-centric&lt;/em&gt; approach where you checkout the source code of application and run some &lt;em&gt;related tasks&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Say, we have an application source code, where we perform 3 standard operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build&lt;/li&gt;
&lt;li&gt;test&lt;/li&gt;
&lt;li&gt;and install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We end up with scenarios, we name then &lt;em&gt;build&lt;/em&gt;, &lt;em&gt;test&lt;/em&gt; and &lt;em&gt;install&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;If use &lt;code&gt;make&lt;/code&gt; utility to build project, it could be just a 3 invocations of &lt;code&gt;make&lt;/code&gt; utility with related arguments.&lt;/p&gt;

&lt;p&gt;Let's create our first Tomtit scenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout $git-repo

mkdir .tom

nano .tom/build.pl6
nano .tom/test.pl6
nano .tom/install.pl6

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code of every scenarios is as simple as running &lt;code&gt;make&lt;/code&gt; though &lt;code&gt;bash&lt;/code&gt; shortcut:&lt;/p&gt;

&lt;p&gt;.tom/build.pl6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash "make"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;.tom/test.pl6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash "make test"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;.tom/install.pl6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bash "sudo make install"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Programmatic API
&lt;/h1&gt;

&lt;p&gt;The tomtit scenarios are written in Raku and basically are just calls of different tasks, those scenarios however not necessarily limited tasks calls, they just are &lt;em&gt;Raku programs&lt;/em&gt; where you can do anything you could with Raku.&lt;/p&gt;

&lt;p&gt;There are two syntactically different types of tasks in Tomtit. The first one you call by the means of &lt;code&gt;task-run&lt;/code&gt; function and  second one is &lt;em&gt;shortcuts&lt;/em&gt; - pretty much the same as &lt;code&gt;task-run&lt;/code&gt; but with mnemonic names and sometimes easier signatures.&lt;/p&gt;

&lt;p&gt;In the scenarios for &lt;code&gt;make&lt;/code&gt; utility we used &lt;code&gt;bash&lt;/code&gt; shortcut to call a piece of Bash code. The full list of shortcuts as we as calling details is here - &lt;a href="https://github.com/melezhik/sparrowdo/blob/master/core-dsl.md"&gt;https://github.com/melezhik/sparrowdo/blob/master/core-dsl.md&lt;/a&gt;  &lt;/p&gt;

&lt;h1&gt;
  
  
  Tasks and plugins
&lt;/h1&gt;

&lt;p&gt;In other words both task-run and shortcuts is just a way to call small piece if code that is downloaded from SparrowHub - script repository and then executed by &lt;code&gt;sparrow&lt;/code&gt; internal script runner for &lt;code&gt;tomtit&lt;/code&gt;, I have not told you but we have one more birds in our zoo-repository!&lt;/p&gt;

&lt;p&gt;These small scripts or tasks are also called Sparrow plugins.&lt;/p&gt;

&lt;p&gt;Tomtits scenarios basically are just a list of executed Sparrow plugins or tasks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Command line API
&lt;/h1&gt;

&lt;p&gt;By running &lt;code&gt;tom --list&lt;/code&gt; you'll see all the scenarios available now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[scenarios list]
build
test
install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once scenarios are defined you run them through &lt;code&gt;tom --run=$scenario&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tom run=build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tom run=test&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And so on.&lt;/p&gt;

&lt;p&gt;To recall what was the last scenario you run use &lt;code&gt;tom --last&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;You'll find thorough documentation on &lt;code&gt;tom&lt;/code&gt; command line client usage at Tomtit's gihtub pages.&lt;/p&gt;

&lt;h1&gt;
  
  
  Custom tasks
&lt;/h1&gt;

&lt;p&gt;Like I said, you are not limited running Bash only in Tomtit scenarios. You can run any task provided you find related plugin for it.&lt;/p&gt;

&lt;p&gt;For example, let's create scenario that configure local git repository with user's parameters like username and email.&lt;/p&gt;

&lt;p&gt;The task is often useful when you've just clone new project, make some changes and want to push some changes back to remote. Git requires you to set your identities as a commiter.&lt;/p&gt;

&lt;p&gt;.tom/git-setup.pl6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task-run "set git", "git-base", %(
  email                =&amp;gt; 'melezhik@gmail.com',
  name                 =&amp;gt; 'Alexey Melezhik',
  config_scope         =&amp;gt; 'local',
  set_credential_cache =&amp;gt; 'on'
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By setting config_scope we ask task to make settings for local git repository and by setting set_credential_cache we also ask git to cache our password, so we don't enter it every time we do &lt;code&gt;git push&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The list of plugins you can use in Tomtit scenarios is available at &lt;a href="https://sparrowhub.io"&gt;SparrowHub&lt;/a&gt; - sparrow plugin repository.&lt;/p&gt;

&lt;p&gt;In the next scenario example we create task to run VSTS build remotely through the &lt;a href="https://sparrowhub.io/info/vsts-build"&gt;vsts-build&lt;/a&gt; plugin:&lt;/p&gt;

&lt;p&gt;.tom/build-vsts.pl6:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;task_run "run my build", "vsts-build", %(
    definition =&amp;gt; "BackEndBuild"
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are many other plugins you can use in Tomtit scenarios as tasks. Check out SparrowHub repository.&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Tomtit provides you with the plenty of small script or plugins you might use in daily tasks, especially when dealing with source code management and build automation.&lt;/p&gt;

&lt;p&gt;Tomtit scenarios are plain Raku scripts to generate dynamic lists of executed tasks - scripts with parameters. &lt;/p&gt;

&lt;p&gt;There is syntax sugar - predefined set of built-in functions you can use instead of referring to plugins, that make code more concise and easier to read. &lt;/p&gt;

&lt;p&gt;If for some reasons you don't find plugin to solve your task, you can always create your own one and start using it strait away.&lt;/p&gt;




&lt;p&gt;Tomtit is easy to use, powerful and fun  - give it a try, and let me know how it's going on.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Write devopsish tests using Tomty and Raku</title>
      <dc:creator>Alexey Melezhik</dc:creator>
      <pubDate>Wed, 25 May 2022 19:44:01 +0000</pubDate>
      <link>https://community.ops.io/melezhik/write-devopsish-tests-using-tomty-and-raku-1lh4</link>
      <guid>https://community.ops.io/melezhik/write-devopsish-tests-using-tomty-and-raku-1lh4</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/melezhik/Tomty"&gt;Tomty&lt;/a&gt; is a Raku test framework with focus on devops tasks. Tomty allows one to write test scenarios on Bash (or &lt;a href="https://github.com/melezhik/Sparrow6#supported-languages"&gt;whatever&lt;/a&gt;) and orchestrate them using Raku.&lt;/p&gt;

&lt;p&gt;In this post I am going to give a quick introduction into Tomty.&lt;/p&gt;




&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;Tomty is installed as Raku module, using zef - Raku package manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;zef &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt;/test https://github.com/melezhik/Sparrow6.git
zef &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt;/test https://github.com/melezhik/Tomty.git 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need bleeding edge version of Tomty and Sparrow (dependency for Tomty) to get an access to all the features mentioned in this post.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup Tomty
&lt;/h1&gt;

&lt;p&gt;Working with Tomty requires some initialization. First of all we need to create a working directory for tests and initialize it. Optionally we can install Bash completion for &lt;code&gt;tomty&lt;/code&gt; - Tomty cli application:&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SP6_REPO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;https://sparrowhub.io/repo
&lt;span class="nb"&gt;mkdir &lt;/span&gt;work
&lt;span class="nb"&gt;cd &lt;/span&gt;work
tomty &lt;span class="nt"&gt;--init&lt;/span&gt;
tomty &lt;span class="nt"&gt;--completion&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Create first scenario
&lt;/h1&gt;

&lt;p&gt;Scenarios could be written on many languages, in this post I'll focus on Bash as it's a simple and quite popular scripting language for devops tasks and automation. Tomty allows effectively right low level tasks in Bash while gluing them together with Raku.&lt;/p&gt;

&lt;p&gt;A Bash scenario should be just a file named &lt;code&gt;task.bash&lt;/code&gt; and located at &lt;em&gt;some&lt;/em&gt; directory:&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="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; tasks/task1/
nano tasks/task1/task.bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"hello world"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once bash task is created, we can run it through a Raku wrapper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty &lt;span class="nt"&gt;--edit&lt;/span&gt; my-task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!raku
task-run "tasks/task1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In context of Raku a Bash task gets called as a Raku function &lt;code&gt;task-run&lt;/code&gt;, with a parameter setting a task directory.&lt;/p&gt;

&lt;p&gt;The approach gives us a benefit of using high level language to call low level Bash scenarios.&lt;/p&gt;

&lt;p&gt;Now, let's run our first task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty my-task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[repository] :: index updated from file:///root/repo/api/v1/index
[tasks/task1] :: hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The task executed successfully, now let's convert this trivial hello world example it into something more practical.&lt;/p&gt;

&lt;h1&gt;
  
  
  Check if a web site is available
&lt;/h1&gt;

&lt;p&gt;The task of checking an http resource health check is quite common in daily devops @job. Let's see how we could do this in Tomty.&lt;/p&gt;

&lt;p&gt;First, let's create a Bash task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano tasks/task1/task.bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;config url&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-D&lt;/span&gt; - | &lt;span class="nb"&gt;head&lt;/span&gt;  &lt;span class="nt"&gt;-n&lt;/span&gt; 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The task is just using &lt;code&gt;curl&lt;/code&gt; command to GET some http URL, pay attention that &lt;code&gt;-f&lt;/code&gt; flag causes curl to exit with none zero exit code in case of receiving none successful http response.  &lt;/p&gt;

&lt;p&gt;A Tomty scenario, would change a bit to pass tested URL as a &lt;em&gt;paramater&lt;/em&gt; into a Bash task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty &lt;span class="nt"&gt;--edit&lt;/span&gt; my-task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!raku
task-run "tasks/task1", %(
  url =&amp;gt; "https://raku.org"
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's see how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty my-task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[tasks/task1] :: HTTP/2 200
[tasks/task1] :: date: Fri, 02 Jul 2021 18:20:58 GMT
[tasks/task1] :: content-type: text/html
[tasks/task1] :: last-modified: Tue, 25 May 2021 16:30:03 GMT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we could see Bash &lt;code&gt;config name&lt;/code&gt; is used as function to access named parameters passed to Bash from Raku as a Raku Hash. This semantic works because Tomty is build on top of Sparrow automation tool, that provides all type of such functionality. &lt;/p&gt;




&lt;p&gt;Many times, relying on a script exit code to check if a test passes or not works just fine, however sometime one needs to specify expected script &lt;em&gt;output&lt;/em&gt; to define a test state.&lt;/p&gt;

&lt;p&gt;Let's see how Tomty allows that.&lt;/p&gt;

&lt;h1&gt;
  
  
  Task checks
&lt;/h1&gt;

&lt;p&gt;Task checks allow define an output a test expects to see in a running script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano tasks/task1/task.check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP/2 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we check that &lt;a href="https://raku.org"&gt;https://raku.org&lt;/a&gt; web server servers HTTP v2 protocol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty my-task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[repository] :: index updated from file:///root/repo/api/v1/index
[tasks/task1] :: HTTP/2 200
[tasks/task1] :: date: Fri, 02 Jul 2021 19:08:34 GMT
[tasks/task1] :: content-type: text/html
[tasks/task1] :: last-modified: Tue, 25 May 2021 16:30:03 GMT
[task check] stdout match &amp;lt;HTTP/2 200&amp;gt; True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if we want to check against v1 or v2, we can use Raku regular expressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano tasks/task1/task.check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;regexp: "HTTP/" 1 || 2 " 200"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refer to Sparrow &lt;a href="https://github.com/melezhik/Sparrow6/blob/master/documentation/taskchecks.md"&gt;task check&lt;/a&gt; documentation to get full explanation of the DSL and see more complex examples of validating scripts output.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tags
&lt;/h1&gt;

&lt;p&gt;Once you have more and more tests you can run all then by using &lt;code&gt;--all&lt;/code&gt; parameter of tomty cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However when there are too many tests, it's gets really difficult to manage them. &lt;/p&gt;

&lt;p&gt;Tags allows to split your tests by multiple groups and run them specifically. It's could extremely useful with a huge tests base.&lt;/p&gt;

&lt;p&gt;Let me show a quick simple example using the previous web site check scenario.&lt;/p&gt;

&lt;p&gt;Say, we don't want to run our web site availability test if we don't have the internet access on our testing environment.&lt;/p&gt;

&lt;p&gt;Let's first add a tag to a Raku scenario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty &lt;span class="nt"&gt;--edit&lt;/span&gt; my-task
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!raku

=begin tomty
%(
  tags =&amp;gt; [ 'offline']
)
=end tomty

task-run "tasks/task1", %(
  url =&amp;gt; "https://raku.org"
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see tags added into dedicated "tomty" Pod6 sections as Raku array ( there could be many tags ). &lt;/p&gt;

&lt;p&gt;Now let's see how we could use this tag, when running tomty cli:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty &lt;span class="nt"&gt;--skip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;offline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1/1] / [my-task] ....... SKIP
=========================================
(=: / [1] tests in 0 sec / (0) tests passed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see Tomty did not execute the test, as we required to skip any tests tagged as &lt;code&gt;offline&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We could have build even more sophisticated examples. For example to run only offline tests for application version 2, but to skip production tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tomty --only=offline+app-v2 --skip=production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To list all available tags run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty &lt;span class="nt"&gt;--list&lt;/span&gt; &lt;span class="nt"&gt;--tags&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes you want only list tests with theirs tags, not execute them, the previous example would be rewritten as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tomty &lt;span class="nt"&gt;--tags&lt;/span&gt; &lt;span class="nt"&gt;--only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;offline+app-v2 &lt;span class="nt"&gt;--skip&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This was a brief introduction into Tomty - test framework written on Raku and supporting many scripting languages to write low level tasks. The main philosophy of Sparrow ( the engine Tomty is built upon ) - use those languages that fits your domain best ( in our case - Bash is simple and efficient way to send http requests) and glue scripts together using high language - Raku, where scripts get called as functions. &lt;/p&gt;

&lt;p&gt;When I develop tests for my daily devops tasks on Tomty, I switch between Bash and Raku often and this approach allows me do my work effectively and with minimal efforts.&lt;/p&gt;




&lt;p&gt;Thanks for reading. I'd like to hear feedback as usual.&lt;/p&gt;

&lt;p&gt;Alexey&lt;/p&gt;

</description>
      <category>devops</category>
      <category>raku</category>
      <category>bash</category>
      <category>testing</category>
    </item>
    <item>
      <title>Validating k8s deployments using Sparrow</title>
      <dc:creator>Alexey Melezhik</dc:creator>
      <pubDate>Wed, 25 May 2022 19:41:16 +0000</pubDate>
      <link>https://community.ops.io/melezhik/validating-k8s-deployments-using-sparrow-28da</link>
      <guid>https://community.ops.io/melezhik/validating-k8s-deployments-using-sparrow-28da</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/melezhik/Sparrow6"&gt;Sparrow&lt;/a&gt; is a wonderful tool to automate @daily devops tasks. Recently I've dropped a new plugin called &lt;code&gt;k8s-deployment-check&lt;/code&gt; to verify k8s deployments. It lets you with a little bit of Raku code effectively test entire k8s infrastructure, including k8s deployments.&lt;/p&gt;




&lt;p&gt;Let's create a sample nginx deployment to show how it works:&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="c1"&gt;# replicas: 1 # tells deployment to run 2 pods matching the template&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:1.14.2&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/www&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;www-data&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DEMO_GREETING&lt;/span&gt;
            &lt;span class="na"&gt;value&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;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;environment"&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DEMO_FAREWELL&lt;/span&gt;
            &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Such&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sweet&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sorrow"&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;www-data&lt;/span&gt;
        &lt;span class="na"&gt;persistentVolumeClaim&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;claimName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-example&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we run simple nginx application with local folder mounted as &lt;code&gt;/var/www&lt;/code&gt; and consuming it's data throughout a volume named &lt;code&gt;www-data&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;k8s apply &lt;span class="nt"&gt;-f&lt;/span&gt; nginx.yaml
deployment.apps/nginx-deployment created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Now when our deployment is up and running, let's verify it, using Raku:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tomty --edit verify&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!raku&lt;/span&gt;

&lt;span class="nv"&gt;task&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;run&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chk-dpl&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;k8s-deployment-check&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nginx-deployment&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
  &lt;span class="s"&gt;namespace&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;melezhik-sandbox&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
  &lt;span class="nv"&gt;volume&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="s"&gt;mounts&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/var/www&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tomty verify&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;[repository] :: index updated from file:///root/repo/api/v1/index
[chk-dpl] :: &amp;gt;&amp;gt;&amp;gt; verify deployment. name=nginx-deployment,namespace=melezhik-sandbox,container=nginx
[chk-dpl] :: [env_start]
[chk-dpl] :: [DEMO_GREETING=Hello from the environment]
[chk-dpl] :: [DEMO_FAREWELL=Such a sweet sorrow]
[chk-dpl] :: [env_end]
[chk-dpl] :: [volume_mounts_start]
[chk-dpl] :: [www-data /var/www]
[chk-dpl] :: [volume_mounts_end]
[chk-dpl] :: ==================================================================
[task check] &amp;gt;&amp;gt;&amp;gt; check volume mounts
[task check] stdout match (r) &amp;lt;[www-data /var/www]&amp;gt; True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we could see Sparrow has successfully verified that &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;k8s deployment resource it exists&lt;/li&gt;
&lt;li&gt;it has volume &lt;code&gt;www-data&lt;/code&gt; mounted as &lt;code&gt;/var/www&lt;/code&gt; folder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can alter the scenario a bit, adding environment variable check as well:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tomty --edit verify&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;task&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;run&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chk-dpl&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;k8s-deployment-check&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nginx-deployment&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
  &lt;span class="s"&gt;namespace&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;melezhik-sandbox&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
  &lt;span class="nv"&gt;volume&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="s"&gt;mounts&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/var/www&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="s"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;DEMO_GREETING&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from the environment&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt;
    &lt;span class="s"&gt;DEMO_FAREWELL&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Such a sweet sorrow&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now run:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tomty verify&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;[repository] :: index updated from file:///root/repo/api/v1/index
[chk-dpl] :: &amp;gt;&amp;gt;&amp;gt; verify deployment. name=nginx-deployment,namespace=melezhik-sandbox,container=nginx
[chk-dpl] :: [env_start]
[chk-dpl] :: [DEMO_GREETING=Hello from the environment]
[chk-dpl] :: [DEMO_FAREWELL=Such a sweet sorrow]
[chk-dpl] :: [env_end]
[chk-dpl] :: [volume_mounts_start]
[chk-dpl] :: [www-data /var/www]
[chk-dpl] :: [volume_mounts_end]
[chk-dpl] :: ==================================================================
[task check] &amp;gt;&amp;gt;&amp;gt; check env
[task check] stdout match (r) &amp;lt;[DEMO_FAREWELL=Such a sweet sorrow]&amp;gt; True
[task check] stdout match (r) &amp;lt;[DEMO_GREETING=Hello from the environment]&amp;gt; True
[task check] &amp;gt;&amp;gt;&amp;gt; check volume mounts
[task check] stdout match (r) &amp;lt;[www-data /var/www]&amp;gt; True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Sparrow &lt;code&gt;k8s-deployment-check&lt;/code&gt; plugin allows one to test k8s infrastructure by just writing a simple piece of Raku code. The full &lt;a href="https://sparrowhub.io/plugin/k8s-deployment-check/0.000001"&gt;documentation&lt;/a&gt; is available at SparrowHub site. &lt;/p&gt;

&lt;p&gt;I am going to add more features eventually. &lt;/p&gt;

&lt;p&gt;Under the hood Sparrow uses Raku regular expressions to verify resources structure, this allows to write even more sophisticated checks. &lt;/p&gt;

&lt;p&gt;For example, to check that a container run command has python 2nd or 3rd version one can write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  command =&amp;gt; "regexp: '/usr/bin/python' 2|3"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stay tuned and as usual I'd like to hear your feedback&lt;/p&gt;




&lt;p&gt;Alexey&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>raku</category>
      <category>testing</category>
    </item>
  </channel>
</rss>
