Bird - Raku DSL for infrastructure testing
Tags: testing, raku, devops, automation
Published: 2021-08-13 17:46:29

---
title: Bird - Raku DSL for infrastructure testing 
published: true
description: How to test Linux servers infrastructure using Bird
tags: testing, Raku, devops, automation
cover_image: https://raw.githubusercontent.com/melezhik/images/master/bird-report2.png
---

[Bird](https://github.com/melezhik/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](raku.org/) language and efficient - it does not require any extra dependencies on a target host.

Let's get started.

# Installation

```bash
zef install --/test Bird
```

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:

```bash
export SP6_REPO=https://sparrowhub.io/repo
s6 --index-update
```

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`:

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

# check if nginx service is enabled
service-is-enabled "nginx";
```

Test is a valid Raku code with [functions](https://github.com/melezhik/bird/blob/master/documentation/dsl.md) exported by Bird. In this example we check that `nginx` service has started and added to autostart. 

Now let's run the test:

```bash
bird --host=sparrowhub.io
```

```
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
```

# 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](https://github.com/melezhik/Sparrow6/blob/master/documentation/dsl.md) 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`:

```perl
service-listen-to "nginx", 443;
```

And here an example of more `lsof ` based test report:

```bash
bird --host=sparrowhub.io
```

```
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
```


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

`nano rules.pl6`:

```perl
service-is-running "nginx";
service-is-enabled "nginx";
service-listen-to "nginx", 443;
service-listen-to "rakudo", 5000, True;
```

```bash
bird --host=sparrowhub.io
```

![bird report](https://raw.githubusercontent.com/melezhik/images/master/bird-report2.png)

# 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](https://github.com/melezhik/bird/blob/master/documentation/dsl.md)!

---

Thank you for reading.

Alexey