Расширения

Механизм расширений (plugins) ISPmanager предназначен для добавления собственных модулей в панель управления. В данном документе приводится пример создания модуля, который будет работать со списком произвольных строк в файле /etc/myconfig. По аналогии с этим примером вы сможете создавать собственные расширения панели управления.

Процесс создания собственного расширения можно разделить на два этапа. Первый - это создание XML-документа, в котором будут описаны все функции, обрабатываемые данным расширением, а также все элементы интерфейса, необходимые для того, чтобы вы увидели ваш модуль в панели управления. Второй этап - это разработка программы или скрипта, который будет реализовывать обработку данных в процессе работы расширения, то есть реализовывать функции.

Создание XML-документа

XML-документ, в котором описывается интерфейс вашего расширения панели управления, должен располагаться в папке /usr/local/ispmgr/etc и называться ispmgr_mod_xxx.xml, где вместо xxx вы можете указать любое название, например, myconfig (ispmgr_mod_myconfig.xml). Документ обязательно должен быть в кодировке UTF-8 и иметь следующий вид:

<?xml version="1.0" encoding="UTF-8"?>
<mgrdata>
	описание функций расширения
	описание элементов меню
	описание таблиц и форм
	описание сообщений
</mgrdata>
	

Описание функций расширения

Данная часть XML-документа определяет имя программы или скрипта, который будет реализовывать функции, тип взаимодействия программы и панели управления, а также набор функций, предоставляемые данным расширением. Она должна иметь следующий вид:

<handler name="программа" type="тип">
  <func>функция1</func>
  <func>функция2</func>
  ...
</handler>
	

В качестве атрибута name укажите имя программы, которая реализует функции, например, myconfig.pl. В качества атрибута type укажите тип взаимодействия панели управления и вашей программы. На текущий момент возможны два типа:

cgi - программа имеет интерфейс CGI, то есть получает данные из переменных окружения и/или стандартного ввода (POST).
xml - программа получает из стандартного ввода XML-документ, описывающий данные, которые передала панель управления.

После этого нужно определить, какие функции будет предоставлять ваше расширение. Все функции можно поделить на три типа:

Список элементов - таблица с панелью инструментов.
Свойства элемента - форма, которая применяется для создания нового либо изменения существующего элемента. Также форма может применяться, если ваш модуль не рассчитан на работу с множеством элементов, а служит для настройки набора каких-либо параметров.
Действие - данный тип функций не предусматривает наличия собственных элементов интерфейса, а является операцией над одним или несколькими элементами из списка.

Имена функций могут содержать буквы латинского алфавита, цифры и точки и должны быть уникальными. Список имеющихся функций можно найти в файле /usr/local/ispmgr/etc/ispmgr.xml.

Описание элементов меню

Для того, чтобы вы могли осуществить доступ к вашему расширению, необходимо создать соответствующие элементы меню навигации панели управления. Для этого вы должны добавить в ваш XML-документ следующий блок:

<mainmenu level="уровень доступа">
  <node name="название категории">
    <node name="функция1"/>
    <node name="функция2"/>
 </node>
</mainmenu>
	

Во-первых, вы должны определиться, на каком уровне доступа вы хотите видеть ваше расширение. На текущий момент доступны следующие уровни доступа к панели управления:

7 - администратор сервера (root).
6 - реселлер (только в ISPmanager Pro).
5 - пользователь.
4 - пользователь с доступом к shell.
3 - FTP аккаунт.
2 - почтовый аккаунт.

В атрибуте level укажите цифру, соответствующую уровню доступа. Если вы хотите, чтобы модуль был доступен на нескольких уровнях, добавьте отдельный блок mainmenu для каждого из них.

В качестве названия категории укажите имя, указанное в атрибуте name узла node для соответствующей категории меню навигации, описанному в файле /usr/local/ispmgr/etc/ispmgr.xml. Предположим, вы хотите дать доступ к вашему расширению всем пользователям и разместить соответствующий пункт меню в раздел "Инструменты" меню навигации. Для этого необходимо найти раздел <mainmenu level="5"> и соответствующий раздел <node name="tool">. То есть в качестве названия категории мы должны указать значение tool.

