Plug-ins

From ISPWiki

Jump to: navigation, search

Contents

Introduction

Plug-ins are used to add modules to the control panel. This article walks you through the steps involved in creating the module that will work with a list of random lines in the /etc/myconfig file. Using this example you can create custom plug-ins.

Follow the instructions below to add your plug-ins.

First step

Add the XML-document that will describe all the functions that this plug-in processes, as well as all the interface elements required for the module to be displayed in the control panel.

Second step

Write a program or a script that will implement the functions.

Creating XML-document

Locate the XML document that describes the interface of your plug-in into the /usr/local/ispmgr/etc directory and name it BINNAME_mod_xxx.xml, where BINNAME is a name of the control panel's file to be run (ispmgr, billmgr, vdsmgr, etc), and xxx is a random value. For example, myconfig (vdsmgr_mod_myconfig.xml). The document should have UTF-8 encoding and look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
  description of plug-in's function 
  description of the menu elements 
  description of tables and forms 
  description of messages 
</mgrdata>

More information can be found in the article XML (ISPmanager).

Describing plug-in's function

This part of the XML-document defines the name of the program or script that will implement the functions, type of interaction between the program and the control panel, as well as the functions provided in this plug-in. It should look something like this:

<handler name="program" type="type" minlevel="minimal_access_level">
  <func minlevel="minimal_access_level">function1</func>
  <func minlevel="minimal_access_level">function2</func>
  ...
</handler>

The name attribute is the name of the program that will implement the functions, such as myconfig.pl. Provide a method of integration of your control panel and program as The type attribute is a type of integration of your control panel and the program. Two types are currently supported:

cgi
The program has a CGI interface, i.e. receives data from the environment variables or/and standard input (POST).
xml
The program receives an XML-document from the standard input that describes the data that the control panel transfers.

Then you need to define the functions that your plug-in will provide:

List of elements
the table with the toolbar.
Element parameters
the form that is used to add a new element or edit an existing one. It can be used if your module does not handle multiple elements, but is supposed to set up parameters.

Action is a function type that does have the interface elements. It is used to perform an action over one or several elements.

The function name can contain alpha-numeric characters, digits and dots. It must be unique. You can get a list of available functions using the command:

/usr/local/ispmgr/sbin/mgrctl -m BINNAME eventlist

Where BINNAME is the name of the control panel file, such as ispmgr, billmgr, vdsmgr, etc.

The minlevel attribute of the func tag defines a minimal user access level on which this function will be accessible. If the func tag does not contain this attribute, that of the handler tag will be used. If extended procedure is required, specify 0 in this attribute and use your handler to define the access privileges. User data will be available in the handler through environment variables (ENV):

  • AUTHID - session unique number.
  • REMOTE_USER - name of the user who called the function.
  • SESSION_LEVEL - level of access of the user who called the function.

The following environment variables can be used:

  • SESSION_LANG - user interface language.
  • RECORDLIMIT - maximum number of records in the table (from the control panel settings). When creating a table, the plug-in must not form more records in the table than specified in this parameter. If more data are used, the corresponding banner should be displayed.
  • MGR - software product name, such as ispmgr. It can be used, if one plug-in is used in multiple software products.
  • MGR_DISTRIBUTION - full name of the software distribution, such as ISPmanager-Lite.
  • MGR_VERSION - software version.
  • MSG_OSNAME - operating system this software is running on.
  • LICID - license number that can be used for licensing your plug-ins. Please note, if licences are provided for a range of IP-address, several licenses will have the same number.

Describing Menu elements

To access your plug-in, you should create the required element in the control panel menu. Add the following block into your XML-document.

<mainmenu level="access level">
  <node name="category name">
    <node name="function1"/>
    <node name="function2"/>
  </node>
</mainmenu>

In the level attribute specify a figure corresponding to the access level. If you want the module to be accessible in several user levels, add the mainmenu block for each of them.

