SME Server:Documentation:Developers Manual:Chapter13

From SME Server
Revision as of 08:35, 1 June 2008 by Cactus (talk | contribs) (Added Template:Note box)
Jump to navigationJump to search

Packaging your application

Once you have created a customization for your SME Server by adding new files, directories, and symbolic links (for your actions, events, etc.) - and perhaps also triggering an action to initialize your customization - you are ready to package your customization into an RPM.


A quick introduction to RPMs

All SME Server software packages are distributed as RPM packages. This is the format used by CentOS and other major Linux distributions for distributing applications and other collections of files. The RPM system provides the ability to install, upgrade, remove and (importantly) verify the contents of installed packages.

An RPM essentially consists of an archive of all the files required by a piece of software. Additionally, it includes meta-information describing the software, and scripts which must be run to install or uninstall the software.

Meta-information stored in an RPM includes:

  1. summary and description of the software
  2. package name
  3. version number
  4. copyright information
  5. category/group to which the software belongs
  6. name and email address of the packager
  7. pre-requisites to installing this package
  8. ... and more

Selecting and creating RPMs for your application

Your application will typically depend on several components:

  1. Software packages that are shipped as a standard part of the SME Server. You do not need to include any of these packages; they are always present in the runtime environment.
  2. Software packages that are not a standard part of the SME Server, but that are required by your software, and would also be of general use in the runtime environment. For example: a Java runtime environment, libraries that enable communication with devices, etc. If possible, these packages should be made into separate packages, rather than being included in your application. This makes it easier to share them with other applications and enforces version compatiblity.
  3. Software packages that are not a standard part of the SME Server, and that are specific to your software application (i.e. not generally useful in the runtime environment). This is the raw Linux version of your application without any specific SME Server integration code. For example, if your application is already available for Linux in the form of RPMs - these RPMs are what we are referring to. These are referred to as the application RPMs.
  4. Any new files that you have created specifically in order to integrate your application into the SME Server runtime environment - should be packaged into a single RPM, as explained in the next section. This is referred to as the integration RPM.

So, if your application is based on Linux software that has already been packaged into RPMs, then you will need to create one new RPM:the integration RPM.

If, on the other hand, your application is based on Linux software that has not yet been packaged into RPMs, then you will probably need to create at least two RPMs: one or more application RPMs, and the integration RPM.

Finally, for simple customizations (such as the loggerdemo example earlier in this manual) there may be no application RPM at all. This would be typical if the point of the application is to change the server configuration without really adding a new software package. In this case you need only the integration RPM which contains the new template fragments, user interface screens, etc..

All files on the system, except for user data, must be installed by RPMs.


Setting up your RPM development environment

If you haven't done so already, set up an RPM development environment. If you are using an SME Server as your development environment, you will need to alter your user account to enable regular login. If you want to enable account "joe", then you would type the following commands from the root account:

chsh -s /bin/bash joe

db accounts setprop joe Shell /bin/bash
Important.png Note:
Shell/login access is disabled by default to enhance the security of the SME Server. Shell access should only be provided to users who require it and who can be trusted to maintain system security.

Then you should be able to log in to the server as user "joe", and get a Linux command line prompt. Log in, then type the following commands to set up your RPM work area:

cd ~/
mkdir -p rpms/{SRPMS,BUILD,SOURCES,SPECS,RPMS,lib}
mkdir -p rpms/RPMS/{i386,noarch}
echo "%_topdir $HOME/rpms" > ~/.rpmmacros

You will now find that you have a directory called rpms in which you will do your work. Under this are the following subdirectories:

SOURCES
The base material from which RPMs are built -- source code, tarballs, etc.
BUILD
Working area used by the rpmbuild program during RPM creation
SPECS
Specification files for building RPMs
SRPMS
Source RPMS (created by build process)
RPMS
Binary RPMS (created by build process). Has subdirectories noarch and i386 for architecture independent and x86 platforms respectively.

As you prepare software to turn into RPMs, you will place files in these directories as appropriate. The following sections will describe what goes where as each item is covered.

