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
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
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";
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
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 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 failBird 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;
And here an example of more lsof
based test report:
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
:
service-is-running "nginx";
service-is-enabled "nginx";
service-listen-to "nginx", 443;
service-listen-to "rakudo", 5000, True;
bird --host=sparrowhub.io
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