---
layout: docs
title: Scripted Dashboardd
lightbox: true
---


== Scripted Dashboards

{% include new_since.ad version="2.10" %}
Static Dashboards are a good solution is most cases, but sometimes you need some
extra dynamic and a way to constantly update the dashboard. Scripted Dashboards
can be used to dynamically generate dashboards on the fly.


=== Basics

A scripted dashboard is written in perl and the dashboard file must be executable.
Scripted dashboards cannot be edited through the web gui, instead the json source
of the dashboard is generated by perl code on the fly. While doing this, the
perl code has full access to hosts and services or hostgroups via Thruks Livestatus
connection pool and whatever is possible with Perl, ex. database querys.

The 5.tab is a scripted dashboard in this example:
------
root@host:/etc/thruk %> ls -la panorama/
-rw-r-----  1 thruk thruk 22185 Aug 12 10:15 1.tab
-rw-r-----  1 thruk thruk 22108 Aug 12 10:15 2.tab
-rw-r--r--  1 thruk thruk 17170 Aug 12 10:15 3.tab
-rwxr-xr-x  1 thruk thruk  5307 Aug 12 10:15 5.tab
------

=== Perl
A scripted dashboard basically looks like this:

------
# title:  Dashboard Title
# user:   thrukadmin
# groups: [{"*" : "read-only"}]

# perl code:
$dashboard = load_data();
# ... add panlets dynamically here

# static basic dashboard:
__DATA__
{
   "tab" : {
      "xdata" : {
         "refresh" : 10
      }
   }
}
------

The first 3 lines describe the dashboards meta data. The meta data is static,
otherwise the dashboard would had to be run everytime a simple list of available
dashboards is requested.

 - title: the title of the dashboard
 - user: owner of the dashboard
 - groups: group permissions. see the above example to create a readonly public dashboard.

To get an idea of how the finished dashboard chould look like, just have a look at
the existing dashboards.

The perl code section usually starts with `$dashboard` which will be loaded from
the `__DATA__` section. Then you can add panels and icons.
At the end of the code section, `$dashboard` must contain the complete dashboard.

==== Functions
You can create your own functions but they have to be a anonymous function.

------
# create function
my $_functionname = sub { ... };

# use function
&{$_functionname}($args, ...);
------

Besides that, you can of course load perl modules and use functions from them.

==== Predefined Functions

===== load_data

Returns the static dashboard from the `__DATA__` block of the dashboard file.

===== get_screen_data

Returns the screen size of current user. Can be used to adjust layout to screen.
Width/Height is the actual available size of the screen for dashboard excluding
the size of the tabbar. Offset_x/y defines the start of the dashboard. For example
in tabbed mode, the offset y is 25px to compensate the tab bar.
Grid snap is the grid size.

------
   {
      width:    <height in px>,
      height:   <width in px>,
      offset_x: <dashboard offset x in px>,
      offset_y: <dashboard offset y in px>,
      gridsnap: <grid snap in px>,
      tabbar:   <1 if tabbar is visible, 0 if not>
   }
------



==== Refresh

There are two types of refresh.

===== Icon Refresh Interval

The icon refresh interval can be changed like this:

------
$dashboard->{'tab'}->{'xdata'}->{'refresh'} = 30;
------

Which sets every icon to a 30 second refresh interval.

===== Dashboard Refresh Interval

The second refresh interval is the dashboard itself. If a dashboard is already
open in a browser, it does not refresh the dashboard json automatically. Instead
it checks the timestamp with every request and reloads the dashboard if that
timestamp has changed. If the timestamp is not set, then the last modified date
of the file itself will be used.

It is usually a good idea to delay the updates a little bit by updating the
timestamp only every few seconds like this:

------
$dashboard->{'ts'} = time()-time()%30;
------

This will make open dashboards reload the dashboard source every 30 seconds.


=== Other Script Languages
{% include new_since.ad version="2.38" %}
Since release 2.38 you can write your dashboards in any language you like. The
tab file has to be executable and must return the json decodable representation
of the dashboard.
See the shell script example at the end of this page.


=== Environment
{% include new_since.ad version="2.38" %}
The following environment variables are set:

   - `DASHBOARD`          = the id number of the dashboard
   - `DASHBOARD_FILE`     = path to source file
   - `REMOTE_USER`        = user name of current user requesting the dashboard
   - `REMOTE_USER_GROUPS` = contact groups for the user above


=== Debugging
{% include new_since.ad version="2.38" %}
The thruk cli tool can be used to evaluate the scripted dashboard.

print json data of dashboard nr 5.:

   %> thruk panorama json 5

print json data of dashboard with given path:

   %> thruk panorama json ~/etc/thruk/panorama/5.tab

=== Examples

==== ISS Position

The first real example creates a geo map with the actual position of the ISS Spacestation.
This example also shows how to use base64 decoded inline images for static icons.

++++
<a title="dashboard" rel="lightbox[dashboard]" href="dashboard/iss.png"><img src="dashboard/iss.png" alt="context menu" width="35%" height="35%" /></a>
<br style="clear: both;">
++++

------
# title:  ISS Position
# user:   thrukadmin
# groups: [{"*" : "read-only"}]

# get actual position
$dashboard = load_data();
my $panlet_1 = $dashboard->{'panlet_1'}->{'xdata'};

# get actual position
my $raw = `curl -s http://api.open-notify.org/iss-now.json`;
my $data = decode_json($raw);

