Плагины

Материал из ISPWiki

Перейти к: навигация, поиск

Содержание

Введение

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

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

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

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

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

Полная документация по каждой части XML-документа вы можете найти в статье XML.

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

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

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

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

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

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

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

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

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

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

Где BINNAME — имя запускаемого файла панели управления (ispmgr, billmgr, vdsmgr и т.д.).

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

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

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

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

В качестве названия категории укажите имя, указанное в атрибуте name узла node для соответствующей категории меню навигации, описанному в файле /usr/local/ispmgr/etc/BINNAME_menu.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". При этом рядом с текстовым полем появится дополнительная кнопка, при нажатии на которую текстовое поле будет расширяться на количество строк, указанных в значении данного атрибута, что позволит вводить данные построчно.

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

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

<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.

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

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

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

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-документ не сможет быть загружен и панель управления не запустится.

Ниже приведён пример 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-документ в формате вывода результатов выполнения функций.

Для того, чтобы выяснить от имени какого пользователя была вызвана функция панели управления, которая привела к выполнению вашей программы, можно использовать переменную окружения 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-узлы с данными в формате вывода результатов выполнения функций и возвратить его на стандартный вывод.

Личные инструменты