For the category name provide the name from the name attribute of the node corresponding to the category of the control panel menu described in /usr/local/ispmgr/etc/BINNAME_menu.xml. For example, you want to grant access to the plug-in to all the VPS owners and locate the corresponding module in the "Tools" section. To do that, locate the mainmenu level="5" section and the corresponding section node name="tool". I.e. a category name is the tool value.

Then, you add one or several menu elements into the corresponding section of the control panel menu. Add nodes and for the name attribute provide a function name that should be called when clicking the icon.

Tables and forms

Describe the interface for functions that this plug-in performs. Our test module should allow us to view existing records in the /etc/myconfig file, add new records and edit existing ones. It should also have a removal function, but this function refers to action and does not need the interface.

Add the following block into the XML-document:

<metadata name="function1" type="list" key="filed_name">
  <toolbar>
    <toolbtn func="function2" type="new"  img="t-new.gif" name="new"/>
    <toolbtn func="function2" type="edit" img="t-edit.gif" name="edit" default="yes"/>
    <toolbtn func="function3" type="group" img="t-delete.gif" name="delete"/>
  </toolbar>
  <coldata>
    <col sort="alpha" sorted="yes" name="field_name" type="data"/>
  </coldata>
</metadata>

The example shows that we want to add the interface to our "function1" (type="list"), in which the key element is "field_name". The unique key element is required to identify a record in the list. This value will be transferred to functions such as, view or delete the element parameters, etc.

Then you need to describe the toolbar that contains three icons: new (name="new"), edit (name="edit") and delete (name="delete") an element. You can provide the action that will be executed when double-clicking the record by adding the default="yes" attribute into the node that describes the control panel's element. Double-clicking the record will call the function to edit the record's parameter. The same function name is specified as the func attribute for two first control panel icons, because one function will implement creation, view and edit of the record's parameters. The type attribute determines the function type:

new
add a new element.
edit
edit an existing element.
group
an operation against a group of elements.
editlist
child list associated with one of the current list elements.
list
child list that is not associated with any element of the current list.

Then you need to provide the coldata block . Add a required number of col nodes, one for each table column. In our case, the table consists of one column in which the "field_name" field will be displayed that the list creation function will return for each element. You should specify the type of the column values. The following types are currently supported:

data
displays information about each element sent to the field which name is specified in the name attribute ("field_name").
msg
can be used if you have a set of values that are returned to the filed which name is specified in the name attribute, such as the record's status (enabled, disabled, etc.), and you want these values to be displayed differently depending on the control panel' language. In this case, the values must consist of the Latin alphabet letters, digits, dots and the "_" symbols.
indicator
displays usage of a specific resource, such as traffic or disk space. You need to add the XML-node with the name of this column and add the used="number" and limit="number" attributes into this node:

If you want to sort the data in the column, add the sorted="yes" attribute providing one of the following values:

alpha
lines that contain the Latin alphabet letter and digits.
digit
digits.
indicator
indicators (such as, traffic or disk space).
ip
IP-addresses.
prop
set of properties (such as, enabled\disabled).

If you wish the elements of the table to be sorted automatically by a column, add the the sorted="yes" attribute.

If you wish the data of one or several columns to be used for statistical information, add the stat="yes" attribute.

Describe the interface of the create and edit forms by adding the following block into the XML-document:


<metadata name="function2" type="form">
  <form>
    <field name="message">
      <input type="text" name="filed_name"/>
    </field>
  </form>
</metadata>

This example shows that we want to add the form (type="form") for "function2". Each control element must have a separate field block that consists of a filed heading and control element. The field heading is provided with the name="message" attribute. You must add a corresponding node into the message block for this function. The procedures on how to create blocks will be described below. Then you need to add the control element. The are three types of control elements:

input
input field. There are several types of input fields that are specified in the type attribute:
text
line input field.
password
password field; when entering a password, all characters are replaced with asterisks.
checkbox
check box type.
textarea
multiline input field.
select
drop-down list.

Use the name attribute to provide a name of the function parameter that is associated with the selected control element. If you wish to specify a default value for this control element, use the value attribute (value="default_value").

