Bird - Raku DSL for infrastructure testing

Alexey Melezhik - Aug 13 '21 - - Dev Community

Bird is a new kid on the block allowing one to test infrastructure using Raku DSL.

It's simple, written on modern and shiny Raku language and efficient - it does not require any extra dependencies on a target host.

Let's get started.

Installation

zef install --/test Bird
Enter fullscreen mode Exit fullscreen mode

Once one installs the Bird they need to do extra step. As Bird relies on ssh-bulk-check Sparrow plugin, they need to set up the one:

export SP6_REPO=https://sparrowhub.io/repo
s6 --index-update
Enter fullscreen mode Exit fullscreen mode

The last step ensures public Sparrow repository is added and Bird will install the plugin when it starts for the first time.

Infrastructure test

nano rules.pl6:

# check if nginx service is running
service-is-running "nginx";

# check if nginx service is enabled
service-is-enabled "nginx";
Enter fullscreen mode Exit fullscreen mode

Test is a valid Raku code with functions exported by Bird. In this example we check that nginx service has started and added to autostart.

Now let's run the test:

bird --host=sparrowhub.io
Enter fullscreen mode Exit fullscreen mode
bird:: [read host from command line] [sparrowhub.io]
bird:: [cmd file] [/root/.bird/285892/cmd.sh]
bird:: [check file] [/root/.bird/285892/state.check]
bird:: [init cmd file]
[repository] :: index updated from file:///root/repo/api/v1/index
[check my hosts] :: check host [sparrowhub.io]
[check my hosts] :: ==========================================================
root@sparrowhub.io's password:
[check my hosts] :: Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-77-generic x86_64)
[check my hosts] :: <<< test_01: service [nginx] is running
[check my hosts] :: YES
[check my hosts] :: >>>
[check my hosts] :: <<< test_02: service [nginx] is enabled
[check my hosts] :: YES
[check my hosts] :: >>>
[check my hosts] :: end check host [sparrowhub.io]
[check my hosts] :: ==========================================================
[task check] verify host [sparrowhub.io] start
[task check] test_01: service [nginx] is running
[task check] stdout match (r) <YES> True
[task check] test_02: service [nginx] is enabled
[task check] stdout match (r) <YES> True
[task check] verify host [sparrowhub.io] end
Enter fullscreen mode Exit fullscreen mode

How Bird does tests?

An interesting thing about Bird is how it does tests. Bird has two execution stages:

  • execute tasks ( lines denoted as check my host)

  • checks tasks output ( lines denoted as task checks)

These 2 stages run one by one, but each of them has a separate meaning.

Execute task checks

Birds would generate Bash commands representing tests that are carried out. The final bash script ( cmd file - /root/.bird/285892/cmd.sh) is generated on the host you run Bird from and then executed over ssh on a target host. Once this stage has finished Bird has an output ([check my hosts] lines ) which is parsed during the next stage.

Check tasks output

During this stage Bird will use prepared task checks rules (check file - /root/.bird/285892/state.check) and run them against the output. Bird will use Sparrow task check DSL to do so.

The parsing and verification steps are executed on the host where Bird runs from.

Once parsing and verification is finished the results are seen as a report ([task check] entries) and in case of any errors the overall test marked as failed.


The logic of test execution at first seems a little bit different from what people would normally have with other tests tools (like goss, testinfra or chef inspec), but it takes just a little time to get used to that and see the benefits:

  • one could see underlying test commands output ([check my hosts] entries), not just tests results, it gives more context, especially once tests fail

  • Bird is a way more easy to develop as it does not rely on rigid data structures and underlying use Raku regexps to check assumptions based on text output and regexp rules.

It takes me literally minutes to add new test methods, say for service tcp/ip port binding, because all I had to do is to parse a lsof command output - https://github.com/melezhik/bird/blob/master/lib/Bird/DSL/Service.pm6#L49-L68

nano rules.pl6:

service-listen-to "nginx", 443;
Enter fullscreen mode Exit fullscreen mode

And here an example of more lsof based test report:

bird --host=sparrowhub.io
Enter fullscreen mode Exit fullscreen mode
bird:: [read host from command line] [sparrowhub.io]
bird:: [cmd file] [/root/.bird/286735/cmd.sh]
bird:: [check file] [/root/.bird/286735/state.check]
bird:: [init cmd file]
[repository] :: index updated from file:///root/repo/api/v1/index
[check my hosts] :: check host [sparrowhub.io]
[check my hosts] :: ==========================================================
root@sparrowhub.io's password:
[check my hosts] :: <<< test_01: service [nginx] listens to port [443]
[check my hosts] :: COMMAND PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
[check my hosts] :: nginx   709     root    8u  IPv6  21734      0t0  TCP *:443
[check my hosts] :: nginx   709     root    9u  IPv4  21735      0t0  TCP *:443
[check my hosts] :: nginx   710 www-data    8u  IPv6  21734      0t0  TCP *:443
[check my hosts] :: nginx   710 www-data    9u  IPv4  21735      0t0  TCP *:443
[check my hosts] :: >>>
[check my hosts] :: end check host [sparrowhub.io]
[check my hosts] :: ==========================================================
[task check] verify host [sparrowhub.io] start
[task check] test_01: service [nginx] listens to port [443]
[task check] stdout match (r) <^^ nginx \s+ \S+ .* '*' ':' 443 $$> True
[task check] verify host [sparrowhub.io] end
Enter fullscreen mode Exit fullscreen mode

Test reports become even more clear if run Bird with color output:

nano rules.pl6:

service-is-running "nginx";
service-is-enabled "nginx";
service-listen-to "nginx", 443;
service-listen-to "rakudo", 5000, True;
Enter fullscreen mode Exit fullscreen mode
bird --host=sparrowhub.io
Enter fullscreen mode Exit fullscreen mode

bird report

Conclusion

I hope you like the Bird and might consider using it in infrastructure testing. I've been constantly adding new methods, you can even check k8s deployments using Bird, checkout documentation!


Thank you for reading.

Alexey

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player