Using Perl Dancer and Docker to create simple monitoring system

I needed a simple system to monitor events. I wanted to have a system where I can specify that object with some name is 'ok' or 'fail'. And I wanted the system to be able to expire statuses. In case there is no data for the object for a long time then the status should be automaticly changed to 'unknown' — to handle situations when script that sends data breaks.

I looked for several systems, but none suited me well, so I've written my own very simple solution with the name 'curry' (it is named after delicious indian dish, not after Haskell Curry =)

Here is the source code — https://github.com/bessarabov/curry

The system is a web server that is powered by Dancer and the system is bundled into an image with Docker.

I really like this way of creating web apps with Dancer & Docker. Every time there is a new commit in git report Docker Hub automatically builds new image.

Here is the power of Docker, to run curry you need to install Docker and when you have docker installed you need to enter just one (!!!) command to have curry up and running:

docker run --publish 15000:3000 bessarabov/curry:1.0.0

This command downloads image from Docker Hub and runs it. This will create web server on port 15000 on your Docker (in case of linux the Docker usually works on 127.0.0.1, is case of mac you can find our Docker ip with the command boot2docker ip and in case of windows read the docs).

This way of running is super simple and it works pretty well to play a bit with this project, but in production you should do several more things. First of all you need to create persistent storage for curry. Curry stores all its data in sqlite database stored in file. To make persistend storage you should store that file outside the docker container (more details in the docs). The other thing that you may like to do in prodoction environment is to add authorization and to run it on https.

So, we have curry up and running, I would like to show several real life examples.

Setting the object with the name 'zero_inbox' to 'ok':

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/set?path=zero_inbox&status=ok&expire=1d"

You can see that we also specified "expire=1d". You must specify this parameter with your first request. The "X-Requested-With" header is used to prevent CSRF attacks.

Let's set one more object:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/set?path=jenkins&status=fail&expire=1d"

So now we have information about statuses of two object. Curry has several endpoints that allows get information about current situation.

With endpoint "get" you can get info about all objects with problems:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get"

It will return:

{
   "success" : true,
   "result" : {
      "status" : "fail",
      "objects" : [
         {
            "path" : "jenkins",
            "status" : "fail"
         }
      ]
   }
}

True value for "success" tells us that endpoint worked fine and gave us answer that we can see in "result" value. "result.status" is "fail" that means that we have some objects with statues "fail" or "unknown". In the "result.objects" we have an array with the broken objects.

There is also an endpoint "get_all". It has the exact answer structure, but gives information about all objects:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get_all"

{
   "success" : true,
   "result" : {
      "status" : "fail",
      "objects" : [
         {
            "path" : "jenkins",
            "status" : "fail"
         },
         {
            "path" : "zero_inbox",
            "status" : "ok"
         }
      ]
   }
}

Lets set that jenkins is fixed (as you can see for the second request we can not specify "expire"):

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/set?path=jenkins&status=ok"

Now we have two objects in curry and all of them have "ok" status. We can check that with "get" endpoint:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get"

{
   "success" : true,
   "result" : {
      "status" : "ok",
      "objects" : []
   }
}

There is one more endpoint in curry that allow inspecting the current situation. It is endpoint "get_object" that returns all known info about the object:

curl -H "X-Requested-With: XMLHttpRequest" "http://curry:15000/api/1/get_object?path=jenkins"

{
   "success" : true,
   "result" : {
      "path" : "jenkins",
      "status" : "ok",
      "expire" : "1d",
      "history" : [
         {
            "status" : "fail",
            "dt" : "2015-02-09 14:23:23"
         },
         {
            "dt" : "2015-02-09 14:33:41",
            "status" : "ok"
         }
      ]
   }
}

So this is all that curry can do. It is just a simple storage of the objects statuses. There is no webinterface — one can use JSON endpoint and add it to existing dashboards.

So, here is my tiny project and I would be extremely happy to hear from you what do you think. Please you the comments, or write GitHub Issue or email me.

blogs.perl.org and https

I'm living in Moscow, Russian. Here we have Underground, a rapid transit system. Recently there appeared free WiFi. You just need to connect some WiFi spot, then accept the Licence agreement and you can use Internet.

Yesterday I've opened blogs.perl.org at my mobile phone and here is what I've seen:

At the bottom of the screen the ad has appeared. A small investigation showed that blogs.perl.org is wo…

pause.cpan.org is not working. Does somebody know something?

Yesterday I wanted to upload d new release to CPAN, but I could not do it because http://pause.cpan.org/ is down.

This site is still down.

There are several posts on twitter, so it is just me:

* https://twitter.com/burakgursoy/status/421089874377072640
* https://twitter.com/kentnl/status/420871801053253632
* https://twitter.com/thaljef/status/421155094873…

Test::Whitespaces

Perl is very flexible in may ways including whitespaces. Perl does not force you to use tab or spaces. The script works fine no matter if it has DOS or UNIX line breaks.

But there are some good practices. I preffer these rules:

  • every line ends with "\n" (including the last line)
  • UNIX way for new lines (only "\n", not "\r\n")
  • no tabs, but 4 spaces instead
  • no trailing spaces
  • no empty lines in the end of the file

I want to make sure that all that rules are followed in my source code. So I've written ="https://metacpa…

$#boo

As we all know $#boo returns the last index of array @boo.

It is clear why we have the prefixes '$' and '@' ('$' is like the first
letter of the word 'scalar' and the '@' is like the first letter of the word
'array').

But is it unclear why there is '#' after the dollar sign. I've checked out
the perl v 1.0 and in the man page there is such text:

> you may find the length of array @days by evaluating "$#days", as in csh.
> [Actually, it's not the length of the array, it's the subscript of the last
> element, since there is (ordinarily) a 0…