# set current iss position
$panlet_1->{'map'}->{'lat'} = $data->{'iss_position'}->{'latitude'};
$panlet_1->{'map'}->{'lon'} = $data->{'iss_position'}->{'longitude'};
$panlet_1->{'label'}->{'labeltext'} = sprintf("<center>Lat: %.3f / Lon: %.3f<br>Last Update: %s</center>",
                                               $panlet_1->{'map'}->{'lat'},
                                               $panlet_1->{'map'}->{'lon'},
                                               POSIX::strftime("%H:%M:%S UTC", gmtime($data->{'timestamp'})),
                                               );

# set map center
my $_nearest_int = sub {
    my($x, $val) = @_;
    $x = int($x);
    my $rem = $x % $val;
    return($x-$rem);
};
$dashboard->{'tab'}->{'xdata'}->{'map'}->{'lat'}  = &{$_nearest_int}($data->{'iss_position'}->{'latitude'},  20);
$dashboard->{'tab'}->{'xdata'}->{'map'}->{'lon'}  = &{$_nearest_int}($data->{'iss_position'}->{'longitude'}, 20);
$dashboard->{'tab'}->{'xdata'}->{'map'}->{'zoom'} = 4;

# make dashboard update every 30 seconds
$dashboard->{'ts'} = time() - time() % 30;

__DATA__
{
   "tab" : {
      "xdata" : {
         "refresh" : 10,
         "map" : {},
      }
   },
   "panlet_1" : {
      "xdata" : {
         "appearance" : {
            "type" : "icon"
         },
         "cls" : "TP.StaticIcon",
         "general" : {
            "src" : "data:image/png;base64, "
         },
         "label" : {
            "bgcolor" : "#7eb4d9",
            "bordercolor" : "#71a4c9",
            "bordersize" : 1,
            "fontcolor" : "#000000",
            "fontitalic" : "",
            "fontsize" : 12,
            "labeltext" : "",
            "orientation" : "horizontal",
            "position" : "below",
         },
         "popup" : {
            "type" : "off"
         },
         "layout" : {},
         "map" : {}
      }
   }
}
------


==== Hostgroups Overview

This example fetches the list of hostgroups and creates an icon for each of it.
This dashboard does not even have a __DATA__ structure and creates the dashboard
completely from the script.

++++
<a title="dashboard" rel="lightbox[dashboard]" href="dashboard/hostgroups.png"><img src="dashboard/hostgroups.png" alt="context menu" width="35%" height="35%" /></a>
<br style="clear: both;">
++++

------
# title:  Scripted Hostgroups
# user:   thrukadmin
# groups: [{"*" : "read-only"}]

$dashboard = load_data();

# fetch all hostgroups sorted by name
my $groups = $c->db->get_hostgroups(sort => {'ASC' => 'name'});
my $nr = 0;
my $x  = 20;
my $y  = 30;
for my $group (@{$groups}) {
    $dashboard->{'panlet_'.$nr} = {
        "xdata" => {
            "appearance" => {
                "iconset" => "default_64",
                "type" => "icon"
            },
            "cls" => "TP.HostgroupStatusIcon",
            "general" => {
                "hostgroup" => $group->{'name'},
            },
            "label" => {
                "bgcolor" => "#cccccc",
                "bordercolor" => "#aaaaaa",
                "bordersize" => 1,
                "fontbold" => "",
                "fontcolor" => "#000000",
                "fontfamily" => "inherit",
                "fontitalic" => "",
                "fontsize" => 10,
                "height" => "",
                "labeltext" => "<center>".$group->{'name'}."</center>",
                "offsetx" => 0,
                "offsety" => 42,
                "orientation" => "horizontal",
                "position" => "center",
                "width" => "60"
            },
            "layout" => {
                "x" => $x,
                "y" => $y,
            }
        }
    };
    $x = $x + 70;
    if($x > 500) {
        $x = 20;
        $y = $y + 90;
    }
    $nr++;
}

# update every 10 seconds
$dashboard->{'ts'}                          = time()-time()%10;
$dashboard->{'tab'}->{'xdata'}->{'refresh'} = 10;
------


==== Shell Scripted Dashboard

This example is a simple shell script which has label with the current time.

------
#!/bin/bash
# title:  Scripted Bash
# user:   thrukadmin
# groups: [{"*" : "read-only"}]

LABEL="Dynamic dashboard<br>generated at: $(date)";

cat<<EOT
{
   "file_version" : 2,
   "panlet_1" : {
      "xdata" : {
         "appearance" : {
            "type" : "icon"
         },
         "cls" : "TP.TextLabelWidget",
         "label" : {
            "bgcolor" : "",
            "bordercolor" : "",
            "bordersize" : 1,
            "display" : "always",
            "fontbold" : "",
            "fontcenter" : "",
            "fontcolor" : "#000000",
            "fontfamily" : "",
            "fontitalic" : "",
            "fontsize" : 14,
            "height" : "",
            "labeltext" : "$LABEL",
            "offsetx" : 0,
            "offsety" : 0,
            "orientation" : "horizontal",
            "position" : "top-left",
            "roundcorners" : "",
            "width" : ""
         },
         "layout" : {
            "center" : "centered",
            "x" : 4,
            "y" : 28,
         },
         "link" : {}
      }
   },
   "tab" : {
      "xdata" : {
         "refresh" : "90",
         "title" : "Dashboard"
      }
   },
   "ts": $(date +%s)
}
EOT
------
