View RSS Feed

mikem

Buildkit by Example

Rate this Entry
by on October 15th, 2007 at 06:19 PM (2794 Views)
So, you want to build a kit? Enter the buildkit tool, written to make it easier for you to package software for Kusu. Today we’ll explore how buildkit works.

We start by creating the ‘kit workspace’:

$ buildkit new kit=acmetools

OK, we’re building an ACME Tools kit, a fictitious client/server application with a monitoring add-on. Let’s have a look at what this command did:

$ cd acmetools/
acmetools $ ls -l
total 56
drwxrwxr-x 2 mike mike 4096 Oct 16 15:11 artifacts
-rw-rw-r-- 1 mike mike 1095 Oct 16 15:11 build.kit
drwxrwxr-x 2 mike mike 4096 Oct 16 15:11 docs
drwxrwxr-x 2 mike mike 4096 Oct 16 15:11 packages
drwxrwxr-x 5 mike mike 4096 Oct 16 15:11 plugins
drwxrwxr-x 2 mike mike 4096 Oct 16 15:11 sources
drwxrwxr-x 2 mike mike 4096 Oct 16 15:11 tmp

A directory called acmetools was created in our working directory. In it we see a file called build.kit and six other directories. The artifacts directory will contain the packages and other objects generated by buildkit when it builds the kit. Any documents to be installed with the main kit package go into the docs directory. If you wrote plug-ins for Kusu apps, place them in the appropriate folder in the plugins directory. The sources directory contains any source or packages to be included. Finally, the tmp directory is used for buildkit’s temporary needs.

Let’s take a look at the contents of the build.kit file that buildkit generated:

Code:
1  # build.kit template
2
3  # Define your packages here by using a correct packageprofile class.
4  # Available types are SourcePackage(), RPMPackage(), SRPMPackage(),
5  # DistroPackage(), BinaryPackage()
6 
7  #pkg1 = SourcePackage()
8  #pkg1.name = 'foo'
9  #pkg1.version = '1.0'
10 #pkg1.release = '0'
11 #pkg1.installroot = '/opt/foo'
12 #pkg1.filename = 'foo-1.0.tar.gz'
13 
14 # define a default component
15 comp = Fedora6Component()
16 comp.name = 'acmetools'
17 comp.description = 'acmetools component for Fedora Core 6.'
18 
19 # Add any packages defined earlier by using the comp.addDep method
20 #comp.addDep(pkg1)
21 
22 
23 # define a default kit
24 # be sure to change arch to fit your needs (x86, x86_64, noarch)
25 k = DefaultKit()
26 k.name = 'acmetools'
27 k.description = 'acmetools kit.'
28 k.arch = 'x86'
29 
30 # Adding the component defined earlier
31 k.addComponent(comp)
32 
33 
34 # Add post install script. You can modify this shell script or add new ones in the
35 # sources directory
36 k.addScript('00-post-script.sh',mode='post')
37 
38 # Add post uninstall script. You can modify this shell script or add new ones in the
39 # sources directory
40 k.addScript('00-postun-script.sh',mode='postun')
This build.kit file currently defines the kit package and one component. On line 15 we define comp to be a Fedora6Component, corresponding to the OS I’m running at the moment. We name the component 'acmetools' and describe it to be 'acmetools component for Fedora Core 6.'.

On line 25 we define the kit package, k. We also name it 'acmetools', describe it as 'acmetools kit.', and state its arch is 'x86'.

We add the component comp to kit package k on line 31. This means that comp belongs to this kit and the relationship will be recorded in the Kusu database. On lines 36 and 40 we add scripts to the kit package; the scripts are found in the sources directory. These shell scripts will be executed at the various stages of package installation and removal.

Direct your attention at the commented out package definition on lines 7-12. Here we define pkg1, a SourcePackage. We give it a name, version, release, define an installroot and filename. As you’ve guessed, this is a package we will be compiling from source to include in our kit. The file foo-1.0.tar.gz needs to be placed in the sources directory buildkit created, and /opt/foo will be passed as the --prefix parameter during the configure step.