You can use additional attributes for fields. If you want the field to be hidden by default, and you want to manage its with javascript, add the hidden="yes" attribute . If you use <input type="text"/> as the control element, and several elements should be entered into the text field, add the zoom="5" attribute. An additional icon next to the text field will be displayed. Clicking the icon will enlarge the field by the number of lines specified in the attribute value.

Messages

An ISPmanager message is a text that you can view in the control panel. It is not associated with data that is received after execution of the functions. The messages are divided into groups according to interface languages. You must add the following block for each interface language:

<lang name="language">
  navigation menu messages
  function messages 
</lang>

Use one of the following values to specify a language:

de
German
en
English
es
Spanish
fr
French
ru
Russian

Default interface language is English. If another language is used and the required message in this language cannot be found, the corresponding message in English will be used.

Then add messages for all menu items that you have created in the "Element description" menu. To do that, add the block:

<messages name="desktop">
  <msg name="menu_function1">message1</msg>
  <msg name="menu_function2">message2</msg>
</messages>

For each menu item, such as <node name="function"/>, you should add <msg name="menu_function1">message1</msg>. For message1 provide an menu item text in UTF-8.

All other messages are divided according to functions they perform. That's why for each function that your plug-in provides, add the following block into the XML-document:

<messages name="function1">
  <msg name="message_name">message</msg>
  ...
</messages>

Following are the standard messages for modules (these names should be used instead of "message_name"):

title
module heading (list or form).
title_new
creation from heading.
hint_default
module function hint.

All other messages are divided into the following types:

list columns names
values from the name attribute of the col;
values for msg type column
value that can be send in the corresponding element parameter that the function returned. If there are several values, you need to add a separate message for each of them;
form fields names
value from the name attribute of the field node;
values for the select control elements
value that will be sent in this list. If the corresponding message is not found, the value returned by the function will be displayed. If there are several values, you need to add a separate message for each of them;
form field hints
value from the name attribute of the field node with hint_, such as, hint_username.
toolbar icon hints
value from name attribute of the toolbtn node with hint_ prefix, such as, hint_new.
javascript messages
all the messages that are used in javascript scenarios. Standard messages of this type are various confirmation messages, for example those used when removing an element. In this case you should use msg_function1_delete, where function1 is the name of the function from the plug-in.

All the message should be encoded in the UTF-8 character set. Otherwise, the XML-document won't load and ISPmanager won't start.

Example of the ispmgr_mod_myconf.xml XML-document:

<?xml version="1.0" encoding="UTF-8"?>
  <mgrdata>
    <handler name="myconf.pl" type="cgi">
      <func>myconf</func>
      <func>myconf.edit</func>
      <func>myconf.delete</func>
   </handler>

   <metadata name="myconf" type="list" key="item">
     <toolbar>
       <toolbtn func="myconf.edit" type="new"  img="t-new.gif" name="new"/>
       <toolbtn func="myconf.edit" type="edit" img="t-edit.gif" name="edit" default="yes"/>
       <toolbtn func="myconf.delete" type="group" img="t-delete.gif" name="delete"/>
     </toolbar>
     <coldata>
       <col sort="alpha" sorted="yes" name="item" type="data"/>
     </coldata>
   </metadata>

   <metadata name="myconf.edit" type="form">
     <form>
       <field name="item">
         <input type="text" name="item"/>
       </field>
     </form>
   </metadata>

   <mainmenu level="7">
     <node name="tool">
       <node name="myconf"/>
     </node>
   </mainmenu>

   <lang name="en">
     <messages name="desktop">
       <msg name="menu_myconf">Test module</msg>
     </messages>
     <messages name="myconf">
       <msg name="title">Test module</msg>
       <msg name="item">Item from myconf</msg>
       <msg name="msg_myconf_delete">Delete item </msg>
       <msg name="hint_new">New item</msg>
       <msg name="hint_edit">Edit item</msg>
       <msg name="hint_delete">Delete item</msg>
     </messages>
     <messages name="myconf.edit">
       <msg name="title">Edit item</msg>
       <msg name="title_new">New item</msg>
       <msg name="item">Item value</msg>
       <msg name="hint_item">Item value from myconf</msg>
     </messages>
   </lang>
   <lang name="ru">
     <messages name="desktop">
       <msg name="menu_myconf">Test module</msg>
     </messages>
     <messages name="myconf">
       <msg name="title">Test module</msg>
       <msg name="item">Element from myconf</msg>
       <msg name="msg_myconf_delete">Delete element </msg>
       <msg name="hint_new">New element</msg>
       <msg name="hint_edit">Edit element</msg>
       <msg name="hint_delete">Delete element</msg>
     </messages>
     <messages name="myconf.edit">
       <msg name="title">Edit element</msg>
       <msg name="title_new">New element</msg>
       <msg name="item">Value</msg>
       <msg name="hint_item">Element value from myconf</msg>
     </messages>
   </lang>
 </mgrdata>