Tip: As you start work on an RPM for version x.y.z of a package, create a subdirectory rpms/SOURCES/yourpackage-x.y.z/ to work in.

mkdir rpms/SOURCES/yourpackage-x.y.z

Under this directory there should be a subdirectory called root, under which is an image of the file hierarchy that will be installed by the RPM.

mkdir rpms/SOURCES/yourpackage-x.y.z/root


Building an RPM

This section describes the process for building an RPM - step by step.

Choose a name and version number for your package. We are going to package the complete loggerdemo example and will use loggerdemo and 1.0.0 as the name and version number.

Collect all of the files which have been created in the previous sections into the /tmp/ directory. There is one additional file createlinks which looks like this:

#!/usr/bin/perl -w

use esmith::Build::CreateLinks qw(:all);
use File::Basename;

my $panel = "manager";

panel_link("loggerdemo", $panel);

Create the directory hierarchy required for building the RPM. This is very close to the hierarchy on the installed system.

# Change to the SOURCES directory
cd ~/rpms/SOURCES

# Remove old files (check that you don't need anything here!)
rm -rf loggerdemo-1.0.0

# Create new directory
mkdir loggerdemo-1.0.0
cd loggerdemo-1.0.0

# The crontab template fragment
mkdir -p root/etc/e-smith/templates/etc/crontab
cp /tmp/25templatedemo root/etc/e-smith/templates/etc/crontab

# The web panel description
mkdir -p root/etc/e-smith/web/functions
cp -p /tmp/loggerdemo !$

# The web panel implementation
mkdir -p root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel
cp -p /tmp/loggerdemo.pm !$

# The web panel English localisation
mkdir -p root/etc/e-smith/locale/en-us/etc/e-smith/web/functions
cp -p /tmp/loggerdemo-en !$

# The createlinks auxiliary file
cp -p /tmp/createlinks .

Your directory structure should now look like this:

[gordonr@sevendev1 loggerdemo-1.0.0]$ find . -type f
./root/etc/e-smith/templates/etc/crontab/25templatedemo
./root/etc/e-smith/locale/en-us/etc/e-smith/web/functions/loggerdemo
./root/etc/e-smith/web/functions/loggerdemo
./root/usr/lib/perl5/site_perl/esmith/FormMagick/Panel/loggerdemo.pm
./createlinks

Package the directory into a tarball: cd ~/rpms/SOURCES

tar zcvf loggerdemo-1.0.0.tar.gz loggerdemo-1.0.0

Create the RPM specification "SPEC" file ~/rpms/SPECS/loggerdemo.spec which looks like this:

%define name loggerdemo
%define version 1.0.0
%define release 01

Summary: SME Server logger demo
Name: %{name}
Version: %{version}
Release: %{release}
License: GPL
Group: Networking/Daemons
Source: %{name}-%{version}.tar.gz
Packager: Fred Frog <red@example.com>
BuildRoot: /var/tmp/%{name}-%{version}-%{release}-buildroot
BuildArchitectures: noarch

%description
Logger Demo sample application.

%changelog
* Thu Feb 2 2006 Fred Frog <fred@example.com>
- 1.0.0-01
- Original version

%prep
%setup

%build
perl createlinks

## NEW ADVICE, DB fragments should be created as files
DEFAULTS=root/etc/e-smith/db/configuration/defaults/loggerdemo
mkdir -p $DEFAULTS

echo "service"  > $DEFAULTS/type
echo "enabled"  > $DEFAULTS/status
echo "10"       > $DEFAULTS/Interval

%install
rm -rf $RPM_BUILD_ROOT
(cd root ; find . -depth -print | cpio -dump $RPM_BUILD_ROOT)
rm -f %{name}-%{version}-filelist
/sbin/e-smith/genfilelist $RPM_BUILD_ROOT > %{name}-%{version}-filelist

%clean
rm -rf $RPM_BUILD_ROOT

%post
/sbin/e-smith/expand-template /etc/crontab
true

%postun
/sbin/e-smith/expand-template /etc/crontab
true

