Building Your Contrib
This how-to intend to give you a tour of what you need with some usefull tmeplates to build you own contrib on SME10 with last php-fpm, httpd 2.4, core backup integration and systemd usage
Architecture
SPEC file
%define name foo
%define version 3.6.431
%define release 1
Summary: foo is a helpdesk system
Name: %{name}
Version: %{version}
Release: %{release}%{?dist}
Distribution: SME Server
License: GNU GPL version 2
URL: http://www.fooweb.com
Group: SMEserver/addon
#wget http://www.fooweb.com/downloads/foo-3.6.431.tar.gz
Source: foo-3.6.431.tar.gz
Packager: Stephen Foo <support@foo.net>
BuildArchitectures: noarch
BuildRoot: /var/tmp/%{name}-%{version}
BuildRequires: e-smith-devtools
Requires: e-smith-release >= 7.0
AutoReqProv: no
%description
http://foo.org/
foo is a helpdesk system
%changelog
* Thu Sep 13 2007 Stephen Foo <support@foo.net> 3.6.431-1
- initial release
- builds from unchanged .tar.gz
%prep
%setup -c -n %{name}
%build
perl createlink
%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 \
--dir '/opt/foo/tempdir/' 'attr(775,www,www)' \
--file '/opt/foo/logo.gif' 'attr(660,www,www)' \
--ignoredir '/opt/foo' \
--dir /var/log/foo 'attr(0755,root,root)' \
--dir /var/log/php/foo 'attr(0755,www,www)' \
--dir /var/lib/php/foo 'attr(0755,www,www)' \
--dir /var/lib/php/foo/tmp 'attr(0755,www,www)' \
--dir /var/lib/php/foo/opcache 'attr(0755,www,www)' \
--dir /var/lib/php/foo/session 'attr(0755,www,www)' \
> %{name}-%{version}-filelist
%clean
cd ..
rm -rf %{name}
%files -f %{name}-%{version}-filelist
%defattr(-,root,root)
Createlinks
#!/usr/bin/perl
use strict;
use esmith::Build::CreateLinks qw(:all);
my $pkg= "smeserver-mycontrib";
my $event = "${pkg}-update";
event_actions($event, qw(
myfoo 05
systemd-default 88
systemd-reload 89
));
event_templates($event, qw(
/etc/e-smith/db/configuration/migrate/80mycontrib
/etc/httpd/conf/httpd.conf
/etc/opt/remi/php80/php-fpm.d/www.conf
/opt/foo/foo.conf
));
event_services($event, qw(
php80-php-fpm restart
httpd-e-smith restart
mysql.init restart
mycontrib restart
));
use esmith::Build::Backup qw(:all);
backup_includes($pkg, qw(
/opt/foo/
));
Configuration DB
In order to have a service to start using systemd, you need it to be defined in the e-smith configuration db, here is the bare minimum:
echo "service" > smeserver-mycontrib-1.0/root/etc/e-smith/db/configuration/defaults/mycontrib/type
echo "enabled" > smeserver-mycontrib-1.0/root/etc/e-smith/db/configuration/defaults/mycontrib/status
You might also need to add a TCPPort or TCPPorts property if needed to open ports in firewall, and also an access property to make access private or public (default is localhost). You can also populate any dedicated property you would need for your own use.
Mariadb myslq init
generate default user, password and db for your app
create the following file to generate the default password dbname and dbuser
smeserver-mycontrib-1.0/root/etc/e-smith/db/configuration/migrate/80mycontrib
{
use MIME::Base64 qw(encode_base64);
my $rec = $DB->get('mycontrib') || $DB->new_record('mycontrib', {type => 'service'});
my $pw = $rec->prop('DbPassword');
return "" if $pw;
$pw = MIME::Base64::encode(int( (1000000000000000) * rand() ));
chomp($pw);
$rec->set_prop('DbPassword', "$pw" );
}
and the following
echo "mycontrib" > smeserver-mycontrib-1.0/root/etc/e-smith/db/configuration/defaults/mycontrib/DbName
echo "mycontrib" > smeserver-mycontrib-1.0/root/etc/e-smith/db/configuration/defaults/mycontrib/DbUser
create and populate your db
Then, create a file in smeserver-mycontrib-1.0/root/etc/e-smith/templates/etc/e-smith/sql/init/80mycontrib.
This content will generate a new user and db into your mariadb server, when expanding the template and restarting service mysql.init
{
my $db = $mycontrib{DbName} || 'mycontrib';
my $user = $mycontrib{DbUser} || 'mycontrib';
my $pass = $mycontrib{DbPassword} || 'changeme';
$OUT .= <<END
#! /bin/sh
if [ -d /var/lib/mysql/$db ]; then
exit
fi
/usr/bin/mysql <<EOF
CREATE DATABASE $db DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
use $db;
#Insert application specific command to create database structure
use mysql;
GRANT ALL PRIVILEGES ON $db.* TO $user\@localhost
IDENTIFIED BY '$pass';
flush privileges;
EOF
END
}
You can also add some line in there to populate the content of the database using a mysql dump. Pay attention to make it not to overwrite existing data ;)
Systemd
all you need to have your service to start is
- a configuration db key foo of type service with status enabled
- a dropin file as this one
smeserver-mycontrib-1.0/root/usr/lib/systemd/system/foo.service.d/50koozali.conf
[Service]
#first we reset the ExecStartPre, if we do not want the initial lines to be executed
ExecStartPre=
#our needs
ExecStartPre=-/sbin/e-smith/service-status foo
ExecStartPre=-/sbin/e-smith/expand-template /opt/foo/foo.conf
Restart=always
[Install]
#so it start on boot
WantedBy=sme-server.target
PHP-FPM
all you need is to add and improve this fragment .
What version of php it will be used against depends on the value you set on the line "if ($PHP_VERSION eq '80'){". This template is called for every version of php using the magic of template.metadata.
smeserver-foo-1.0/root/etc/e-smith/templates/etc/php-fpm.d/www.conf/15foo
{
if ($PHP_VERSION eq '80'){
if (($foo{'status'} || 'disabled') eq 'enabled'){
my $max_upload_size = ($foo{MaxUploadSize} || '4096');
$max_upload_size .= 'M' if ($max_upload_size =~ m/^\d+$/);
my $memory_limit = ($foo{MemoryLimit} || '500M');
$memory_limit .= 'M' if ($memory_limit =~ m/^\d+$/);
my $open_basedir= $foo{PHPBaseDir} || '';
$open_basedir = "/opt/foo/html/:/var/log/foo/:/var/lib/php/foo:$open_basedir";
my $id = 'foo';
my $max_children = $foo{'PHPmaxChildren'} || 20;
my $min_spare_servers = $foo{'PHPminServers'} || 4;
my $start_servers = $foo{'PHPstartServers'} || 6;
my $max_spare_servers = $foo{'PHPmaxServers'} || 8;
my $max_requests = $foo{'PHPmaxRequests'} || 1000;
$min_spare_servers = ( $min_spare_servers > $max_spare_servers ) ? printf("%.0f",$max_spare_servers/2) : $min_spare_servers;
$start_servers = ( $start_servers > $max_spare_servers ) ? printf("%.0f", $max_spare_servers /2 + $min_spare_servers/2 ) : $start_servers;
$OUT .=<<_EOF;
[php$PHP_VERSION-$id]
user = www
group = www
listen.owner = root
listen.group = www
listen.mode = 0660
listen = /var/run/php-fpm/php$PHP_VERSION-$id.sock
pm = dynamic
pm.max_children = $max_children
pm.start_servers = $start_servers
pm.min_spare_servers = $min_spare_servers
pm.max_spare_servers = $max_spare_servers
pm.max_requests = $max_requests
php_admin_value[session.save_path] = /var/lib/php/$id/session
php_admin_value[session.gc_maxlifetime] = 86400
php_admin_value[opcache.file_cache] = /var/lib/php/$id/opcache
php_admin_value[upload_tmp_dir] = /var/lib/php/$id/tmp
php_admin_value[error_log] = /var/log/php/$id/error.log
slowlog = /var/log/php/foo/slow.log
php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f php@{ $DomainName }
php_admin_flag[display_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = syslog
php_admin_value[memory_limit] = $memory_limit
php_admin_value[max_execution_time] = 3600
php_admin_value[post_max_size] = $max_upload_size
php_admin_value[upload_max_filesize] = $max_upload_size
php_admin_value[disable_functions] = system, show_source, symlink, dl, passthru, phpinfo, escapeshellarg, escapeshellcmd
php_admin_value[open_basedir] = $open_basedir
php_admin_flag[allow_url_fopen] = on
php_admin_flag[file_uploads] = on
php_admin_flag[session.cookie_httponly] = on
php_admin_flag[allow_url_include] = off
php_admin_value[session.save_handler] = files
php_admin_flag[output_buffering] = off
_EOF
}
else{
$OUT .= '; foo is disabled';
}
}
}
you will also need the specific files created and accessible by www, that is done in the spec file for the permission and you need also to create them
mkdir -p smeserver-foo-1.0/root/var/lib/php/foo/{session,tmp,opcache}
mkdir -p smeserver-foo-1.0/root/var/log/php/foo
mkdir -p smeserver-foo-1.0/root/var/log/foo
Apache httpd
you will need to create a template fragment for your contrib in order to get it displayed by the httpd server. There are three major situations:
php-fpm using a subdir
{
$allow = ($access eq 'public')?'all granted':"ip $localAccess $externalSSLAccess";
}
Alias /nextcloud /usr/share/nextcloud
<Directory "/usr/share/nextcloud">
Options +FollowSymLinks
AllowOverride All
<FilesMatch \.php$>
SetHandler "proxy:unix:/var/run/php-fpm/php81-mycontrib.sock|fcgi://localhost"
</FilesMatch>
Require {$allow}
SetEnv HOME /usr/share/nextcloud
SetEnv HTTP_HOME /usr/share/nextcloud
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
</Directory>
<Directory "/home/e-smith/files/nextcloud/data/">
# just in case if .htaccess gets disabled
Require all denied
</Directory>
php-fpm using a dedicated virtualhost
You can simply use the virtualhost template subfolder WebAppVirtualHost/ or create your own. If you want to create your own check the content of /etc/e-smith/templates/etc/httpd/conf/httpd.conf/WebAppVirtualHost and adapt it to your needs with a new path
Then the admin after installing the contrib can set the dedicated virtualhost using the command
db domains set mycontrib.mydomain.com domain Content Primary Description mycontrib DocumentRoot /usr/share/mycontrib Nameservers internet RequireSSL enabled TemplatePath WebAppVirtualHost letsencryptSSLcert enabled
proxypass to a port
You can simply use the proxypass directive see SME Server:Documentation:ProxyPass, either using a domain or an URI / location.
You can also create your own template fragment like 99madsonic
{
$OUT .= " # static html, js, images, etc. served from coolwsd\n";
$OUT .= " # browser is the client part of LibreOffice Online\n";
$OUT .= " ProxyPass /browser http://127.0.0.1:9980/browser retry=0\n";
$OUT .= " ProxyPassReverse /browser http://127.0.0.1:9980/browser\n";
$OUT .= " # WOPI discovery URL\n";
$OUT .= " ProxyPass /hosting/discovery http://127.0.0.1:9980/hosting/discovery retry=0\n";
$OUT .= " ProxyPassReverse /hosting/discovery http://127.0.0.1:9980/hosting/discovery\n";
}
Assemble and build
Final step is to assemble your archive content, and build a rpm. This is quite similar to what you can see in Package Modification or Package Import