После этого необходимо добавить один или несколько элементов меню в соответствующий раздел меню навигации. Для этого добавляем узлы node и в качестве атрибута name указываем имя функции, к которой необходимо обратиться при нажатии соответствующего пункта меню.

Описание таблиц и форм

Далее нужно описать интерфейс для функций, предоставляемых вашим расширением. Наш тестовый модуль предполагает наличие возможности просмотра существующих записей в файле /etc/myconfig, а также добавления новых и изменения существующих записей. Также нужна возможность удаления, но эта функция относится к разряду действие и наличия интерфейса не предполагает.

Итак, для того, чтобы реализовать список записей, нужно добавить следующий блок в XML-документ:

<metadata name="функция1" type="list" key="имя_поля">
  <toolbar>
    <toolbtn func="функция2" type="new"  img="t-new.gif" name="new"/>
    <toolbtn func="функция2" type="edit" img="t-edit.gif" name="edit" default="yes"/>
    <toolbtn func="функция3" type="group" img="t-delete.gif" name="delete"/>
  </toolbar>
  <coldata>
    <col sort="alpha" sorted="yes" name="имя_поля" type="data"/>
  </coldata>
</metadata>
	

Здесь написано, что мы хотим добавить интерфейс к нашей функции "функция1" типа список (type="list"), в котором ключевым элементом будет "имя_поля". Уникальный ключевой элемент необходим для того, чтобы однозначно идентифицировать запись в списке. Именно это значение будет передано функциям, работающим с элементами списка, таким как просмотр параметров элемента, удаление и прочим.

После этого описывается панель инструментов, в котором присутствуют три кнопки: создать (name="new"), редактировать (name="edit") и удалить (name="delete") элемент. Вы можете указать действие, которое будет осуществляться при двойном щелчке по записи путём добавления атрибута default="yes" в нужный узел, описывающий элемент панели инструментов. В нашем случае при двойном щелчке по записи будет вызвана функция редактирования параметров записи. Как вы могли заметить, в качестве атрибута func в первых двух кнопках панели инструментов указано одно и то же имя функции. Это получается вследствие того, что в нашем случае одна функция будет реализовывать создание, а также просмотр и редактирование параметров записей. Тип функции определяется атрибутом type:

new - создание нового элемента.
edit - редактирование существующего элемента.
group - операция над группой элементов.
editlist - дочерний список, связанный с одним из элементов текущего списка.
list - дочерний список, не привязанный ни к одному из элементов текущего списка.

Далее указывается блок coldata, в который нужно добавить необходимое количество узлов col, по одному на каждую колонку в таблице. В нашем случае таблица состоит из единственной колонки, в которой будет отображаться поле "имя_поля", которое будет возвращать функция создания списка для каждого элемента. Вы должны указать тип записей в колонке. На текущий момент существует три типа:

data - в данной колонке будет отображаться информация по каждому элементу, переданная в поле с именем, указанным в атрибуте name (в нашем случае это "имя_поля").
msg - этот тип может быть полезен, если вы имеете конечный набор значений, возвращаемых в поле с именем, указанным в атрибуте name, например, статус записи (включено,отключено и т.п.), и хотите, чтобы эти значения отображались по разному, в зависимости от языка панели управления. В этом случае значения, возвращаемые в этом поле, должны состоять из букв латинского алфавита, цифр, точек и знаков "_".
indicator - в данной колонке будeт отображаться индикаторы использования того или иного ресурса, например, дискового пространства или трафика. В этом случае для каждого элемента, для которого необходимо вывести индикатор, следует добавить XML-узел с именем данной колонки списка и добавить в этот узел два атрибута: used="число" и limit="число".

Если вы хотите, чтобы данные в столбце можно было сортировать, добавьте атрибут sort, в котором укажите одно из следующих значений, зависящее от типа данных в данном столбце:

alpha - строки из букв латинского алфавита и цифр.
digit - числа.
indicator - индикаторы (например, дисковое пространство, трафик и прочее).
ip - IP-адреса.
prop - набор параметров (например, включен/отключен).

Если вы хотите, чтобы записи в таблице автоматически сортировались по одному из столбцов при входе в модуль, добавьте атрибут sorted="yes"

Если же вы хотите, чтобы на основе данных, содержащихся в одном или нескольких столбцах, отображалась статистическая информация, добавьте атрибут stat="yes".

После этого нужно добавить описание интерфейса для формы создания и редактирования свойств записи. Для этого добавьте следующий блок в XML-документ:

<metadata name="функция2" type="form">
  <form>
    <field name="сообщение">
      <input type="text" name="имя_поля"/>
    </field>
  </form>
</metadata>
	

Здесь указывается, что мы хотим добавить форму (type="form") для работы с функцией "функция2". Для каждого элемента управления необходимо добавить отдельный блок field, состоящий из заголовка поля и, собственно, самого элемента управления. Заголовок для данного поля указывается с помощью атрибута name="сообщение". При этом необходимо добавить соответствующий узел в блок сообщений для данной функции. О правилах составления блоков сообщений будет сказано ниже. После этого нужно добавить элемент управления. Встречаются три типа элементов управления:

input - поле ввода. Существует несколько типов полей ввода, которые указываются в атрибуте type:
text - поле для ввода строки.
password - поле для ввода пароля, при вводе символы заменяются звёздочками.
checkbox - элемент управления типа флажок.
textarea - многострочное поле ввода.
select - выпадающий список.

С помощью атрибута name необходимо указать имя параметра функции, который связан с данным элементом управления. Если вы хотите задать некоторое значение по умолчанию для элемента управления, вы можете использовать атрибут value="значение_по_умолчанию".

Также существуют дополнительные атрибуты для полей field. Если вы хотите, чтобы поле было скрыто по умолчанию, и управлять его видимостью с помощью javascript, добавьте атрибут hidden="yes". Если же вы используете в качестве элемента управления <input type="text"/>, и это текстовое поле подразумевает ввод нескольких значений, вы можете добавить атрибут zoom="5". При этом рядом с текстовым полем появится дополнительная кнопка, при нажатии на которую текстовое поле будет расширяться на количество строк, указанных в значении данного атрибута, что позволит вводить данные построчно.

Описание сообщений

Сообщения ISPmanager являются по сути всем тем текстом, который вы видите в панели управления, и который не привязан непосредственно к данным, полученным в результате выполнения функций. Сообщения делятся по языкам интерфейса. Для каждого языка необходимо добавить блок:

<lang name="язык">
	сообщения меню навигации
	сообщения функций
</lang>
	

В качестве языка необходимо указать одно из следующих значений:

de - немецкий
en - английский
es - испанский
fr - французский
ru - русский

Основным языком интерфейса является английский. Если в качестве языка панели управления выбран другой язык, и необходимое сообщение не найдено, будет использовано аналогичное сообщения из английского языка.

Далее необходимо добавить в этот блок сообщения для всех пунктов меню, которые вы создали в описании элементов меню. Для этого добавим блок следующего вида:

<messages name="desktop">
	<msg name="menu_функция1">сообщение1</msg>
	<msg name="menu_функция2">сообщение2</msg>
</messages>
	

То есть для каждого пункта меню вида <node name="функция1"/> необходимо добавить сообщение вида <msg name="menu_функция1">сообщение1</msg>. В качестве сообщение1 укажите текст пункта меню в кодировке UTF-8.

Все остальные сообщения делятся по функциям, поэтому для каждой функции, предоставляемой вашим расширением ISPmanager, необходимо добавить в XML-документ блок следующего вида:

<messages name="функция1">
	<msg name="имя_сообщения">сообщение</msg>
	...
</messages>
	

Существуют следующие стандартные типы сообщений для модулей ISPmanager (данные названия необходимо указать вместо имя_сообщения):

title - заголовок модуля (списка или формы).
title_new - заголовок формы создания нового элемента.
hint_default - подсказка о назначении данного модуля

