http://downloads.openqrm.net/contrib/plugin-howto/
插件基础(part 1)
需求
For starting with plugin-development you need to have openQRM compiled from its sources. It is recommended to use the sources from the cvs because this will generally include the latest fixes.
To compile openQRM you need to have the development components installed on your build-system (gcc/c++, make, autoconf, etc.).
Also the java jdk version 1.5 from sun and maven version 1.0.2 is required.
Please notice that you need to have exactly this java + maven versions !
Hint: to speed up compilation please remove all plugin-directories from the .../src/plugins/ directory expect e.g. the dhcpd plugin.
创建插件骨架
First create a new directory in the openQRM sources at ../src/plugins/ called "myservice". This directory should be named as plugin you plan to create.
cd ../src/plugins/
mkdir -p myservice
Then create a basic Makefile with the following content :
#
# openQRM plugin myservice Makefile
#
# standard definitions for the build- packaging-system
export PACKAGE_PREFIX = openqrm
export PACKAGE_GROUP = plugin
export PACKAGE_NAME = myservice
export PACKAGE_F_NAME = $(PACKAGE_PREFIX)-$(PACKAGE_GROUP)-$(PACKAGE_NAME)
# defining the output directory :
# ../../../out for general compilation
# ../../../pkg_stage/$(PACKAGE_F_NAME)/opt for rpm/deb packaging
ifdef PACKAGE_TYPE
OUTDIR := ../../../pkg_stage/$(PACKAGE_F_NAME)/opt
else
OUTDIR := ../../../out
endif
# define which files should be installed
INSTALL_FILES := etc/myservice.xml, -m 0700 etc/init.d, include
INSTALL_FILES_DEST := $(OUTDIR)/qrm/plugins/myservice
# include the build- and packaging-functions
INC_NAME := ../../build/Makefile.inc
include $(INC_NAME)
RPM_INC_NAME := ../../build/Makefile.rpm.inc
include $(RPM_INC_NAME)
all: check
# Do everything here to e.g. create the binaries for
# your plugin. This section should compile your component "myservice"
@echo "making the myservice-plugin"
install:
# Do everything here additional needed to install "myservice" in
# the OUT_DIR. No compilation should be done in this step
# Files in INSTALL_FILES will be installed automatically
@echo "installing myservice for Qrm"
clean: check
# Do everything here to clean-up the install-section
@echo "cleaning up myservice"
@/bin/rm -rf $(OUTDIR)/qrm/plugins/myservice
realclean: clean
@echo "making realclean for the myservice plugin"
@/bin/rm -rf $(QRM_CACHE_DIR)/myservice \
$(QRM_ROOT_DIR)/build/myservice
configure:
# You can use this section to pre-configure your plugin build
check:
@if [ -z $(QRM_CACHE_DIR) ]; then echo "ERROR: QRM_CACHE_DIR not set!"; exit 1; fi
@if [ -z $(QRM_ROOT_DIR) ]; then echo "ERROR: QRM_ROOT_DIR not set!"; exit 1; fi
This Makefile-skeleton should be self-explaining from the included comments.
Now let's create the directory structure for the "myservice" plugin. Since plugins in openQRM should be separated from the base-server the concept is that each plugin will "work" within its plugin directory and not put and/or use files on system-level. Based on that a plugin should have a directory layout similar to the system-director layout and manage their services within their own directories. This mechanism makes it also easy to find plugin components e.g. in our example the init-script for the "myservice-server" should be located at ../src/plugins/myservice/etc/init.d/.
For now we just create an etc/init.d and include dir :
cd myservice
mkdir -p etc/init.d include
创建插件定义和功能文件
For giving openQRM some initial informations about the "myservice" plugin we create its definition in a xml-file at ../src/plugins/myservice/etc/myservice.xml :
<?xml version="1.0"?>
<plugin>
<properties>
<name>myservice</name>
<version>0.1</version>
<description>Provides the myservice-service</description>
<schema_version>1.0</schema_version>
</properties>
<config/>
</plugin>
For building and automatic packaging later we also need to create an info.xml file for the "myservice" plugin at ../src/plugins/myservice/include/myservice-info.xml with the following content :
<?xml version="1.0"?>
<package>
<module>
<name>myservice</name>
<version>0</version>
<type>plugin</type>
<release>1</release>
<license>Qlusters Public License Version 1.1</license>
<group>QRM/plugins</group>
<arch>i386</arch>
<summary>myservice plugin</summary>
<description>Provides myservice for openQRM</description>
</module>
</package>
To let openQRM know what to do when installing, uninstalling, starting and stopping the "myservice" plugin a functions file needs to be created at ../src/plugins/myservice/include/myservice-functions. It should look like :
#!/bin/bash
function myservice_install() {
echo "installing the myservice plugin"
# this function will run during installing the plugin
}
function myservice_uninstall() {
echo "uninstalling the myservice plugin"
# this function will run during uninstallation
}
function myservice_start() {
echo "starting the myservice plugin"
# this function will run immeadiatly after the openQRM-server is started
# to start the myservice plugin service
}
function myservice_stop() {
echo "stopping the myservice plugin"
# this function will run before the openQRM-server gets stopped
# to stop the myservice plugin service
}
function myservice_run_once() {
echo "running run_once for the myservice plugin"
# this function will run once after the plugins installation
# phase and can be used to e.g. register new components or
# apply any updates/changes to the configuration
}
For this howto we defined that "myservice" is based on a common client-server model. That means we need to create one init-script for the "myservice-server" which will be running on the openQRM-server and one "myservice-client" init-script for the starting the client component on the systems managed by openQRM.
First let's create the "myservice-server" init-script ../src/plugins/myservice/etc/init.d/myservice-server as following :
#!/bin/bash
# init script for the myservice plugin managing myservice-server
QRM_SERVER_BASE_DIR=$(pushd $(dirname $0)/../../../../.. > /dev/null; echo $PWD; popd > /dev/null)
PLUGIN_BASE_DIR=$QRM_SERVER_BASE_DIR/qrm/plugins/myservice
LOCKFILE=$QRM_SERVER_BASE_DIR/qrm/plugins/myservice/var/lock/subsys/myservice-server
mkdir -p $QRM_SERVER_BASE_DIR/qrm/plugins/myservice/var/lock/subsys/
function start() {
echo "starting openQRM myservice plugin"
$QRM_SERVER_BASE_DIR/qrm/plugins/myservice/sbin/myservice-serverd &
touch $LOCKFILE
}
function stop() {
echo "Stopping openQRM myservice plugin"
killall myservice-serverd 1>/dev/null 2>&1
rm -f $LOCKFILE
}
function status() {
if [ -s $LOCKFILE ]; then
echo "openQRM myservice-server is running"
else
echo "openQRM myservice-server is stopped"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
sleep 1
start
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
exit 1
esac
exit $?
Then create the "myservice-client" init-script at ../src/plugins/myservice/etc/init.d/myservice-client as following :
#!/bin/bash
# openQRM init script for the myservice plugin managing myservice-client
#
# chkconfig: 345 97 18
# description: openQRM is the next generation Linux Data Center management. \
# Please see www.openQRM.org for more details.
export `eval cat /proc/cmdline`
. /var/qrm/conf/qrm.conf.$id
. $QRM_NODES_BASE_DIR/qrm/include/qrm-nodes-functions
LOCKFILE=$QRM_NODES_BASE_DIR/qrm/plugins/myservice/var/lock/subsys/myservice-client
mkdir -p $QRM_NODES_BASE_DIR/qrm/plugins/myservice/var/lock/subsys/
function start() {
echo "starting openQRM myservice plugin (myservice-client)"
$QRM_NODES_BASE_DIR/qrm/plugins/myservice/sbin/myservice-clientd &
touch $LOCKFILE
}
function stop() {
echo "Stopping openQRM myservice plugin (myservice-client)"
killall myservice-clientd 1>/dev/null 2>&1
rm -f $LOCKFILE
}
function status() {
if [ -s $LOCKFILE ]; then
echo "openQRM myservice-client is running"
else
echo "openQRM myservice-client is stopped"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
sleep 1
start
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
exit 1
esac
exit $?
We created the initial skeleton of the "myservice" plugin and we have now the following files :
./etc/init.d/myservice-client
./etc/init.d/myservice-server
./etc/myservice.xml
./include/myservice-functions
./include/myservice-info.xml
./Makefile
We can now attempt to build it for testing. Here an example output of the build procedure :
[root@demo myservice]# make clean
# Do everything here to clean-up the install-section
cleaning up myservice
[root@demo myservice]# make
# Do everything here to e.g. create the binaries for
# your plugin. This section should compile your component "myservice"
making the myservice-plugin
[root@demo myservice]# make install
/usr/bin/install -D etc/myservice.xml ../../../out/qrm/plugins/myservice/etc/myservice.xml
/usr/bin/install -D -m 0700 etc/init.d/myservice-client ../../../out/qrm/plugins/myservice/etc/init.d/myservice-client
/usr/bin/install -D -m 0700 etc/init.d/myservice-server ../../../out/qrm/plugins/myservice/etc/init.d/myservice-server
/usr/bin/install -D include/myservice-functions ../../../out/qrm/plugins/myservice/include/myservice-functions
/usr/bin/install -D include/myservice-info.xml ../../../out/qrm/plugins/myservice/include/myservice-info.xml
touch ../../../out/qrm/plugins/myservice/include/.files_installed
# Do everything here additional needed to install "myservice" in
# the OUT_DIR. No compilation should be done in this step
# Files in INSTALL_FILES will be installed automatically
installing myservice for Qrm
[root@demo myservice]#
完成“myservice”插件
We have now created the initial directory structure and files for the "myservice" plugin. Still we are missing the actual "myservice-server/client" daemons and for now almost all functions are still empty. For this howto we will create very simply scripts for the "myservice-server" and the "myservice-client". In a real integration those daemons/binaries will be created through the plugins compile procedure defined in the plugins Makefiles "all" section. The "myservice-serverd" and "myservice-clientd" script should be located in the plugins sbin directory so let's create it by running :
mkdir -p sbin
Here the "myservice-serverd" script which should be saved at ../src/plugins/myservice/sbin/myservice-serverd :
#!/bin/bash
# this is a simple example server daemon for the "howto create an openQRM plugin" howto
echo "myservice-server started"
while (true); do
sleep 1000
done
And a "myservice-clientd" script which should be saved at ../src/plugins/myservice/sbin/myservice-clientd :
#!/bin/bash
# this is a simple example client daemon for the "howto create an openQRM plugin" howto
echo "myservice-client started"
while (true); do
sleep 1000
done
To automatically add those two new file to the plugins installation please add them to the INSTALL_FILES variable in the Makefile. It should now look like :
INSTALL_FILES := etc/myservice.xml, -m 0700 etc/init.d, include, -m 700 sbin
Connecting the "myservice-server" to openQRM
Starting the "myservice-server" daemon as an additional plugin service is easy. Just add its start (and stop) commands to the "myservice_start" and "myservice_stop" functions in ../src/plugins/myservice/include/myservice-functions. Those two functions should now look like :
function myservice_start() {
echo "starting the myservice plugin"
# this function will run immeadiatly after the openQRM-server is started
# to start the myservice plugin service
$QRM_SERVER_BASE_DIR/qrm/plugins/myservice/etc/init.d/myservice-server start
}
function myservice_stop() {
echo "stopping the myservice plugin"
# this function will run before the openQRM-server gets stopped
# to stop the myservice plugin service
$QRM_SERVER_BASE_DIR/qrm/plugins/myservice/etc/init.d/myservice-server stop
}
连接“myservice-client”到系统中,由openQRM管理。
For the "myservice-client" which should be running automatically on the systems managed by openQRM we have to do some more work. An openQRM plugin extension callled "BootService" is used to make a system, associated with this boot-service, do the following steps during init : download a specified boot-service package from the openQRM-server (this is a zip file containing all required files to start the boot-service) unpack the boot-service package run a specified init-script Let's first create the boot-service package for the "myservice" plugin. For starting the "myservice-client" we basically just need the daemon file and its init-script. To pack them during the "make install" stage of the plugin build please update the Makefile's "install" section to look like :
install:
# Do everything here additional needed to install "myservice" in
# the OUT_DIR. No compilation should be done in this step
# Files in INSTALL_FILES will be installed automatically
@echo "installing myservice for Qrm"
mkdir -p $(OUTDIR)/qrm/plugins/myservice/client
tar -C $(OUTDIR)/qrm/ --exclude CVS --exclude Makefile -czf $(OUTDIR)/qrm/plugins/myservice/client/myservice-client.tgz plugins/myservice/etc/init.d/myservice-client plugins/myservice/sbin/myservice-clientd
Next we need to create the boot-service definition which is done via a simple xml configuration file. Please create ../src/plugins/myservice/etc/myservice-plugin.xml with the following content :
<?xml version="1.0"?>
<!DOCTYPE plugin PUBLIC "-//JPF//Java Plug-in Manifest 0.2" "http://jpf.sourceforge.net/plugin_0_2.dtd">
<plugin id="com.qlusters.qrm.plugins.puppet-plugin" version="0.0.1" >
<requires>
<import plugin-id="com.qlusters.qrm.plugins.core"/>
</requires>
<extension plugin-id="com.qlusters.qrm.plugins.core" point-id="BootService" id="myservice">
<parameter id="name" value="myservice"/>
<parameter id="runlevel" value="35"/>
<parameter id="package" value="http://$QRM_SERVER_IP_ADDRESS/unsecure/myservice/myservice-client.tgz"/>
<parameter id="init" value="plugins/myservice/etc/init.d/myservice-client"/>
</extension>
</plugin>
This definition creates a new boot-service in openQRM named "myservice". All systems associated with this boot-service will download the myservice-client.tgz package, unpack it and run its init-script at init 3 or 5. Please add this file to the INSTALL_FILES variable in the Makefile. INSTALL_FILES should now look like :
INSTALL_FILES := etc/myservice.xml, -m 0700 etc/init.d, include, -m 700 sbin, etc/myservice-plugin.xml
To make the myservice-client.tgz package available for download we copy it to a public section of the webserver. This step should happen during the installation of the plugin so the "myservice_install" and "myservice_uninstall" functions in ../src/plugins/myservice/include/myservice-functions should be updated as following :
function myservice_install() {
echo "installing the myservice plugin"
# this function will run during installing the plugin
mkdir -p $QRM_SERVER_BASE_DIR/qrm/usr/tomcat/webapps/ROOT/unsecure/myservice
/bin/cp -f $QRM_SERVER_BASE_DIR/qrm/plugins/myservice/client/myservice-client.tgz $QRM_SERVER_BASE_DIR/qrm/usr/tomcat/webapps/ROOT/unsecure/myservice/
}
function myservice_uninstall() {
echo "uninstalling the myservice plugin"
# this function will run during uninstallation
/bin/rm -rf $QRM_SERVER_BASE_DIR/qrm/usr/tomcat/webapps/ROOT/unsecure/myservice
}
Last step for the boot-service setup is to associate it with the systems managed by openQRM. This step should happen once during installation so the "myservice_run_once" function (also in ../src/plugins/myservice/include/myservice-functions) should be used and updated as following :
function myservice_run_once() {
echo "running run_once for the myservice plugin"
# this function will run once after the plugins installation
# phase and can be used to e.g. register new components or
# apply any updates/changes to the configuration
# boot-services for images
$QRM_SERVER_BASE_DIR/qrm/bin/qrm-cli boot associate -k myservice -t image
}
Not to forget is that this boot-service should be removed during uninstallation of the "myservice" plugin. Please update again the "myservice_uninstall" function and add the line to disassociate the boot-service. It should look like :
function myservice_uninstall() {
echo "uninstalling the myservice plugin"
# this function will run during uninstallation
/bin/rm -rf $QRM_SERVER_BASE_DIR/qrm/usr/tomcat/webapps/ROOT/unsecure/myservice
$QRM_SERVER_BASE_DIR/qrm/bin/qrm-cli boot dissociate -k myservice -t image
}
编译和安装插件“myservice”
The "myservice" plugin is now ready to be build and installed. To build/rebuild it please run "make clean && make && make install" in the "myservice" plugin directory. Here an example output :
[root@demo myservice]# make clean && make && make install
# Do everything here to clean-up the install-section
cleaning up myservice
# Do everything here to e.g. create the binaries for
# your plugin. This section should compile your component "myservice"
making the myservice-plugin
/usr/bin/install -D etc/myservice.xml ../../../out/qrm/plugins/myservice/etc/myservice.xml
/usr/bin/install -D -m 0700 etc/init.d/myservice-client ../../../out/qrm/plugins/myservice/etc/init.d/myservice-client
/usr/bin/install -D -m 0700 etc/init.d/myservice-server ../../../out/qrm/plugins/myservice/etc/init.d/myservice-server
/usr/bin/install -D include/myservice-functions ../../../out/qrm/plugins/myservice/include/myservice-functions
/usr/bin/install -D -m 700 sbin/myservice-clientd ../../../out/qrm/plugins/myservice/sbin/myservice-clientd
/usr/bin/install -D -m 700 sbin/myservice-serverd ../../../out/qrm/plugins/myservice/sbin/myservice-serverd
/usr/bin/install -D etc/myservice-plugin.xml ../../../out/qrm/plugins/myservice/etc/myservice-plugin.xml
touch ../../../out/qrm/plugins/myservice/include/.files_installed
# Do everything here additional needed to install "myservice" in
# the OUT_DIR. No compilation should be done in this step
# Files in INSTALL_FILES will be installed automatically
installing myservice for Qrm
mkdir -p ../../../out/qrm/plugins/myservice/client
tar -C ../../../out/qrm/ --exclude CVS --exclude Makefile -czf ../../../out/qrm/plugins/myservice/client/myservice-client.tgz plugins/myservice/etc/init.d/myservice-client plugins/myservice/sbin/myservice-clientd
[root@demo myservice]#
This compile procedure now created the "installable" plugin at ../../../out/qrm/plugins/myservice. To install the "myservice" plugin please copy the ../../../out/qrm/plugins/myservice directory into the plugins directory of your running openQRM-server and enable the "myservice" plugin via the qrm-installer :
[root@demo myservice]# /bin/cp -aR ../../../out/qrm/plugins/myservice /opt/qrm/plugins/
[root@demo myservice]# cd /opt/qrm
[root@demo qrm]# ./qrm-installer -i -m myservice
#####################################################
# #
# #
# Welcome to OpenQRM 3.1.4 #
# installation procedure #
# #
# by Qlusters Inc #
#####################################################
(logfile for the installation at /var/log/qrm/qrm-installer.log)
Components will be installed in following order:
1. myservice
Please notice
QRM will be installed with the following configuration :
General setup:
--------------
QRM server interface : eth0
QRM server base directory : /opt
QRM server log directory : /var/log/qrm
QRM nodes base directory : /opt
QRM nodes logs directory : syslog
QRM default kernel :
Database setup:
---------------
IP : localhost
name : qrm
port : 3306
socket : /var/lib/mysql/mysql.sock
username : root
password :
Component myservice Configuration
------------------------------------------
There is no configurable parameters for this component
Is the configuration correct? (y - continue, n - cancel , c - configure)? (y/n/c) [y]
==================================
Running components sanity checks
==================================
myservice........
[ OK ]
==================================
Running install stage for components
==================================
myservice..............
Installing myservice
installing the myservice plugin
[ OK ]
Do you want to restart QRM server? (y/n) [y]
Stopping the Qrm-server ------------/ [ OK ]
Starting the Qrm-server ---------/ [ OK ]
#################################################################
Installation finished
Components with status SUCCESS : myservice
#################################################################
[root@demo qrm]#
The "myservice" plugin is now installed and enabled on the openQRM-server. To check the "myservice-server" plugin service came up correctly we check that the "myservice-serverd" is running by "ps" :
[root@demo ~]# ps -C myservice-serverd
PID TTY TIME CMD
10021 pts/2 00:00:00 myservice-serve
[root@demo ~]#
To check the "myservice-client" plugin service came up correctly we can quickly deploy a VE and check that the "myservice-clientd" is running on that system :
[root@fc4_test_small_nfs-1 ~]# ps -C myservice-clientd
PID TTY TIME CMD
1992 ? 00:00:00 myservice-clien
[root@fc4_test_small_nfs-1 ~]#
编译"myservice"插件的rpm-packages。
The "myservice" plugin is now fully integrated into the openQRM build-system. To create rpm-packages for the "myservice" plugin you can simply run :
make clean PACKAGE_TYPE=rpm
make all PACKAGE_TYPE=rpm
make install PACKAGE_TYPE=rpm
make pack_rpm PACKAGE_TYPE=rpm
from the main source dir. This will create rpm-packages for the openQRM-base and all plugin available in the plugins source directory. To create Debian (.deb) packages you can use the following make commands :
make clean PACKAGE_TYPE=deb
make all PACKAGE_TYPE=deb
make install PACKAGE_TYPE=deb
make pack_rpm PACKAGE_TYPE=deb
总结(part 1)
We have now successfully integrated the example "myservice" client-server based service into openQRM via a custom plugin.
How to go on from here ?
We (the openQRM-Team) are working on further parts of this openQRM plugin-howto which will cover :
- working with custom Resource-, Image- and VE-parameter
- adding custom menu-items and web-pages
- interacting with the objects in the openQRM-server via java
- and more
You can download all files used in for this howto (part 1) packed in a .tgz at :
http://downloads.openqrm.net/contrib/plugin-howto/myservice-plugin-1.0.tgz