Using Mock to test package builds

This page is a collection of bits people have found useful when working with mock.

What is Mock?
Mock takes a srpm and builds it in a chroot. This ensures that your BuildRequires lines are correct, that there are no missing dependencies, and that it builds cleanly. The Mock project page has more information on Mock.

How do I set up Mock?
First, install the mock package, which is available from Fedora Package Collection.

Default configuration
When using mock, you can use the "-r" option to select a particular test configuration. If there's one configuration that system users will normally use, you can set that as the default:
 * 1) cd /etc/mock
 * 2) ln -s --force SOMECONFIG.cfg default.cfg

(An example of SOMECONFIG.cfg is "fedora-14-x86_64.cfg"; see the /etc/mock directory for the existing mock configurations.)

Setting up local mirror
If you want to set up a local mirror, refer MockSetupUsingLocalMirror

Proxy Configurations
If you're behind a proxy, add the proxy info to the desired cfg file in /etc/mock in the same format that you would add it to your yum.conf. See man yum.conf for details on how to do it.

How do I use Mock?
Mock accepts a number of commands. Mock accepts commands in old-style format (e.g., "rebuild" or "init" without a leading "--"), but these are deprecated; use commands with a leading "--" instead.

Using Mock outside your git sandbox
Add your user name to the mock group

Create your srpm using 'rpmbuild -bs'. Then change to the directory where your srpm was created.

Now you can start mock with

where is the name of a configuration from  (do not include the   extension). Passing -r is not necessary if you have set a default config file via a symlink as shown above. --rebuild is the default option. So the following would work equally well

The --verbose option is useful if you want more output to be shown for debugging purposes.

If using mock version older than 0.8.8 or on a system with python 2.4, and building i386 packages on x86_64, prepend  to the mock command line:

Newer versions of mock no longer need the setarch command, although it does not hurt anything if it is there.

Using Mock inside your git sandbox
You only need to type 'make mockbuild' to start a mock build. The used architecture depends on the directory where you start the mock build.

Building packages that depend on packages not in a repository
If you're building some package P that depends on another package Q, and Q is not in a repository, you can still use mock. Here's one way to do that.

First, initialize the mock repository: mock -r MOCK_CONFIG --init

(An example of MOCK_CONFIG is "fedora-14-x86_64"; see the /etc/mock directory for the existing mock configurations.)

Install the packages you need to build the program (named in BuildRequires) from the yum repositories and/or local RPMs. In practice, you may need to do a number of these (for the different package dependencies); you can list multiple packages on the same line: mock -r MOCK_CONFIG --install PACKAGE_NAME_OR_PATH_TO_RPM

Current versions of mock should permit you to now build from the source RPM. If that does not work then the "--copyin" method below should be used. The --no-clean option is necessary since by default the chroot is cleaned prior to building. mock -r MOCK_CONFIG --no-clean /PATH/TO/SRPM

Copy in the source RPM into /tmp (we'll copy in and do a build inside the shell, to work around the checks that detect that the packages aren't in the repository): mock -r MOCK_CONFIG --copyin /PATH/TO/SRPM /tmp

Shell into the mock environment and perform the build: mock -r MOCK_CONFIG --shell cd rpmbuild --rebuild /tmp/SRPM_NAME

Caching in mock 0.8.x and later
Mock 0.8.x introduces three different types of caches: 1) root cache, 2) yum cache, and 3) ccache. These caches greatly speed up mock.

Look in /etc/mock/defaults.cfg for documentation on configuring each of these caches. You can configure the directory where they are stored, the maximum age of the caches, and (for ccache only) the max disk usage for the cache.

Root cache
Starting with mock 0.5, mock can automatically cache the standard buildroot for each environment in a local tar file (/var/cache/mock/$CONFIG/root_cache/*). It then unpacks this tar file to populate the buildroot, rather than downloading the buildroot RPMs fresh each time. After unpacking the buildroot from the root cache, mock does a  to make sure that the buildroot is up-to-date prior to installing additional BuildRequires for a package build.

The root cache is enabled by default in mock 0.8.x and later. To disable, see the documentation in /etc/mock/defaults.cfg. The root cache can be disabled globally or per-chroot. The root caches are automatically deleted and recreated every 15 days to prevent them from being too stale.

Keep in mind that the root cache can affect reproducibility of your build, especially in environments where the set of base RPMs is updated often (eg. rawhide). Disable the root cache in environments where build reproducibility is of utmost importance.

yum cache
By default, yum stores downloaded RPMs in a directory under /var/cache/yum. The yum cache feature bind mounts the chroot /var/cache/yum to a common directory outside the chroot environment (such as /var/cache/mock/$CONFIG/yum_cache/) where it can be saved and re-used by subsequent builds. This ensures that yum does not need to download each RPM fresh over the network for every build. This feature is enabled by default.

ccache
The ccache tool is a utility that wraps calls to compilers such as 'gcc' and caches the output. When called to compile the same program a second time (with the same cmdline args, gcc-version, and header files), ccache will instead pull the cached version rather than running the compiler afresh.

Using Squid to Speed Up Mock package downloads
The cached buildroots trick above is much faster than using squid alone, but you can also use squid in addition to the cached buildroots, particularly if you are at the slow end of an Internet connection.

The root cache will contain the standard buildroot packages, but as it gets older, the  after unpacking it may have to update several packages. In addition, some packages aren't in the standard buildroot, but are often needed (e.g. pkgconfig). These can be faster served from a squid cache than from downloading them from the Internet for each package build.

Install the squid package which is available from Fedora Package Collection.

Some items worth changing in :
 * Maximum Object Size. Normally, this is 4MB.  However, some of the base packages like glibc can be larger than 16MB, and if you're building say Eclipse plugins, that's 60MB.  So make it large.


 * Cache Replacement Policy. Normally, lru is fine.  But in our case, we want to keep the largest objects around longer, and just download the smaller objects if we can.


 * Cache Size. Normal size is 100MB.  This isn't going to cut it.  This needs to be at least 1GB, more if you regularly build for multiple Fedora releases and multiple architectures.

Then start squid, and configure it to start on startup.

To make the build user automatically use the squid cache, type:

If you only want to use squid for particular mock configurations (perhaps you have local mirrors of some distributions and don't need squid for those), you can, instead of setting the  environment variable, set up the proxy configuration in the   part of each mock configuration file:

config_opts['yum.conf'] = """ [main] ... proxy=http://localhost:3128/

... """

Edit /etc/mock/*.cfg to not use mirror lists
'''Don't use the mirrorservice.org mirror; they prevent downstream caching via the HTTP header "Cache-Control: no-store". '''

If you're using squid, you don't want mock+squid to use a random mirror for downloading packages. Change the config files in /etc/mock/*.cfg to use a single fast-for-you mirror in a  entry, and don't use  s.

Using tmpfs to avoid disk access
It's not clear that tmpfs is a huge win anymore, now that autocache works and is a standard feature.

When having enough RAM (1.5-2 GB), using a tmpfs can speedup the 'prep' phase significantly. With 1.5GB RAM on a Celeron 2.8 GHz, populating the buildroot will take 2-5s (seconds) on subsequent builds.

You can either mount /var/lib/mock as a tmpfs, or you can mount each of the build directories under /var/lib/mock as separate tmpfs file systems. The latter lets you use the autocache above and keeps the autocache files on disk, rather than in the tmpfs. If you erase and recreate the autocaches often, keeping them in tmpfs makes sense. If you don't recreate them often, then you should use per-build-directory tmpfs mounts instead.

Using mock under SELinux
Using SELinux in conjuction with chroot-ed environments such as mock presents a number of problems, such as needing to replicate all default file contexts with the chroot directory prefix, which is an administrative nightmare. The approach used by mock is very simple, though it only works with the  policy: preload a dummy  that makes all child processes think that SELinux is disabled. With mock itself running as an unconfined process, this generally works well.

Problems with SELinux memory protection
However, from FC5 onwards, the SELinux  domain is no longer fully unconfined by SELinux; memory protection is implemented to protect most user processes against a variety of possible exploits. This presents at least two sets of problems when using mock in FC5: Whilst it is possible to turn off these checks using SELinux booleans, this is not a desirable thing to do for all processes. Another solution would be to ensure that all files were labelled correctly in the chroot and that SELinux domain transitions ocurred when needed. However, this is not possible because processes running under mock are told by the dummy  that SELinux is disabled.
 * 1) When  building packages for legacy distributions, the build process can involve loading old shared libraries that do not have separate sections for, say, executable code and writable data. This leads to   denials when a process running in the   domain tries to load such a library, unless the library is labelled.
 * 2) When building packages using mono (the same might apply to java), the   process would normally run in its own less-constrained domain ; when running under mock,   runs in the   domain, which can result in   and   denials.

SELinux policy module for mock
The following solution to these issues creates an SELinux policy for mock that has two aspects:
 * 1) It runs   in its own domain  that is as unconstrained as any process that needs to run under it needs to be, which so far means that it allows   and , just like the   domain does.
 * 2) It labels all files installed under   (where   sets up its chroot environments) with the special context type , for which   is allowed for processes in the   domain.

This solution relaxes SELinux protection sufficiently for mock to be able to work, without compromising the protection afforded to the normal unconfined domain.

To install the policy module: Compliling targeted mock module /usr/bin/checkmodule: loading policy configuration from tmp/mock.tmp /usr/bin/checkmodule: policy configuration loaded /usr/bin/checkmodule: writing binary representation (version 5) to tmp/mock.mod Creating targeted mock.pp policy package rm tmp/mock.mod.fc tmp/mock.mod
 * Create a directory to store local policy files, such as, and change to that directory
 * Download [[Image:PackageMaintainers_MockTricks_mock.if]], [[Image:PackageMaintainers_MockTricks_mock.fc]], and [[Image:PackageMaintainers_MockTricks_mock.te]] to this directory
 * Build and install the policy module as follows:
 * 1) make -f /usr/share/selinux/devel/Makefile

If the policy module is loaded before the  package is installed,   will be labelled as   and   will be labelled as   at installation time. Otherwise, it's necessary to use  to fix the file contexts:
 * 1) restorecon -R /var/lib/mock /usr/bin/mock

Using mock as a chroot sandbox tool
Mock can be used to create chroots for testing things, not just building packages. Here is a quick howto:

mock -r  --init mock -r  --install mock -r  --shell
 * Create a config file that points to the repo(s) of your choice, where your test packages are

Why use mock to shell, why not chroot directly? Using mock to "shell" will allow mock to create the mountpoints you'll probably need inside the chroot. If you want to manage your mounts manually, do so by all means.