Writing a program

After you have created the XML-document with the interface description, you need to write a program or script that will handle the data for the plug-in. This program should be located in /usr/local/ispmgr/addon, belong to root and have permissions 700. The program name should match the value specified in the name attribute of the XML-document handler node.

To locate a user who called the function to start your program, use the REMOTE_USER environment variable. Make sure that this user has been authorized.

Below is the example of the myconf.pl CGI-program written in Perl:

#!/usr/bin/perl

use CGI qw/:standard/;

$Q = new CGI;
$func = $Q->param(func);

print "<doc>";

if( $func eq "myconf" ){
	&List;
} elsif( $func eq "myconf.delete" ){
	&Delete;
} elsif( $func eq "myconf.edit" ){
	if(	$Q->param( "sok" ) ){
		if( $Q->param( "elid" ) ){
			&Set;
		} else{
			&New;
		}
		print "<ok/>";
	} else{
		&Get;
	}
}

print "</doc>";
exit 0;

sub List {
	if( open( IN, "/etc/myconf" ) ){
		while( <IN> ){
			chomp;
			print "<elem><item>$_</item></elem>";
		}
		close( IN );
	}
}

sub Get {
	$elid = $Q->param( "elid" );
	print "<elid>$elid</elid><item>$elid</item>" if( $elid );
}

sub Set {
	$elid = $Q->param( "elid" );
	$item = $Q->param( "item" );
	if( open( IN, "/etc/myconf" ) ){
		if( open( OUT, ">/etc/myconf.new" ) ){
			for( <IN> ){
				chomp;
				if( $_ eq $elid ){
					print OUT "$item\n";
					$ok = 1;
				} else {
					print OUT "$_\n";
				}
			}
			close( OUT );
		}
		close( IN );
	}

	if( $ok ){
		rename( "/etc/myconf.new", "/etc/myconf" );
		print "<ok/>";
	} else {
		print "<error>Item hasn`t been updated</error>";
	}
}

sub New {
	$elid = $Q->param( "elid" );
	$item = $Q->param( "item" );
	if( open( ADD, ">>/etc/myconf" ) ){
		print ADD "$item\n";
		close( ADD );
		print "<ok/>";
	} else {
		print "<error>Item hasn`t been added</error>";
	}
}

sub Delete {
	$elid = $Q->param( "elid" );
	if( open( IN, "/etc/myconf" ) ){
		if( open( OUT, ">/etc/myconf.new" ) ){
			for( <IN> ){
				chomp;
				print OUT "$_\n" if( $_ ne $elid );
			}
			close( OUT );
		}
		close( IN );
	}

	rename( "/etc/myconf.new", "/etc/myconf" );
	print "<ok/>";
}

If you use the program in the xml mode, it receives the XML from stdin that can contain description of the interface for creating lists and forms that you have described in your XML-document. You can edit these data with your program in order to change the set of list columns, form fields or icons of the toolbar. Your program needs to add the required XML-nodes with data and return it to stdout.

Was this helpful? Yes | No
Personal tools