Все остальные сообщения делятся на следующие типы:

названия столбцов списка - в качестве имени сообщения необходимо указать значения, указанные в атрибуте name узла col.
значения для столбцов типа msg - в качестве имени сообщения необходимо указать значение, которое может быть передано в соответствующем параметре элемента, возвращённого функцией. Если значений несколько, необходимо создать отдельное сообщение для каждого из них.
названия полей формы - в качестве имени сообщения необходимо указать значения, указанные в атрибуте name узла field.
значения для элементов управления типа select - в качестве имени сообщения необходимо указать то значение, которое может быть передано в этом списке. Если соответствующее сообщение не будет найдено, будет отображено само значение, возвращённое функцией. Если значений может быть несколько, необходимо создать отдельное сообщение для каждого из них.
подсказки к полям формы - в качестве имени сообщения необходимо указать значения, указанные в атрибуте name узла field с префиксом hint_, например, hint_username.
подсказки к кнопкам в панели инструментов - в качестве имени сообщения необходимо указать значения, указанные в атрибуте name узла toolbtn с префиксом hint_, например, hint_new.
сообщения javascript - к ним относятся все сообщения, используемые в javascript. К стандартным сообщениям такого рода можно отнести сообщение подтверждения удаления элемента. В этом случае в качестве имени сообщение необходимо указать msg_функция1_delete, где в качестве значения "функция1" необходимо указать имя функции из расширения.

Ещё раз следует обратить ваше внимание на тот факт, что все сообщения должны быть представлены в кодировке UTF-8. В противном случае XML-документ не сможет быть загружен и ISPmanager не запустится.

Ниже приведён пример XML-документа ispmgr_mod_myconf.xml

<?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">The value of the item from myconf</msg>
    </messages>
  </lang>
  <lang name="ru">
    <messages name="desktop">
      <msg name="menu_myconf">Тестовый модуль</msg>
    </messages>
    <messages name="myconf">
      <msg name="title">Тестовый модуль</msg>
      <msg name="item">Элемент из myconf</msg>
      <msg name="msg_myconf_delete">Удалить элемент </msg>
      <msg name="hint_new">Новый элемент</msg>
      <msg name="hint_edit">Редактировать элемент</msg>
      <msg name="hint_delete">Удалить элемент</msg>
    </messages>
    <messages name="myconf.edit">
      <msg name="title">Редактировать элемент</msg>
      <msg name="title_new">Новый элемент</msg>
      <msg name="item">Значение</msg>
      <msg name="hint_item">Значение элемента из myconf</msg>
    </messages>
  </lang>
</mgrdata>
	

Разработка программы

После того, как мы подготовили XML-документ, описывающий интерфейс расширения, необходимо написать программу или скрипт, который будет обрабатывать данные для расширения. Данная программа должна располагаться в директории /usr/local/ispmgr/addon, принадлежать пользователю root и иметь права доступа 700. Имя программы должно совпадать со значением, указанным в атрибуте name узла handler XML-документа.

В качестве результата работы программы должен быть XML-документ в формате вывода результатов выполнения функций ISPmanager 4.

Для того, чтобы выяснить от имени какого пользователя была вызвана функция ISPmanager, которая привела к выполнению вашей программы, можно использовать переменную окружения REMOTE_USER. При этом вы можете быть уверены, что данный пользователь был авторизован.

Ниже приведён пример CGI-программы myconf.pl, написанной на языке 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/>";
}
	

Если же вы используете программу в режиме xml, то, как было сказано выше, она получает из стандартного ввода XML, в котором также могут присутствовать блоки описания интерфейса для построения списков или форм, который вы описали в вашем XML-документе. У вас есть возможность корректировать с помощью вашей программы эти данные с целью изменения набора столбцов списка, полей форм, либо кнопок в панели инструментов. Также ваша программа должна добавить в этот документ необходимые XML-узлы с данными в формате вывода результатов выполнения функций ISPmanager 4 и возвратить его на стандартный вывод.