Skip to main content

Creating OpenSolaris Package : Primer

Posted by kohsuke on June 23, 2008 at 12:11 PM PDT

Introduction

I wanted to create a package for Hudson and contribute that to OpenSolaris. But there's not much information about how to go about creating packages on the OpenSolaris website. This is in stark contrast to projects like Ubuntu, where the packaging is treated as one of the main ways to contribute and the link is easy to find (that said, to be fair, for Hudson's debian packages, I choose to run my own repository for now, so I hadn't contacted them yet. So perhaps it's very difficult process.)

Now, fortunately, I'm a Sun employee, so I do have some contacts and colleagues who are more familiar with Solaris. So through that, I found out an internal website with a lot more information (note to OpenSolaris folks if they are reading this — why is it internal?), which in turn led me to the "SFW consolidation" project of Solaris (I believe SFW stands for "Solaris Freeware Workspace" or something.)

But this turns out to be a nightmare. The very first thing a new package contributer is supposed to do is to check out the SFW workspace, but alas, you can't even do this unless you have TeamWare, which OpenSolaris doesn't have. That's right, you can't create OpenSolaris packages on OpenSolaris out of the box! Even if you manage to check out the workspace, you'll then have to deal with makefiles and 1000s of lines of shell scripts to create SVR4 packages (for the uninitiated, SVR4 packages are the traditional Solaris package format, and the new one in OpenSolaris is called IPS.)

I subsequently learned why they do this rather round about way of creating IPS packages by going through SVR4, but suffice to say that this makes it that much harder to contribute to the packaging effort. I've wasted a better part of a day going through all those scripts, trying to figure out how it works, to no avail. People like Ludo and Jyri in our organization are trying to make this better, but it was still too hard for me. You can also see a post from James Gosling in a related topic, where he complained about the difficulty in making contributions.

But the good news is, there's a better way to do it. If you directly create IPS packages and bypass SVR4 entirely, then it's a much better experience. So the rest of my blog is about how you can leverage all my research and improvements to existing tools, and get up and running with your own OpenSolaris packages quickly, without pulling out your hair.

IPS 101

To introduce you to the art of package making, let me start with a quick intro of IPS.

Many of you must be familiar with a concept of a "repository." In Java context perhaps you know about a Maven repository. Unix users might have heard about Debian package repository, RPM repository, and so on. IPS appears to be conceptually similar to all those well-known repositories, but at the same time it's different in one important way. Namely, there's no package file.

See, when you think of creating a package, you normally think about creating one archive file that contains the stuff. For example, with a Maven repository, you create a jar. With debian repository you create a ".deb" file. Once you have those packages, you put them together in a certain known directory format, generate a bit of metadata by probably running a tool or two, and put them all under Apache, and you are now running a repository.

But it is not so in IPS. With IPS, you first have to have a repository manager called pkg.depotd running. This repository manager does use a file system to store packages, but the storage format is considered its implementation detail and not advertised. And instead of creating a package file, you submit a package by making a series of HTTP requests to this server (which forms a transaction as a whole.) In a way, this is more like the model of version control system --- think Subversion for example. It's defined more in terms of the wire protocol (WebDAV when over HTTP), instead of the storage format. I mean, does anyone know how Subversion revisions are stored on the server?

Personally, I'm not so sure if this is the right approach. For example, my hosting provider for kohsuke.org doesn't have Python for my plan, so I can't run my package repository on my own server. Also, moving packages between repositories, and doing package mirroring, etc., becomes much harder. Or you need to run a repository manager just to test one package that you created. But I guess it's a conscious decision by them, and they are the experts, not me.

In any case, that's about all you need to know about IPS for now, so let's move on.

Creating a package

As I wrote above, creating a package in IPS really means sending a series of HTTP requests to this repository manager. The most well-documented interface for this is pkgsend, and this is actually pretty straight-forward. The following example shows how you can create the "mycmd" package that contains just one file:

// go to one terminal and run a repository manager on port 10000
$ pkg.depotd -p 10000 -d ./my-test-repository
// go to another terminal now
$ eval `pkgsend open mycmd@1.0-1`
$ pkgsend add file ./mycmd.sh path=/usr/bin/mycmd.sh
$ pkgsend close

You add more stuff by calling "pkgsend add" repeatedly, and you can add files, users, directories, symlinks, and you name it. See this document for more details.

