Child pages
  • How To Create Custom Server Notifications

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents
stylenone

Note
titleNote:

We added this functionality in cPanel & WHM version 64.

Warning
titleWarnings:
  • This feature is a technology preview. Functionality may change in future versions.
  • This feature is intended for advanced users.

Overview

This document outlines how to create a server status plugin for cPanel & WHM version 64 and later. This plugin sends cPanel & WHM server alert notifications to an Internet Relay Chat server, Slack, or related service. The notification plugin consists of two Perl modules. The following steps describe how to create and configure these modules.

Create the plugin

Warning
titleImportant:
  • The Provider module must be a subclass of the Cpanel::iContact::Provider module.
  • You do not need knowledge of the ancestor module.
Section
Column
width72px

Column

Create the Schema module

To create the first Perl module (Schema), perform the following steps:

  1. Create a Perl module in the following directory, where $MODULE_NAME represents your new module's name:

    Code Block
    /var/cpanel/perl/Cpanel/iContact/Provider/Schema/$MODULE_NAME.pm
  2. Expand, and then use the following module as a an example for your module:

    Note
    titleNote:

    If your Schema module requires external modules, place them within the checkval functions that they intend to use.

    Code Block
    languageperl
    linenumberstrue
    collapsetrue
    package Cpanel::iContact::Provider::Schema::Example; # Change 'Example' to your Service name 
    use strict;
    use warnings;
     
    # Use any modules from our installed CPAN modules here.
     
    sub get_settings {
        return {
            'EXAMPLEAUTHTOKEN' => {
                'shadow'   => 1, # Flag for saving to /etc/wwwacct.conf.shadow or /etc/wwwacct.conf
                'type'     => 'password', # This maps to an HTML input tag's "type" attribute. Perfect for things like passwords or API bearer tokens.
                'checkval' => sub {
                    # Not really much to do here, since I'm not actually aware of a good validation regex for these tokens.
                    my $value = shift();
                    # Do some validation here to make sure $value is either a) a sanitized version of what was input via the UI OR
                    # b) a blank string, as it failed to validate.
                    # NOTE: Do not establish whether the parameter is *valid* for your service (in this example). Instead, this ensures that you format things the way you want them.
                    # As an example, you can input non-resolving email addresses in for the email notification field in Basic Setup, it will just fail to send when we go to actually do that.
                    # Generally we expect integrators to follow this model as well. To reject an email address because it does not follow the RFC for a valid address string for example, would make sense here though.
                    ...
                    return $value;
                },
                'label' => 'Example Service Auth Token',
                'help' => 'Some string that would tell people how to obtain this, what it should look like, etc.',
            },
            'EXAMPLESERVICEHOST' => {
                'shadow'   => 1,
                'type'     => 'text',
                'checkval' => sub {
                    my $value = shift();
                    ...
                    return $value;
                },
                'label' => 'Example Service API URI',
                'help' => 'Some string that would tell people how to obtain this, what it should look like, etc.',
            },
            # NOTE to 3rd party integrator - Only have one property prefixed with CONTACT, as that one will be the 'triggering' property for notifications.
            # In the logs, the TYPE of the notification will show up as CONTACT<NAME> where <NAME> is your TYPE.
            'CONTACTEXAMPLE' => {
                'name'     => 'Example', # Needed to tell cPanel what provider module to load over in /var/cpanel/perl/Cpanel/iContact/Provider/
                'shadow'   => 1,
                'type'     => 'text',
                'checkval' => sub {
                    my $value = shift();
                    ...
                    return $value;
                },
                'label' => 'Example Service user to notify',
                'help' => 'Some string that would tell people how to obtain this, what it should look like, etc.',
            }
        };
    }
     
    sub get_config {
        return {
            'default_level'    => 'All', # Maps to what you'd see in the WHM >> Contact Manager UI as the default notification level. In /var/cpanel/clevels.conf, this would be translated to '3'.
            'display_name'     => 'Example', # Maps to what your provider shows up as in the WHM >> Contact Manager UI.
            'icon_name'        => 'Example', # Maps to what your icon is named. Currently irrelevant, as it does nothing to help your icon load, and falls back to 'display_name' above if not set.
            'icon'             => ... # A long Data URI (ex. "data:image/png;base64,$my_image_base64"). Thankfully these only display at 16x16px, so you can scale down the image first.
        };
    }
     
    1;
  3. Input relevant information in the key subroutines: get_settings() and get_config()

    Note
    titleNote:

    The target service (for example, Slack) uses this module to validate your provider's settings and configuration, and to establish how to present the information in the user interface.

 


 

