Action Menu

new in release v1.86

The Action Menu is a way to create custom icons and menus for every host or service. You may add multiple action icons or even multiple menus for each host or service. You can then open links or trigger server actions from that menu or icons.

Action Menu

Adding an Action Menu

There are 3 ways to add an action menu to a host or service.

  • set the menu directly by the _THRUK_ACTION_MENU custom variable

  • reference an existing menu from the action_menu_items by a _THRUK_ACTION_MENU custom variable

  • use apply rules from action_menu_apply

The are some examples in the configuration documentation.

Server Actions

Server Action can be triggered from icons or menu items by using a pseudo url like this in your action urls. See the configuration section on how and where to set this link.

    server://*scriptname*/argument1/argument2/...

To make this work, you need to define that scriptname in your thruk_local.conf:

  <action_menu_actions>
      scriptname   = /usr/local/bin/sample.sh $HOSTNAME$ $SERVICEDESC$
  </action_menu_actions>

When somebody clicks on that link, Thruk will start the sample.sh script like:

    /usr/local/bin/sample.sh <hostname> <servicename> argument1 argument2

First it uses the complete commandline from the thruk_local.conf and replaces all available macros. Then it adds the arguments from the link configuration.

See Macros for a list of all available macros.

Scripts

The scripts can do whatever they want. However you should consider a few things:

  • Make the script exit quickly. Thruk waits for the script to return. Long running tasks should be started in the background.

  • Give the user useful feedback on STDOUT

  • Exit codes should be zero if OK and greater than zero on errors.

script output

Script output will be displayed as user response which allows the script to give feedback to the user. HTML is allowed and will be used in the output.

Authorization / Security

The Script will be run whenever the user has access to the given host and service. Its general good advice to check the $REMOTE_USER and/or $REMOTE_USER_GROUPS environment variables before running critical scripts. Macros used in the command line defined in your config and the REMOTE_USER variables can be trusted. Variables supplied by the url can easily be faked and are considered unsafe.

You can use the action_wrapper script from the examples folder to check for valid users and groups.

  <action_menu_actions>
      scriptname   = .../examples/action_wrapper -u omdadmin -g Admins,Operators ./sample.sh $HOSTNAME$ $SERVICEDESC$
  </action_menu_actions>

Available standard environment variables are listed on the CLI Environment page.

Dynamic Javascript Menus

new in release v2.24

Since version 2.24 you can use javascript to dynamically create menus. Basically you create a file ending on .js in your action_menus folder. The first function will be called and expected to return a json structure with the actual menu.

Althought the first function will be called to generate the menu, the file may contain multiple functions, for example to generate submenus.

The first function in the file must return an array of (action_menu_items). The menu itself can be a function again to create more dynamic menus.

All defined functions are running in the same namespace, so make sure your functions use uniq names over all your menus. Best practice is to use the filename as prefix.

user data
new in release v3.02

The current user with its roles and groups is available in the thruk_user variable and can be used to make your menu depend on user attributes. ex.:

{
  "name":"thrukadmin",
  "groups":["example"],
  "roles":["authorized_for_admin","authorized_for_all_host_commands",,...],
  "can_submit_commands":true,
  "readonly":false
}

A very simple example:

action_menus/js_basic_menu.js
function js_basic_menu(data) {
    return({
      "icon":"../themes/{{theme}}/images/dropdown.png",
      "title": "javascript menu",
      "menu":[{
          "icon":"uil-link",
          "label":"test menu item",
          "action":"http://..."
        }]
    });
}

A more advanced example with dynamic submenus. Menu callbacks may return thenables (in jQuery context). This makes it possible to do ajax requests and use the result to create submenus. This example creates a submenu listing all hosts.

action_menus/js_adv_menu.js
function js_adv_menu(cfg) {
    return({
      "icon":"../themes/{{theme}}/images/dropdown.png",
      "title": "javascript advanced menu",
      "menu":[
        {
          "icon":"uil-link",
          "label":"test menu item",
          "action":"http://..."
        },
        {
          "icon":"fa-folder",
          "label":"list all hosts",
          "menu": js_adv_menu_submenu
        }
      ]
    });
}

function js_adv_menu_submenu(cfg) {
  return(jQuery.get("../r/hosts?columns=name").then(function(data, textStatus, jqXHR) {
    var result = [];
    jQuery(data).each(function(i, r) {
      result.push({ label: r.name });
    });
    return(result);
  }));
}

Examples

Panorama Dashboard

This is a small example script which uses perl to change the color of a shaped icon.

icon settings

Dashboard Icon

thruk_local.conf
  <action_menu_actions>
    switch_color    = .../switch_color.pl $DASHBOARD_ID$ $DASHBOARD_ICON$
  </action_menu_actions>
switch_color.pl

just changes the color of the icon.

#!/usr/bin/perl