Also commented out, on line 20, we are adding a dependency to comp, our component. When comp is installed, it will pull in pkg1 as a dependency.

So now we understand how the build.kit file describes our kit, but it’s probably not exactly what we want. What more needs to be done before we can ship our kit?

First let’s place our sources where buildkit can find them:

acmetools $ ls -l sources/
total 32
total 2008
-rw-rw-r-- 1 mike mike 418 Oct 16 15:11 00-post-script.sh
-rw-rw-r-- 1 mike mike 378 Oct 16 15:11 00-postun-script.sh
-rw-r--r-- 1 mike mike 35991 Oct 16 16:51 acmetools-master-1.2-1.i386.rpm
-rw-r--r-- 1 mike mike 39488 Oct 16 16:51 acmetools-master-1.2-1.x86_64.rpm
-rw-rw-r-- 1 mike mike 18490 Oct 16 16:51 acmetools-monitor-1.01.tar.gz
-rw-rw-r-- 1 mike mike 1917631 Oct 16 16:51 acmetools-node-1.2-1.src.rpm

For the sake of this example, let’s assume the acmetools-master package is installed on the installer node, the acmetools-node package is installed on all compute nodes, while the acmetools-monitor package is an applciation for monitoring ACME Tools nodes. Take note of the types of these sources; we have RPMs, a source RPM and a tarball.

Next we will define our packages in the build.kit file:

acmetools_monitor_pkg = SourcePackage()
acmetools_monitor_pkg.name = 'acmetools-monitor'
acmetools_monitor_pkg.version = '1.01'
acmetools_monitor_pkg.release = '1'
acmetools_monitor_pkg.installroot = '/opt/acmetools/monitor'
acmetools_monitor_pkg.filename = 'acmetools-monitor-1.01.tar.gz'

The acmetools-monitor package comes as a tarball and is thus defined a SourcePackage. This particular tarball (sources/acmetools-monitor-1.01.tar.gz), is easy to install by running configure, make and make install. The above definition tells buildkit to generate an RPM with release 1 which installs acmetools-monitor to /opt/acmetools/monitor.

acmetools_node_pkg = SRPMPackage()
acmetools_node_pkg.name = 'acmetools-node'
acmetools_node_pkg.version = '1.2'
acmetools_node_pkg.release = '1'
acmetools_node_pkg.filename = 'acmetools-node-1.2-1.src.rpm'

The acmetools-node package differs slightly, but not much. It’s a source RPM, so acmetools_node_pkg is an instance of SRPMPackage. A package will be generated according to the spec file contained inside sources/acmetools-node-1.2-1.src.rpm.

acmetools_master_pkg = RPMPackage()
acmetools_master_pkg.name = 'acmetools-master'
acmetools_master_pkg.version = '1.2'
acmetools_master_pkg.release = '1'
if getArch() == 'x86':
acmetools_master_pkg.filename = 'acmetools-master-1.2-1.i386.rpm'
if getArch() == 'x86_64':
acmetools_master_pkg.filename = 'acmetools-master-1.2-1.x86_64.rpm'

The acmetools-master looks a little more complicated. It’s a precompiled RPM, so acmetools_master_pkg is an instance of RPMPackage. Note how we define the filename depending on the current arch buildkit is running on.

There are other package types (DistroPackage, BinaryPackage) which I won’t touch on today.
Great, our packages are defined. Now they need to be added to components — which we first need to define. We may decide on something like this:

master_comp = DefaultComponent()
master_comp.name = 'acmetools-master'
master_comp.description = 'ACME Tools component for installer node.'
master_comp.ngtypes = ['installer']

OK, there is master_comp which is a DefaultComponent. This is a change from the default Fedora6Component, which would set additional descriptive properties on master_comp. We want to reuse this component on other distributions, though. Notice the ngtypes property is assigned a Python list. The list contains the nodegroup types that we want to associate this component with. In this case, the component will be installed on nodes in installer-type nodegroups.

slave_comp = DefaultComponent()
slave_comp.name = 'acmetools-slave'
slave_comp.description = 'ACME Tools component for compute node.'
slave_comp.ngtypes = ['compute']