Section
Column
width72px

Column

Create the Provider module

  1. Create the second Perl module (Provider) in the following directory, where $MODULE_NAME represents your new module's name:

    Code Block
    /var/cpanel/perl/Cpanel/iContact/Provider/$MODULE_NAME.pm
  2. Expand, and then use the following module as a an example for your module:

    Code Block
    languageperl
    linenumberstrue
    collapsetrue
    package Cpanel::iContact::Provider::Example;
    use strict;
    use warnings;
    
    # You must use the following, as all iContact providers are subclasses of this.
    use parent 'Cpanel::iContact::Provider';
      
    # You *may* also want to use some CPAN modules here for contacting your service,
    # in particular, one of the WebService, LWP/HTTP or Net namespaced modules.    # (See NOTE: below) Try::Tiny would probably be nicer than block eval too.
    
    # NOTE: We strongly recommended that you require *all* external dependencies
    # at runtime. These modules load every time iContact notifications are sent if
    # you 'use' them. When you 'use' modules, you can negatively impact the memory
    # footprint of the parent process responsible for sending iContact
    # notifications.
    
    sub send { # Here is where we define how to reach out and touch your service.
        my ($self) = @_;
      
        # NOTE: If you use Data::Dumper, get the output of this hashref --
        # the 'html_template' contents may corrupt your tty due to some of the
        # symbols translating into control codes for the terminal.
        # Just run 'reset' on your terminal to clear any corruption of that 
        # (or just don't dump that before decoding the UTF8 chars within it).
    
        # This hashref contains the recipients ('to' arrayref) and the processed
        # notification templates, among other things.
        my $args_hr = $self->{'args'};
      
        # This will contain any of the non-CONTACT prefixed properties you defined
        # in the schema module.
        my $contact_hr = $self->{'contact'};
      
        my @errs;
      
        my $subject_copy = $args_hr->{'subject'};
        my $body_copy    = ${ $args_hr->{'text_body'} };
    
        require Encode;
        my $subject      = Encode::decode_utf8( $subject_copy, $Encode::FB_QUIET );
        my $body         = Encode::decode_utf8( $body_copy, $Encode::FB_QUIET );
      
        foreach my $destination ( @{ $args_hr->{'to'} } ) {
            eval {
                # Try to do something to contact your service and deliver the
                # notification payload here. The author *should* die within this
                # block if something returns a failure response but doesn't die.
                my $response;
                $self->_send( 
                    'destination' => $destination,
                    'subject' => $subject,
                    'content' => $body 
                ) || die "Sending to $destination failed: " . $self->_last_error();
            };
            push( @errs, $@ ) if $@;
        }
      
        # After all notification send attempts complete, die if one or more
    	# failed
        if (@errs) {
            die "One or more notification attempts failed. Details below:\n"
              . join( "\n", @errs );
        }
      
        return 1;
    }
      
    # Ensure that you define all of the other internal methods defined below if you
    # need them. You will notice in my example that I had a _send and _last_error 
    # subroutine. How you wish to implement these is up to you, however.
    ...
      
    1;
  3. Input relevant information in the key subroutine: send()

    Note
    titleNote:

    This module defines how your provider communicates with your service, and uses the settings we defined in our Schema module.

Additional documentation

Localtab Group
Localtab
activetrue
titleSuggested documentation
  • Contact Manager — This interface allows you to specify when your server sends notifications for each communication type, and the importance of each type of alert.
  • Guide to WHM Plugins — An overview of WHM plugin workflow, files, and icons.
Localtab
titleFor cPanel users

Content by Label
showLabelsfalse
max5
showSpacefalse
cqllabel in ("server","thirdpartysoftware") and label = "cpanel" and space = currentSpace()

Localtab
titleFor WHM users

Content by Label
showLabelsfalse
max5
showSpacefalse
cqllabel in ("server","thirdpartysoftware") and label = "whm" and space = currentSpace()

Localtab
titleFor developers

Content by Label
showLabelsfalse
max5
showSpacefalse
cqllabel in ("server","thirdpartysoftware") and space = "SDK"