%files -f %{name}-%{version}-filelist
%defattr(-,root,root)

Note the %post (post-installation) and %postun (post-uninstallation) statements which expand the /etc/crontab template after installing or uninstalling the RPM.

Check that your RPM will build OK with "build prepare":

cd ~/rpms/SPECS
rpmbuild -bp loggerdemo.spec

The last line of output should be + exit 0 if rpmbuild is successful.

Run the rpmbuild command again to actually create your RPM with the "build all" options:

rpmbuild -ba loggerdemo.spec

If everything was successful, the last line of output should again be + exit 0.

The RPMs should have been generated and put into ~/rpms/RPMS/noarch/ as this program can run equally well on any platform. A source RPM should also exist in ~/rpms/SRPMS/.

Test your RPM by installing it on an SME Server test box.

Important.png Note:
RPMs need to be installed as root, but you should not log in as the root user. Instead, you should create a normal user and provide them with 'root' privileges via the sudo command. To provide full sudo rights to the user joe, use the su - -c /usr/sbin/visudo and add the following line to the end of the file: joe ALL=(ALL) ALLYou can then use the sudo to run commands as root when required. You will be prompted for your password (not the root password) which ensures that someone else isn't using your terminal.

sudo yum localinstall  ~/rpms/RPMS/noarch/loggerdemo-1.0.0-01.noarch.rpm
Preparing...                ########################################### [100%]
   1:loggerdemo             ########################################### [100%]
Migrating existing database mailpatterns
Migrating existing database hosts
Migrating existing database configuration
Migrating existing database yum_repositories
Migrating existing database networks
Migrating existing database yum_updates
Migrating existing database yum_installed
Migrating existing database spamassassin
Migrating existing database accounts
Migrating existing database backups
Migrating existing database yum_available
Migrating existing database domains

The customization should be fully installed, and the /etc/crontab file should show the customization.

Then remove the customization:

sudo rpm -e loggerdemo

The customization should be completely gone, and the /etc/crontab file should look the way it did before.


The createlinks script

The source tarballs of an RPM should not include symbolic links as they are difficult to store under many version control systems and cause issues when generating patches. Since the SME Server uses many symbolic links, there are simple methods for creating the ones required. This is done through the createlinks script which is called from the %build section of the SPEC file. Let's examine one. It starts with the standard Perl script header and an import of the required module:

#!/usr/bin/perl -w
 
 use esmith::Build::CreateLinks qw(:all);

The templates2events function can be used to create the appropriate templates2expand links in various events:

my $imap  = "/var/service/imap";
my $imaps = "/var/service/imaps";

templates2events("/etc/dovecot.conf", qw(bootstrap-console-save console-save));
templates2events("$imap/config",      qw(bootstrap-console-save email-update));
templates2events("$imaps/config",     qw(bootstrap-console-save email-update));

Note that the first argument is a filename and the second argument is a list of events in which to create the link. The safe_symlink function can be used to create a generic symbolic link, as well as the directory hierarchy enclosing that link:

for my $event (qw(
    email-update
    ldap-update
    network-create
    network-delete
    ))
{
    safe_symlink("sigusr1", "root/etc/e-smith/events/$event/services2adjust/imap");
}

safe_symlink("daemontools", "root/etc/rc.d/init.d/imap");

The event_link function is used to create the links from the event directories to the generic actions directory. For example:

for my $event (qw(post-upgrade))
{
    event_link("imap-relocate-maildirs", $event, "05");
}

creates a symbolic link S05imap-relocate-maildirs in the post-upgrade event. The target of the symbolic link will be the imap-relocate-maildirs script in the /etc/e-smith/events/actions/ directory.

Finally, the service_link_enhanced function makes it simple to create the /etc/rc.d/rc7.d and similar startup symlinks:

service_link_enhanced("imap", "S55", "7");
service_link_enhanced("imap", "K45", "6");
service_link_enhanced("imap", "K45", "0");
service_link_enhanced("imap", "K45", "1");

More documentation on this module can be seen with the command perldoc esmith::Build::CreateLinks.