Packaging Reference¶
This guide contains information about creating StarlingX packages.
Tips and tricks¶
Here are some things to consider when creating packages:
Make sure you have the correct BuildRequires dependencies listed. Mock will ensure that these packages are installed in the build environment before trying to build the package in question. Be aware that CentOS often uses
-devel
for developer packages (which typically include headers and the.so
shared library link) whereas StarlingX generally uses-dev
. For BuildRequires, you can use the following:Instead of
virtual/x86_64-wrs-linux-gcc
, you can usegcc
.Instead of
glib-2.0
, useglib2-devel
.Instead of
sqlite3
, usesqlite-devel
.You can comment out or delete
virtual/libc
andvirtual/x86_64-wrs-linux-compilerlibs
.
Typically, you do not need to manually add dependencies due to shared libraries to either Requires or Provides in the spec file. RPM will usually add them automatically.
When your package creates a shared library, make sure to install it with 755 (or other suitably executable) permissions. The automatic dependency handling only runs if the library file is actually executable.
It can be useful to refer to a bitbake-generated spec file, especially for STX-specific packages. Generally the
build
andinstall
phases are missing from the bitbake-generated spec file and you must add them.Make sure all necessary files are listed, because the build_srpm phase will only include source files listed in your spec file. In a simple case, this can be just the following line:
Source: %{name}-%{version}.tar.gz
Package without a makefile¶
In this case, the process is generally similar to the above instructions, but
the %build
section has alternative commands or may be omitted altogether.
The install phase is done directly in the RPM spec file.
For example, the collector
package has no makefile. Its spec file is at
stx/utilities/tools/collector/centos/collector.spec
. There is no “build”
phase, because the files are scripts. However, the files must be unpacked and
installed into the appropriate locations. The relevant bits look like this:
Source0: %{name}-%{version}.tar.gz
%prep
%setup
%install
mkdir -p %{buildroot}
install -d 755 -d %{buildroot}%{_sysconfdir}/collect.d
install -d 755 -d %{buildroot}%{_sysconfdir}/collect
install -d 755 -d %{buildroot}/usr/local/sbin
install -d 755 -d %{buildroot}/usr/local/bin
install -d 755 -d %{buildroot}%{_sbindir}
install -m 755 collect %{buildroot}/usr/local/sbin/collect
install -m 755 collect_host %{buildroot}/usr/local/sbin/collect_host
install -m 755 collect_date %{buildroot}/usr/local/sbin/collect_date
install -m 755 collect_utils %{buildroot}/usr/local/sbin/collect_utils
install -m 755 collect_parms %{buildroot}/usr/local/sbin/collect_parms
install -m 755 collect_mask_passwords %{buildroot}/usr/local/sbin/collect_mask_passwords
install -m 755 expect_done %{buildroot}/usr/local/sbin/expect_done
install -m 755 collect_sysinv.sh %{buildroot}%{_sysconfdir}/collect.d/collect_sysinv
install -m 755 collect_psqldb.sh %{buildroot}%{_sysconfdir}/collect.d/collect_psqldb
install -m 755 collect_openstack.sh %{buildroot}%{_sysconfdir}/collect.d/collect_openstack
install -m 755 collect_networking.sh %{buildroot}%{_sysconfdir}/collect.d/collect_networking
install -m 755 collect_ceph.sh %{buildroot}%{_sysconfdir}/collect.d/collect_ceph
install -m 755 collect_sm.sh %{buildroot}%{_sysconfdir}/collect.d/collect_sm
install -m 755 collect_tc.sh %{buildroot}%{_sysconfdir}/collect.d/collect_tc
install -m 755 collect_nfv_vim.sh %{buildroot}%{_sysconfdir}/collect.d/collect_nfv_vim
install -m 755 collect_ovs.sh %{buildroot}%{_sysconfdir}/collect.d/collect_ovs
install -m 755 collect_patching.sh %{buildroot}%{_sysconfdir}/collect.d/collect_patching
install -m 755 collect_coredump.sh %{buildroot}%{_sysconfdir}/collect.d/collect_coredump
install -m 755 collect_crash.sh %{buildroot}%{_sysconfdir}/collect.d/collect_crash
install -m 755 collect_ima.sh %{buildroot}%{_sysconfdir}/collect.d/collect_ima
install -m 755 collect_fm.sh %{buildroot}%{_sysconfdir}/collect.d/collect_fm
install -m 755 collect_containerization.sh %{buildroot}%{_sysconfdir}/collect.d/collect_containerization
install -m 755 collect_dc.sh %{buildroot}%{_sysconfdir}/collect.d/collect_dc
install -m 755 etc.exclude %{buildroot}%{_sysconfdir}/collect/etc.exclude
install -m 755 run.exclude %{buildroot}%{_sysconfdir}/collect/run.exclude
ln -sf /usr/local/sbin/collect %{buildroot}/usr/local/bin/collect
ln -sf /usr/local/sbin/collect %{buildroot}%{_sbindir}/collect
Either the setup
or autosetup
macro can be used to unpack the Source0
tarball in %{_builddir}
. Next, a number of files are explicitly installed
into %{buildroot}
. Most of these come from the unpacked tarball. One file
comes from the original source directory, since it wasn’t moved over to
%{_builddir}
in the prep phase. All the other sections in the spec file are
treated the same way as the above package.
OpenStack and Python packages¶
These packages are similar to the above as far as requirements, dependencies, etc. The build phase is a bit different since there is no compilation step involved.
Source0: %{name}-%{version}.tar.gz
%prep
%setup -q
%build
%{__python2} setup.py build
%install
%{__python2} setup.py install -O1 --skip-build --root %{buildroot}
mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d
install -pm 644 tools/nova.bash_completion \
%{buildroot}%{_sysconfdir}/bash_completion.d/nova
In this case, the setup
macro unpacks the Source0 tarball in the prep
phase. Next the setup.py
that is part of the Python package handles
the actual process of building and installing the Python code. During the
install phase, a separate file is installed which isn’t handled by the Python
installer.
CentOS package with appended patches¶
This example uses the parted
package from CentOS and appends a few
patches of our own.
Assuming this package has never been modified by StarlingX previously, find a home for the package. This example uses
$MY_REPO/stx/integ/filesystem/parted
.MY_GIT_ROOT=$MY_REPO/stx/integ MY_PKG_ROOT=$MY_GIT_ROOT/filesystem/parted mkdir -p $MY_PKG_ROOT cd $MY_PKG_ROOT # You must also add the new package directory to your local centos_pkg_dirs file if not already present echo filesystem/parted >> $MY_GIT_ROOT/centos_pkg_dirs
Create a directory skeleton. The
patches
directory contains patches applied to the tarball inside thesrc.rpm
. Themeta_patches
directory contains patches applied to the rpmbuild directory of the.src.rpm
and are used to modify theSPECS/*.spec
file, or theSOURCES/*
files.mkdir -p centos/meta_patches mkdir -p centos/patches touch centos/meta_patches/PATCH_ORDER echo TIS_PATCH_VER=1 > centos/build_srpm.data
Tell
build-srpms
where to find thesrc.rpm
in thesrpm_path
file. Two locations are supported for source RPMS: the$MY_REPO/cgcs-centos-repo
directory is for source RPMS provided by CentOS. Tell the build system to search for a source RPM using themirror:
prefix when you specify the path to the source RPM.find -L $MY_REPO/cgcs-centos-repo/ -name 'parted*.src.rpm' /localdisk/<username>/designer/test/cgcs-root/cgcs-centos-repo/Source/parted-3.1-23.el7.src.rpm echo "mirror:Source/parted-3.1-23.el7.src.rpm" > centos/srpm_path
The other location supported by
build-srpms
is the downloads subgit of your layers (found in$MY_REPO/stx/downloads
for CGCS, for example). This should be used for packages that CentOS does not provide. In this case, place the source RPM you downloaded in the directory, and use therepo:
prefix when creating yoursrpm_path
file. The base path forrepo:
is$MY_REPO
, so specify paths from that point.cp ~/Downloads/somepackage-1.2-3.src.rpm $MY_REPO/stx/downloads echo "repo:stx/downloads/somepackage-1.2-3.src.rpm" > centos/srpm_path
(Optional) Set up a git environment to create your patch. The SRPM will be extracted, then the source tarball will be extracted and patched.
# clean any prior edit environment that might exist # build-srpms --edit --clean parted # # Create a working edit environment # build-srpms --edit parted ... ===== 'parted' has been extracted to for editing. ===== ===== Metadata can be found at: /localdisk/loadbuild/<username>/test/std/srpm_work/parted/rpmbuild ===== Source code can be found at: /localdisk/loadbuild/<username>/test/std/srpm_work/parted/gits/parted.spec/parted-3.1 # # Create you patch # cd $MY_WORKSPACE/std/srpm_work/parted/gits/parted.spec/parted-3.1 edit # create a patch git add git commit -m 'foo bar' git format-patch -n HEAD^ 0001-foo-bar.patch # Copy it to the repo... probabbly best to drop the missleading 0001 prefix mv 0001-foo-bar.patch $MY_PKG_ROOT/centos/patches/foo-bar.patch # undo the commit, if patch failed testing and needs more work git reset --soft HEAD~ # # Now create a meta_patch to add your patch to the spec file # cd $MY_WORKSPACE/std/srpm_work/parted/rpmbuild # modify Release to include tis patch version, add our patch to the end of the patch list vi SPECS/parted.spec .... Release: 23.el7%{?_tis_dist}.%{tis_patch_ver} .... Patch34: 0034-tests-Use-wait_for_dev_to_-functions.patch # WRS Patch35: syscalls.patch Patch36: foo-bar.patch ... # if the %prep/%setup section does not use 'git am %{patches}' which automatically applies all patches, # then it should contain a list of %patch macros (one per patch) and you will have to append your patch to the end of the list. # %patch macros are basically just invocations of the 'patch' command to apply your patches. e.g. like this %patch35 -p1 %patch36 -p1 git add SPECS/parted.spec # Optionally edit and add files in SOURCES/ git commit -m 'meta foo bar' git format-patch -n HEAD^ 0001-meta-foo-bar.patch # Copy it to the repo... probabbly best to drop the missleading 0001 prefix mv 0001-meta-foo-bar.patch $MY_PKG_ROOT/centos/meta_patches/meta-foo-bar.patch # undo the commit, if patch failed testing and needs more work git reset --soft HEAD~ # # Finally add the meta patch to the patch order file... so that the patches vs the spec file apply in the correct order # echo meta-foo-bar.patch >> $MY_PKG_ROOT/centos/meta_patches/PATCH_ORDER
(Optional) Create a
build_srpm.data
file and add aCOPY_LIST
which identifies additional files to copy into SOURCES before finalizing the srpm.vi $MY_PKG_ROOT/centos/build_srpm.data COPY_LIST="files/resizepart.sh"
Note
The order is SRPM extracted first, then copy
centos/patches/*
into SOURCES, then apply meta patches, then copy anything named inCOPY_LIST
into SOURCES.COPY_LIST
items are not available for meta patching. Just edit them directly.Build the final
src.rpm
with your new changes inserted.build-srpms --clean parted build-srpms parted
Build the rpm.
build-rpms --clean parted build-rpms parted Verify contents of rpm: build-rpms --no-descendants parted cd $MY_WORKSPACE/rpmbuild mkdir TMP; cd TMP rpm2cpio parted-3.1-23.el7.tis.1.x86_64.rpm | cpio -ivmd
Test. If it fails, go back to step 4.
Commit.
cd $MY_PKG_ROOT git add meta_patches/PATCH_ORDER meta_patches/meta-foo-bar.patch patches/foo-bar.patch # add these as required git add centos/srpm_path git add centos/build_srpm.data git commit -F ... rebase/push...
Discard the working directory and its temporary gits created in step 4.
build-srpms --clean --edit parted
Up-version a CentOS package with appended patches¶
Suppose you have a patched srpm resource-agents-3.9.5-54.el7_2.8.src.rpm
and
you want to migrate to a newer srpm, for example,
resource-agents-3.9.5-54.el7_2.8.src.rpm
.
First question: How do I know if there is a newer version available? If the local CentOS mirror has been updated, you can scan it for new srpms that have local WRS patches using:
find_patched_srpms_needing_upgrade
/localdisk/designer/<username>/test/cgcs-root/stx/recipes-cgl/cluster-resource-agents/centos/srpm_path: resource-agents-3.9.5-54.el7_2.8.src.rpm ==> resource-agents-3.9.5-54.el7_2.9.src.rpm
This tells you that there are patches for
resource-agents-3.9.5-54.el7_2.8.src.rpm
, but a newer version is available
(resource-agents-3.9.5-54.el7_2.9.src.rpm
). You should probably migrate the
patches to the new resource-agents-3.9.5-54.el7_2.9.src.rpm
. No output
means no migrations are required at this time.
Check out the old version with our patches.
build-srpms resource-agents --edit --clean build-srpms resource-agents --edit
Point the
srpm_path
at the new source rpm.vi $MY_REPO/cgcs-root/stx/recipes-cgl/cluster-resource-agents/centos/srpm_path mirror:CentOS/vault.centos.org/7.2.1511/updates/Source/SPackages/resource-agents-3.9.5-54.el7_2.9.src.rpm
Check out the new version without our patches.
build-srpms resource-agents --edit --no-meta-patch ... ===== 'resource-agents' has been extracted for editing. ===== ===== Metedata can be found at: /localdisk/loadbuild/<username>/test/std/srpm_work/resource-agents/rpmbuild ===== Source code can be found at: /localdisk/loadbuild/<username>/teststd//srpm_work/resource-agents/gits/resource-agents.spec/ClusterLabs-resource-agents-5434e96
You now have two directories, each a git tree with two branches, one based on the old srpm, one on the new srpm.
cd $MY_WORKSPACE/std/srpm_work/resource-agents/rpmbuild git branch --all master resource-agents-3.9.5-54.el7_2.8 * resource-agents-3.9.5-54.el7_2.9 cd $MY_WORKSPACE/std/srpm_work/resource-agents/gits/resource-agents.spec/ClusterLabs-resource-agents-5434e96 git branch --all master resource-agents-3.9.5-54.el7_2.8 * resource-agents-3.9.5-54.el7_2.9
Show the commit histories of the two branches to identify the work to do.
cd $MY_WORKSPACE/std/srpm_work/resource-agents/gits/resource-agents.spec/ClusterLabs-resource-agents-5434e96 git log resource-agents-3.9.5-54.el7_2.8 --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %C(bold blue)<%an>%Creset' --abbrev-commit * be18338 - (HEAD, resource-agents-3.9.5-54.el7_2.8) WRS: Patch99: exportfs_accept_ipv6.patch (2016-04-29 01:11:03 -0400) * 70308b7 - WRS: Patch98: pgsql.patch (2016-04-29 01:11:02 -0400) * 802a93a - WRS: Patch97: lvm_vg_activation.patch (2016-04-29 01:11:00 -0400) * 96acac3 - WRS: Patch96: umount-in-namespace.patch (2016-04-29 01:11:00 -0400) * 24b1bb1 - WRS: Patch95: copyright.patch (2016-04-29 01:10:59 -0400) * cb5c3a9 - WRS: Patch94: ipaddr2_check_if_state.patch (2016-04-29 01:10:58 -0400) * 600cda6 - WRS: Patch93: new_ocf_return_codes.patch (2016-04-29 01:10:57 -0400) * 5f40f0b - WRS: Patch92: filesystem_rmon.patch (2016-04-29 01:10:56 -0400) * facf036 - (tag: pre_wrs_resource-agents-3.9.5-54.el7_2.8) Patch91: bz1316633-backup-and-restore-rabbitmq-users-during-resource-re.patch (2016-04-29 01:10:32 -0400) * 48cbdac - Patch90: bz1311180-rabbitmq-cluster-forget-stopped-cluster-nodes.patch (2016-04-29 01:10:31 -0400) git log resource-agents-3.9.5-54.el7_2.9 --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %C(bold blue)<%an>%Creset' --abbrev-commit * 746eb3d - (HEAD, tag: pre_wrs_resource-agents-3.9.5-54.el7_2.9, resource-agents-3.9.5-54.el7_2.9) Patch94: bz1318744-galera-no-grastate.patch (2016-04-29 01:12:16 -0400) * f6fc3f0 - Patch93: bz1318744-galera-heuristic-recovered.patch (2016-04-29 01:12:15 -0400) * dc76b27 - Patch92: bz1318744-galera-crash-recovery.patch (2016-04-29 01:12:14 -0400) * facf036 - (tag: pre_wrs_resource-agents-3.9.5-54.el7_2.8) Patch91: bz1316633-backup-and-restore-rabbitmq-users-during-resource-re.patch (2016-04-29 01:10:32 -0400) * 48cbdac - Patch90: bz1311180-rabbitmq-cluster-forget-stopped-cluster-nodes.patch (2016-04-29 01:10:31 -0400)
The image below shows the color-coded results of the comparison.
The patches in green with
WRS:
in the patch name must be ported.The commit in orange noted with
tag:
was the last common commit.The patches in blue are new patches from upstream that may interfere with our patches.
Package providing an init script¶
The packages/recipes that provide an init script (found under /etc/init.d/
and corresponding /etc/rc.d/
) must be converted to systemd services.
Within STX there are two kinds of services:
Services that must be started on boot.
Services that are monitored by pmond (and automatically restarted in case of failure). In this case, we don’t want systemd to restart a process in case of failure.
The general idea about converting those services is to still keep the script
file installed under /etc/init.d/
in the short term and wrap it in a
systemd service. This is needed so that service dependencies can be evaluated by
systemd and start them in the right sequence on boot. Re-using the same init
script at the moment is more convenient for supporting the same code base for
wrlinux and CentOS packaging (no need to support multiple version of the same
script).
Given an example init script /etc/init.d/helloworld
, create a corresponding
helloworld.service
file:
[Unit]
Description=Helloworld service
# Configures requirement dependencies on other services. If this service gets activated, the
# services listed here will be activated as well. If one of the other services gets deactivated or
# its activation fails, this service will be deactivated.
Requires=
# A weaker version of Requires. Services listed in this option will be started if the configuring
# unit is. However, if the listed services fail to start, this has no impact on the current service.
Wants=
# The next two directives are important for specifying the services dependancies. This will indicate
# to systemd in which order services should be started. This does not imply a dependency
# relationship ('Requires' or 'Wants') and must be used in conjunction with one of the above
# directives if this is desired.
# The services listed in this directive will be started before starting the current service.
After=syslog.target network.target
# The services listed in this directive will not be started until the current service is marked as
# started if they are activated at the same time.
Before=
[Service]
# Usual types are 'oneshot', 'simple' and 'forking'.
# oneshot: The process is not a daemon running in the background. Systemd will wait that the process
# exit before continuing.
# simple: Systemd will fork the process.
# forking: The process will call fork(). It is recommended to use 'PIDfile' in this case so that
# systemd can identify the process.
Type=oneshot
# Commands with their arguments that are executed when this service is started
ExecStart=/etc/init.d/helloworld start
# Additional commands that are executed before command in ExecStart
ExecStartPre=
# Additional commands that are executed after command in ExecStart
ExecStartPost=
# Commands to execute to stop the service
ExecStop=/etc/init.d/helloworld stop
# Additional commands that are executed after the service is stopped
ExecStopPost=
# Commands to execute to trigger a configuration reload in the service
ExecReload=
# Only useful when 'Type' is 'forking'. PID file is important if the process is monitored by pmond.
PIDFile=/var/run/helloworld.pid
# Configures whether the service shall be restarted when the service process exits.
# Should be 'always' is systemd should monitor the process.
# Should be 'no' (default) if process is monitored by pmond.
Restart=
[Install]
# This enables to service to be started on boot. It is equivalent of init runlevel (see below for equivalence). This
# means that the current service will be started when the listed unit is started. All the other services that are
# also dependent on this target will also get started, the order will depends on the 'After' and 'Before' options
# specified above.
WantedBy=multi-user.target
Once the systemd service file is defined, it needs to be packaged in the rpm.
The helloworld.service
file must be installed in the /etc/systemd/system/
directory (recommended for STX services) by the rpm spec. It’s important to set
file permissions to 664. The systemd services must be enabled on install
and disabled on uninstalled. This is achieved by using the systemd command
systemctl enable (and disable). However, it is recommended to use the macros
already defined by rpm. For example:
%install
install -d -m 755 %{buildroot}/etc/systemd/system/
install -p -D -m 664 helloworld.service %{buildroot}/etc/systemd/system/helloworld.service
# Enable the service and start it.
%post
%systemd_post helloworld.service
# Disable the service and stop it.
%preun
%systemd_preun helloworld.service
# Try to restart the service. Usefull on upgrades.
%postun
%systemd_postun_with_restart helloworld.service
Systemd searches these directories for services (in order of precedence, the first item has higher precedence than the one following):
/etc/systemd/system/
Recommended and reserved location for system administrator customized services/run/systemd/system/
Mainly used by CentOS. Don’t pollute this directory./usr/lib/systemd/system/
CentOS is distributed with a number of predefined targets that are more or less similar to the standard set of runlevels. Use the following comparison table for specifying your WantedBy target.
runlevel0.target -> poweroff.target
runlevel1.target -> rescue.target
runlevel2.target -> multi-user.target
runlevel3.target -> multi-user.target
runlevel4.target -> multi-user.target
runlevel5.target -> graphical.target
runlevel6.target -> reboot.target
Convert to systemd service (without intermediate init script):
The exact PID file name that is used by pmond can be found by looking on an installed system under
/etc/pmon.d/
. Look forpidfile=
in the corresponding pmond configuration file for the service.Some of the init scripts are using start-stop-daemon to manage processes. The start-stop-package has been ported to CentOS (it is not supported by CentOS). Make sure the init script is providing the right
--pidfile
argument that matches the pmond service configuration. A process that is started by start-stop-daemon with the--daemon
or-d
options indicates that the processes will be forked, in which case the systemd service Type should be forking. Else if the script or process doesn’t fork, the Type should be simple which will tell systemd to fork it.Hints for defining service startup order (Before and After):
Systemd determines when a service should start using the
After=
andBefore=
values found in the[Unit]
section of theservice
file. These values take a space-separated list of other services or targets, where a target is effectively a collection of services. For example, the log management service has the following values:[Unit] Description=StarlingX Log Management After=network.target syslog-ng.service iscsid.service sw-patch.service Before=config.service pmon.service
In this example, the log management service can’t start until software is patched, and a network, a disk and the syslog-ng service are all up and running.
The init script might contain some specific information about the order. Look for Required-Start and Required-Stop in it.
Troubleshooting (at runtime):
Enable a service:
systemctl enable
Disable a service:
systemctl disable
Start a service:
systemctl start
Stop a service:
systemctl stop
Get service status:
systemctl status
Get list of running units ordered by time to init:
systemd-analyze blame
Show systemd logging:
journalctl /usr/lib/systemd/systemd
Show logging of a specific service:
journalctl _SYSTEMD_UNIT=
After you’ve converted a package¶
Each repo has a centos_iso_image.inc
file, which contains the list of
packages to be included in the installation iso relevant to the repo. The
build-iso
step merges the individual centos_iso_image.inc
files to
generate the complete list.