This is the first of a series of blogs titled ‘Two worlds meet’ talking about how two technologies can be used together to solve a problem. Mostly one world will be linux or more specifically a virtualized linux setup using kernel virtual machine, with the other world being java.
In this blog I will be looking at automated creation of a yum repository using maven, nexus, and hudson. First however, some background is needed. Some time ago I bought a new server with more than sufficient resources to run multiple virtual machines. The aim there was to do some separation of concerns having virtual machines with different purposes and also be able to run conflicting software. Doing that introduces a whole new problem of maintaining the software on these virtual machines. Of course, I use a standard linux distribution such as opensuse but I still have some custom scripts that I need and want to have available on all VMs.
Using the standard linux tooling an abvious method is to just create my own Yum repository to publish my own RPMs in and then add that Yum repo as a channel in all of my VMs. Of course, the challenge is then to easily and automatically create such a YUM repository. Fortunately, since I am working quite a lot with Java and Maven (earning a living with it basically), there is a quite easy solution with a nice separation of concerns.
The ingredients of this solution are:
- maven for building the rpm using the maven rpm plugin
- the maven release plugin for tagging a released version of the RPM, stepping its version, and publishing it into a maven repository
- a maven repository such as nexus for publishing RPMs into
- hudson for detecting changes and automatically updating/building the Yum repository upon changes to the RPMs.
In addition, some basic infrastructure is needed such as:
- a version control system such as subversion
- apache for providing access to subversion and for serving the Yum repo to all VMs
- an application server such as glassfish for running hudson and nexus
This may seem like a lot of infrastructure, but before I started I already had most of this except for the nexus maven repository, so all in all the effort for this solution was quite limited.
The main new ingredient of the solution is the script to create the Yum repository from the nexus repository. This script exploits the fact that nexus stores its repositories in a standard maven directory structure (an approach using REST web services is also possible):
#!/bin/bash REPO=/usr/java/nexus/nexus/storage/rpms # Create the repo directory YUM=$HOME/yum rm -rf $YUM mkdir -p $YUM mkdir -p $YUM/noarch # Find the RPMs in the nexus repository and use hardlinks @ to preserve modification times and avoid the overhead of # copying for rpm in $( find $REPO -name '*.rpm' ) do echo "RPM $rpm" ln $rpm $YUM/noarch done # createrepo is a standard command available on opensuse # to create a Yum repository createrepo $YUM # sign it gpg -a --detach-sign $YUM/repodata/repomd.xml gpg -a --export F0ABC836 > $YUM/repodata/repomd.xml.key # sync the results to their final destination to make them # available rsync --delete -avz $YUM/ /data/www/http.wamblee.org_yum/public
Using this approach it is really easy to update an RPM and make it available on all my VMs. The procedure is basically as follows:
- edit the source of the RPMs and check in
- Now tag it and step the versions using:
- Deploy the just tagged version to the nexus repository:
- Some time later the Yum repository has been automatically updated by hudson based on the contents of the nexus repository
- On a specific VM simply use a standard update using
Note that this may require an explicit
to make sure that zypper sees the latest versions of all RPMs. Autorefresh will also work but might require some more time before zypper sees the latest versions.
Therefore, in the end a really simply procedure to quickly make RPMs available on all VMs and also make sure each version is properly tagged in subversion. The only issue is that hudson will always run on every SCM change, so not only when an RPM is released but I consider that a minor issue.
The YUM repo is here.
An example pom is below:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd "> <parent> <groupId>org.wamblee.server</groupId> <artifactId>root</artifactId> <version>1.0.1</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>rpm</packaging> <groupId>org.wamblee.server</groupId> <artifactId>kvmguest</artifactId> <version>1.0.3-SNAPSHOT</version> <name>kvmguest</name> <description>KVM guest support</description> <organization> <name>org.wamblee</name> </organization> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>rpm-maven-plugin</artifactId> <version>2.0.1</version> <extensions>true</extensions> <configuration> <changelogFile>CHANGELOG</changelogFile> <copyright>Apache License 2.0, 2010</copyright> <group>org.wamblee.server</group> <packager>Erik Brakkee</packager> <mappings> <mapping> <directory>/usr</directory> <filemode>755</filemode> <username>root</username> <groupname>root</groupname> <sources> <source> <location>files/usr</location> </source> </sources> </mapping> <mapping> <directory>/etc/kvmguest.d</directory> <filemode>755</filemode> <username>root</username> <groupname>root</groupname> <sources> <source> <location>files/etc/kvmguest.d</location> </source> </sources> </mapping> <mapping> <directory>/usr/share/doc/packages</directory> <filemode>444</filemode> <username>root</username> <groupname>root</groupname> <sources> <source> <location>files/usr/share/doc/packages</location> </source> </sources> </mapping> </mappings> <provides> <provide>kvmguest</provide> </provides> </configuration> </plugin> </plugins> </build> </project>