use warnings;
use strict;
use Thruk::Utils;

my $file  = 'var/panorama/'.$ARGV[0].'.tab';
my $data  = Thruk::Utils::read_data_file($file);
my $color = $data->{$ARGV[1]}->{'xdata'}->{'appearance'}->{'shapecolor_ok'};
if($color eq '#CA1414') {
    $color = '#199C0F';
} else {
    $color = '#CA1414';
}
$data->{$ARGV[1]}->{'xdata'}->{'appearance'}->{'shapecolor_ok'} = $color;
Thruk::Utils::write_data_file($file, $data);

print "switched color to $color\n";

Confirmation Dialog

new in release v2.14-2

Using arbitrary attributes, you can easily add a confirmation dialog to your server actions.

action_menus/confirm_restart.json
{
  "icon":"uil-redo",
  "label":"service restart",
  "action":"server://restart_service",
  "onclick": "return(confirm('Really restart service?'));"
}

Hide Menu Item for Readonly Users

new in release v3.02

With the hidden attribute items can be made invisible. server actions. In this example the item is made hidden if the user has the readonly role.

action_menus/hidden_items.json
{
  "icon":"uil-redo",
  "label":"service restart",
  "action":"server://restart_service",
  "onclick": "return(confirm('Really restart service?'));",
  "hidden": thruk_user.readonly
}

Custom Form Elements

Combining the raw html menu item with javascript menus can create any arbitrary menu.

action_menus/js_form_menu.js
function js_menu(d) {
  return({
    "icon":"../themes/{{theme}}/images/dropdown.png",
    "title": "form menu",
    "menu":[
      {
        "icon":"uil-document-info",
        "html":"<div class='flexrow gap-1 flex-nowrap'>"
              +"<b>test</b>"
              +"<input type='text'>"
              +"<button onclick='test_form_handler(this)'>ok</button>"
              +"</div>"
      }
    ]
  });
}

function test_form_handler(btn) {
  // prevent clicking twice
  // and give user some response by adding a loading gif to the button
  jQuery(btn).attr('disabled', true).html("<div class='spinner'>");

  // send user input as server action
  var input = jQuery(btn).prev().val();
  jQuery.post("status.cgi?serveraction=1",{
    link:    'server://NameOfServerAction/'+encodeURIComponent(input),
    host:    action_menu_options.host,
    service: action_menu_options.service,
    backend: action_menu_options.backend,
    token:   CSRFtoken
  }, function(response) {
    // show repsonse
    thruk_message(response.rc, response.msg);

    // close menu again
    action_menu_close();
  });
}

Sending Commands

This example fetches some host details from the rest api and shows a dynamic host menu based on some attributes. It also sends some commands.

action_menus/js_cmd_menu.js
function js_menu(d) {
  return({
    "icon":"../themes/{{theme}}/images/dropdown.png",
    "title": "confirm menu",
    "menu": js_menu_items
  });
}

function js_menu_items(d) {
  // fetch host attributes
  return(
    jQuery.get("../r/sites/"+d.backend+"/hosts/"+d.host)
    .then(function(data, textStatus, jqXHR) {
    var result = [];
    host_data = data[0];
    if(!host_data) {
      return({ 'label': 'host not found?'});
    }

    result.push({ label: d.host+":", disabled: true });

    // add submenu with all parents
    if(host_data.parents.length > 0) {
      parents_menu = [];
      jQuery(host_data.parents).each(function(i, r) {
        parents_menu.push({ label: r, action: "extinfo.cgi?type=1&host="+r });
      });
      var parents = {
        'label': 'parents',
        'menu': parents_menu
      };
      result.push(parents);
    }

    // add submenu with all child hosts
    if(host_data.childs.length > 0) {
      childs_menu = [];
      jQuery(host_data.childs).each(function(i, r) {
        childs_menu.push({ label: r, action: "extinfo.cgi?type=1&host="+r });
      });
      var childs = {
        'label': 'childs',
        'menu': childs_menu
      };
      result.push(childs);
    }

    // add active checks switch
    result.push({
      'label': "active checks",
      'menu': [{
        'label': 'disable active checks',
        'disabled': !host_data.active_checks_enabled,
        'action': function() {
          jQuery.post("../r/sites/"+d.backend+"/hosts/"+d.host+'/cmd/disable_host_check')
                .then(function(data, textStatus, jqXHR) {
                  thruk_message(0, "active checks disabled");
                });
        }
      }, {
        'label':   'enable active checks',
        'disabled': host_data.active_checks_enabled,
        'action': function() {
          jQuery.post("../r/sites/"+d.backend+"/hosts/"+d.host+'/cmd/enable_host_check')
                .then(function(data, textStatus, jqXHR) {
                  thruk_message(0, "active checks enabled");
                });
        }
      }]
    });

    return(result);
  }));
}
Edit page on GitHub