Plug-ins
From ISPWiki
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.