While this does clearly convey how it works, it's pretty horrible way of creating a package because it's too low level (I mean, just imagine your build script or makefile filled with line after line of pkgsend invocation!) And this is where our GlassFish Update Center team does a better job. They've developed a script which directly talks to Python API of IPS (the entire IPS is written in Python), so that you can create a package more productively. I've extended their original work a bit to make it even easier to use (I'm working with them to contribute back those changes.) See this document for more about the script, and you can see an example of what you'd be writing in here (this uses my extension) and here (this doesn't.)

I packaged this tool and published it in Hudson's IPS repository. So if you are using OpenSolaris, you can install my tools as follows:

$ su
# pkg set-authority -O http://hudson.gotdns.com/ips/ hudson
# pkg authority
AUTHORITY                           URL
hudson                              http://hudson.gotdns.com/ips/
opensolaris.org
(preferred)         http://pkg.opensolaris.org:80/
#
pkg refresh
# pkg install glassfish-makepkgs
DOWNLOAD                                    PKGS       FILES     XFER (MB)
Completed                                    1/1       66/66     0.64/0.64

PHASE                                        ACTIONS
Install Phase                                  83/83

This creates /usr/bin/makepkgs (symlinked to makepkgs.py), along with a few other tools. With this tool, you now only need to write your small package definition like the ones I linked above, then run it like:

$ makepkgs -d ./build/repo ./proto.py

... and this will deposit a new package into ./build/repo. The tool starts the repository manager temporarily in the same process, so there's no need to run the repository manager separately.

Moving packages around

Most likely, the machine where you'll build a package is different from a machine that hosts the publicly visisble IPS repository. So you'll need some means to transfer packages from one machine to another. For this I wrote the "tarpkgs" tool in the glassfish-makepkgs tool suite. It extracts packages from your repository and bundles them up to a .tgz format for easier transportation.

$ tarpkgs ./build/repo my-package > my-package.tgz

You can then extract this into any other repository. So perhaps you might do something like this to push it to the public repository:

$ tarpkgs ./build/repo my-package | ssh www.kohsuke.org "cd path/to/public/repo; tar xvzf -"

If you wish, you can have more complex set up that involves intermediate repositories for testing. This is a generic command to move packages from one repository to another.

Publishing a package

As I wrote above, to publish a package, you need to be running pkg.depotd , and do so most likely in the read-only mode, or else anyone on the internet would be able to push a package to your repository.

$ /usr/lib/pkg.depotd --readonly -d path/to/repo

This is fairly straight-forward to do in OpenSolaris, which has pkg.depotd out of the box. But chances are, your internet-facing public server doesn't run OpenSolaris. So you'd have to grab all the relevant Python modules and install it on your own (someone in OpenSolaris, please create a tgz for IPS.)

In such an internet facing server, you'll likely be using apache as the front end. If so, see this posting for how to configure pkg.depotd under apache.

You'll be using the tarpkgs script above to deposit the packages you built elsewhere into this repository. When you deploy a new package, however, you have to kill pkg.depotd and restart it, so that it picks up a change. AFAICT from the code, there's no graceful reloading mechanism.

Testing a package

Ideally, you would like to install a package before you publish it, but because IPS always require a server, you first have to publish it before you can install it (very unnatural, if you ask me.) That said, to be fair, you can run pkg.depotd very easily anywhere at any port, so you can at least test it before you push it to a public repository that other people depend.

See the console output above under "creating a package", which shows the steps to hook up your repository and install a new package. If you re-publish your package, you can rerun "pkg refresh" and "pkg install ..." to update to a new package. It's also possible to install a package to a place other than "/" to avoid corrupting your running system.

When you test your own package, you should definitely use ZFS snapshot so that you can get back to the original state before installation. And this is very easy!

take a snapshot before you start messing around
# zfs snapshot rpool/ROOT/opensolaris@before-pkg-installation
and when it's over, roll back!
# zfs rollback rpool/ROOT/opensolaris@before-pkg-installation

Conclusion

In conclusion, creating an IPS package and running your own repository is not really hard, and I hope this guide helps you do that. You just install "glassfish-makepkgs" and off you go.

But at the same time, I have to point out that tooling around IPS is quite weak. The official tool set is virtually non-existent, and available ones have clumsy interfaces. Often error checks are not sufficient, so your mistake often results in the stack dump, and you are on your own to figure out what mistake caused it to choke. I think all these factors are adding up to the lack of community contributions to create packages.

And since not many people are contributing packages, there's no paved road to include your packages into the official repository. I hope Solaris folks would act on these issues before it's too late.

(If there's more interest, I can also talk about how you can install IPS on other Unixes and cross-build packages — in fact I've done all this work on my primary desktop machine that runs Ubuntu.)

Comments

Unfortunately java.net apparently decided to disable hyperlinks, the crucial link was lost. For others reading this, the e-mail discussion about the contrib repository is at http://mail.opensolaris.org/pipermail/pkg-discuss/2008-June/004026.html

About your comment about SFW, I guess I'm not trying to deny the value of SFW. I'm just wondering why I have to check out (or even just think about) all the other packages that I don't care about. Shouldn't I just be able to work on my little package and that alone?

While the SFW instructions are complex, they're mostly not about how to build a package. They're about much more - how to integrate a package into the shared build and delivery system so that everyone who works with it can build it, debug it, maintain it and update it, and how Sun makes sure it can support it long term - it's the difference between building a package you can install now, and building a component that's integrated into a product that will be supported for over a decade.

Since many people are just interested in building a package, work has been happening since before the 2008.05 release on a system to allow community members to do that and contribute it to a shared package repository - see the recent pkg-discuss thread on the contrib repo for more information.

P.S. To your earlier teamware comment, even if you install teamware it will not help unless you work for Sun (you do but not everyone ;-) since the repository is internal. You need to download the 600MB tarball anyway. (The good news is these are moving to mercurial on opensolaris.org. Looks like ON is already there, I hope SFW should as well in the near future.)

The idea that supportable applications can only be built by building all of them together from a single source tree is unfortunately a myth that exists only in the OpenSolaris organization. I'd be surprised if such approach is taken anywhere else in the industry. Moreover, Sun's own enterprise applications (see JES) are fully supported without the need to build them all from one single source tree. Can you imagine having to build Directory Server, Web Server and Messaging Server every time you fix a bug in Application Server?