master_comp.addDep(acmetools_master_pkg)
slave_comp.addDep(acmetools_node_pkg)
slave_comp.addDep(acmetools_monitor_pkg[color=black])
/COLOR]

The component for compute nodes is defined similarly. We also add our packages to the two components as dependencies: acmetools_master_pkg is required by master_comp, installed on all installer-type nodes and acmetools_node_pkg and acmetools_monitor_pkg are required by slave_comp, and will be installed on all compute-type nodes.

Finally, our kit package definition:

k = DefaultKit()
k.name = 'acmetools'
k.description = 'ACME Tools kit.'
k.arch = getArch()
k.addComponent(master_comp)
k.addComponent(slave_comp)

We add the two components to the kit, and we’re done. Our build.kit file is now complete. Notice the use of getArch() to define which arch this kit should be generated for. Also, we don’t add have any scripts to add to the kit, so we can safely remove the two shell script templates buildkit generated (sources/00-post-script.sh and sources/00-postun-script.sh).

Let’s make our ISO:
acmetools $ cd ..
$ buildkit make kit=acmetools

What happened?

$ ls -l acmetools/
total 2756
drwxrwxr-x 3 mike mike 4096 Oct 16 18:31 artifacts
-rw-rw-r-- 1 mike mike 1289 Oct 16 18:24 build.kit
drwxrwxr-x 2 mike mike 4096 Oct 16 15:11 docs
-rw-rw-r-- 1 mike mike 1157 Oct 16 18:31 kitinfo
-rw-rw-r-- 1 mike mike 2748416 Oct 16 18:31 kit-acmetools-0.1-0.i386.iso
drwxrwxr-x 2 mike mike 4096 Oct 16 18:32 packages
drwxrwxr-x 5 mike mike 4096 Oct 16 15:11 plugins
drwxrwxr-x 2 mike mike 4096 Oct 16 18:29 sources
drwxrwxr-x 5 mike mike 4096 Oct 16 18:31 tmp

We see two new items listed, the kitinfo file (described previously) and kit-acmetools-0.1-0.i386.iso, our ISO, ready for kitops to work with. The contents of the packages directory, the packages we wanted, are what’s inside:

$ ls acmetools/packages/
component-acmetools-master-0.1-0.noarch.rpm acmetools-monitor-1.01-1.i386.rpm
component-acmetools-slave-0.1-0.noarch.rpm acmetools-node-1.2-1.i386.rpm
kit-acmetools-0.1-0.i386.rpm acmetools-node-debuginfo-1.2-1.i386.rpm
acmetools-master-1.2-1.i386.rpm

Note the component packages are prefixed with ‘component-’, while the kit package has ‘kit-’ prepended.
To summarize, the steps for creating a kit are:
  1. create the kit workspace: buildkit new kit=<name_of_kit>
  2. place your sources in the sources directory; also provide plugins or documentation, if you have any
  3. edit the build.kit file to define the packages and components in your kit, remembering to assign packages as component dependencies and adding the components to the kit
  4. make the kit ISO: buildkit make kit=<kit_workspace_directory>

Running buildkit without arguments prints out usage information.

Have fun authoring kits!

Updated April 13th, 2008 at 04:45 AM by mikem

Categories
Kusu/OCS

Comments

  1. samick -
    samick's Avatar
    Thanks, mikem.

    I had trubble to build my kits in kusu-1.0.centos-5.i386. The command buildkit make kit=mykit had result:

    File "/opt/kusu/lib/python/kusu/util/tools.py", line 163, in mkdtemp
    return tempfile.mkdtemp('', 'kusu-', **kwargs)
    TypeError: mkdtemp() got multiple values for keyword argument 'prefix'

    I changed line
    return tempfile.mkdtemp('', 'kusu-', **kwargs)
    to
    return tempfile.mkdtemp(**kwargs)
    in the file /opt/kusu/lib/python/kusu/util/tools.py. This fixed the issue.
    permalink

Trackbacks

Total Trackbacks 0
Trackback URL: