Sparrowdo - is a configuration management tool written on Perl6. It's an efficient tool to automate servers deployments. Have you written a Perl5 application? Don't bother yourself with finding proper deployment tool. Sparrowdo to the rescue!

In the rest of the post I am going to give a step by step instruction on how to use Sparrowdo to deploy Mojolicious application with a source code fetched from Git. What we're going to do is:

Fetch the source code from GitHub repository.

Install CPAN dependencies by using Carton/cpanfile.

Keep all the files and run the processes under dedicated system user.

Set up systemd script to run web application as a daemon.

Set up a file with passwords to be used in application's digest access authentication.

Are you ready? Off we go.

Sparrowdo Install

Sparrowdo is Perl6 module so is installed by zef manager:



$ zef install Sparrowdo

Once Sparrowdo is installed we should start writing Sparrowdo scenario, let's create a file named sparrowfile , located in the current working directory:



$ nano sparrowfile

We run sparrowdo scenario remotely on the target host like this:



$ sparrowdo --host=$remote-host

Sparrowdo console client supports many options, follow documentation for details.

The minimum of options is a remote host being deployed or --localhost_mode if we run deploy at the localhost.

Application source code

This is a simple Mojolicios application with a single endpoint which if a user is successfully authenticated returns "hello world":



#!/usr/bin/perl use Mojolicious::Lite; use strict; plugin 'digest_auth', realm => 'app', expires => 120, allow => '.htdigest' ; get '/' => sub { my $c = shift; return unless $c->digest_auth; $c->render( text => 'hello world' ); }; app->start;

Dedicated system user

We're going to keep all the data and run our application under a dedicated system user, so let's create it:



user "web-application";

Fetching the source code from SCM

It is simple just add this:



git-scm 'git@github.com:melezhik/my-app.git', %( to => '/home/web-application/projects', user => "web-application" );

To make this work we also need to create a directory ~/projects , so let's add this line beforehand:



directory "/home/web-application/projects", %( owner => "web-application", group => "web-application" )

Installing dependencies

All the dependencies are declared via cpanfile:



$ cat cpanfile requires 'Mojolicious::Lite'; requires 'Mojolicious::Plugin::DigestAuth';

So just run a carton installer:



bash "cd /home/web-application/projects/my-app && carton", %( description => "update cpan dependencies by carton", user => "web-application" );

To install all declared CPAN dependencies into ./local directory.

Populating a file with passwords

We use digest access authentication in our application. This, first of all we need to create a local file with credentials:



$ htdigest -c .htdigest $realm $username

Where $real - authentication realm is specific for an application, and the real command to create a login/password entry for login user would be:



$ htdigest -c .htdigest app user # let's set password as `1`

Don't forget to "hide" .htdigest from Git, so not to commit it occasionally:



$ echo .htdigest >> .gitignore

All is left to do is to populate password file to remote server by sparrowdo,

we also have to store the file under the application root:



file '/home/web-application/projects/.htdigest', %( content => slurp '.htdigest', owner => 'web-application', group => 'web-application' );

We are almost all set, the last thing we need to is set up systemd service

Set up systemd script and run application service

With sparrowdo it's just as simple as adding few lines of code:



systemd-service "my-app", %( user => "my-app", workdir => "/home/web-application/projects/my-app", command => "/bin/bash --login -c 'cd /home/web-application/projects/my-app && carton exec ./app.pl daemon --listen http://0.0.0.0:3000'" ); service-restart "my-app";

This code ensures that our application will be accessible as 0.0.0.0:3000.

Let's give it a run

Here is an example of sparrowdo report for the localhost deployment:



$ sparrowdo --local_mode --format=production

The output:



running sparrow tasks on 127.0.0.1 ... target OS is - ubuntu push [task] create user web-application OK push [task] create directory /home/web-application/projects OK push [task] fetch from git source: https://github.com/melezhik ... OK push [task] create file /home/web-application/projects/my-app/.htdigest OK push [task] update cpan dependencies by carton ... OK push [task] create template /etc/systemd/system/my-app.service OK push [task] restart service my-app OK SPL file /opt/sparrow/sparrow.list is empty get index updates from SparrowHub ... OK set up task box file - /home/melezhik/.sparrowdo//opt/sparrow/task-box.json - OK public@user is uptodate (0.2.1) public@directory is uptodate (0.1.5) public@bash is uptodate (0.1.7) public@file is uptodate (0.0.6) public@templater is uptodate (0.0.11) Installing modules using /opt/sparrow/plugins/public/templater/cpanfile Complete! Modules were installed into /opt/sparrow/plugins/public/templater/local public@service is uptodate (0.1.15) running task box from /opt/sparrow/sparrow-cache/task-box.json ... 2017-11-14 16:11:03 : [task] create user web-application [path] modules/change/ 2017-11-14 16:11:03 : [task] create directory /home/web-application/projects [path] modules/create/ 2017-11-14 16:11:03 : [task] fetch from git source: https://github.com/melezhik ... [path] modules/bash-command/ [params] envvars: 2017-11-14 16:11:04 : [task] create file /home/web-application/projects/my-app/.htdigest [path] / 2017-11-14 16:11:05 : [task] update cpan dependencies by carton ... [path] modules/bash-command/ [params] envvars: 2017-11-14 16:11:05 : [task] create template /etc/systemd/system/my-app.service [path] modules/generate-content/ 2017-11-14 16:11:05 : [task] create template /etc/systemd/system/my-app.service [path] / 2017-11-14 16:11:06 : [task] restart service my-app [path] modules/stop/ [params] os:debian service:my-app 2017-11-14 16:11:06 : [task] restart service my-app [path] modules/start/ [params] os:debian service:my-app

Checks

Now lets check our web app, it should be visible as process:



$ sudo ps aux | grep web-application web-app+ 29642 0.0 0.0 17808 7180 ? Ss 16:11 0:00 /bin/bash --login -c cd /home/web-application/projects/my-app && carton exec ./app.pl daemon --listen http://0.0.0.0:3000

And is accessible by http:



$ curl --digest -uuser:1 127.0.0.1:3000 hello world

Thank you for reading. I hope this post was useful.