Replacing the Application Packaging Developer’s guide

I started at Sun in the European Localisation group, and writing tools to create (and sometimes hack) SVR4 packages for Solaris was one of the things I had to do quite a bit – I found myself consulting the Application Packaging Developer’s Guide frequently. So, having the opportunity to help write its replacement was pretty cool.

Bart did a great job in defining the structure of the new book, and writing a lot of the initial content. Brock wrote some comprehensive content on package signing, SMF and zones, and I’ve been working on the guide since then, using some of the original documentation that Stephen wrote.

Unlike the previous guide, we have fewer examples in this guide. We feel that our man pages are better than the SVR4 packaging man pages were, and already contain useful examples. This guide is meant to compliment our man pages, not replace them.

The guide is a lot shorter than the old book – currently 56 pages, as opposed to the 190 pages in the document it replaces. Some of this is because of the fewer examples we have, but also we don’t have to write about patch creation, complex postinstall or class-action scripting or relocatable packages. IPS is simpler than SVR4 in many ways, though there is a learning curve, which this book aims to help with.

There’s more work to do on the book (as you can tell by the “XXX” markers that appear throughout) but what we’ve got so far is here: source code, and here, inelegantly rendered as a pdf.

If you use IPS, or have had experience in packaging software for Solaris previously, I’d be interested in hearing your thoughts on the content so far.

Updated: I’ve updated the PDF with the latest content as of today, and made sure there’s a datestamp on the file, so you can tell which version you’re reading. Changelog below (though I’ve not put the source back to the gate, yet, so these changesets will likely be collapsed)

Updated: Almost at the final version – there’s a few small changes to make, but I’ve updated the links to the pdf of that version now, which hasn’t yet been pushed to the gate. Too many commit messages to indicate what’s changed unfortunately.

Like this:

Related

Post navigation

One of the challenges I’ve had as a user of IPS is changing the publisher of packages.

Typically, I will develop my software into a local repo, with a publisher of for example foo-dev. If I then wish to publish my software to a production repo, for example, foo, I have to use the set-publisher.sh script from the pkg-gate, which is not well documented if you’re not aware of its existence.

Yep, I remember the conversation. Sounds reasonable. For now, I’ll add a section to chapter 14, which covers package republication to cover that use case. I’ll update the pdf later today (and add an “Updated:” note to the blog post. Thanks for taking a look!

An actuator is a tag applied to any action delivered by the packaging system that causes a side effect to happen when that action is installed, removed, or updated.”

“There is no obvious way to emulate preremove or postremove scripts.”

So how will IPS packages unconfigure or back out the changes they have made to the system?

As you stated yourself in the document, self-assembly should be used where that is possible, but most open source software has no concept of self assembly. How will an IPS package remove his own changes made to configuration files of such software?

Let us assume the best case scenario for illustration purposes:

Apache supports the include directive. An IPS package injects an include statement into the httpd.conf file via an SMF manifest it has brought on during installation. The include statement includes an additional configuration fragment. For the purpose of this illustration, disregard the fact that Apache can use wild cards.

How will that package remove his include statement from httpd.conf upon being removed from the system?

Well, today in Solaris, once a httpd.conf points to /etc/apache2/2.2/conf.d your package simply delivers a fragment of a .conf file file into that directory, and the actuator attribute attached to the action that delivers that file has a refresh_fmri pointing to the apache22 SMF instance.

Likewise, removing that file would cause the same actuator to run, refreshing the service, and causing Apache to re-read its configuration.

The pattern is the same, the only difference if the software isn’t capable of self-assembly, is that you have to help it along by writing an SMF service.

That is, your system contains an SMF service that builds your configuration file. Perhaps it references a “golden master” version of the config file in an alternate location, copying that file into place.

When you deliver software that needs to modify that that configuration, you deliver a fragment containing the changes, then restart the service with a restart_fmri actuator in the package. The service then rebuilds the configuration, using the original template, and the fragment you’ve just delivered.

When the software needs to be removed, the same restart_fmri actuator fires, notices the fragment is missing, and rebuilds the config file.

The key thing, is that running the SMF service should be deterministic, always resulting in the same configuration being built each time gets run with the same set of configuration fragments installed.

If user modifications are allowed, those modifications should be performed on an unpackaged config file fragment, such that the SMF service includes them when constructing the configuration. I would assume an appropriate warning would be given in your configuration file, indicating where modifications should be made.

Tim, you told “If you use IPS, or … packaging software for Solaris previously, I’d be interested in hearing your thoughts…”. I have experience in IPS, SVR4, and, earlier, in RPM.

The fatal problem with IPS is that a software package can’t be transferred off the wire, as just file.

Before IPS era I could just copy a package on a flash drive, put it in my pocket, bring it into another system, install. Easy. With IPS I should … put a Solaris server in my pocket, bring, connect to network, hmm … ?!

Before IPS era I have had a shelf with distribution medias with various Solaris releases. I could take any CD from the shelf and immediately install any software package from CD. Very easy! With IPS I should … have a Solaris server serving a lot of legacy IPS repositories just for the case if somebody, once per year, would need it. The electric power costs, the maintainance costs of this approach are not comparable with the costs of keeping CD’s shelf.

Before IPS I have had a collection of my favorite software packages kept in ~/pkg/. With IPS I should … own and administer a Solaris server to maintain my collection ?

Look, nowadays the Sun Studio is distributed as “tar.bz2” file. What a shame! Excellent example of advances in Solaris package management system. Just forget package management.

What about independent software catalogues, which offer cross-platform software? Should they serve http and ftp downloads for Windows, Linux and Mac OsX, but run separate IPS server especially for Solaris, provide separate infrastructure for uploading and managing packages ? Really ?

What about ISV in the same concern, Mozilla, e.g.?

I wouldn’t say that IPS is a kind invitation to provide Solaris versions of software. It is a blocker.

Well, IMO, the IPS is a disgusting beast that was brought into Solaris (by Ian Murdock, I guess). It looks like subversive act.

We do support downloadable packages. *.p5p package archives are the logical successor to the SVR4 datastream format. You can easily retrieve any/all packages from a given repository into one or more of these files, which are easy to serve using traditional distribution methods.

pkg(1) supports temporary publishers, where you can point the ‘pkg install’ command directly at of these package archives, from which to install, or update your software. No need to carry around a Solaris server for the job.

I agree that Sun Studio should be delivering in this format, and the problem is being worked on.

Alternatively, you can pkgrecv(1) the contents of an existing repository into a local repository, and burn an ISO image of it to serve from an another Solaris server (or client) at a later date if that suits your needs better. Indeed, there’s no need to burn the entire repo, you can pkgrecv just the latest packages if you need to keep the size to a minimum.

I would expect that Solaris releases would be available as an iso snapshot of the repository as well as livecds

Of course you’re entitled to your opinion, but if your experience of IPS was a result of investigating OpenSolaris a few years ago, I hope you’ll be pleasantly surprised with how far the packaging system has come since 2005.

I hope to get an updated pdf of the guide up here within the next few days.

“When you deliver software that needs to modify that that configuration, you deliver a fragment containing the changes, then restart the service with a restart_fmri actuator in the package. The service then rebuilds the configuration, using the original template, and the fragment you’ve just delivered.”

That’s all good an well, but it requires an SMF manifest to be restarted or stopped. What removes the SMF manifest, the package which brought it on to the system?

I am still unclear how this should work, and propose that you document this extensively in the packaging guide, the document being a guide an all.

For example, assuming that the package delivers a manifest which, when started, injects some configuration lines into some /etc/opt/vendor/bla.conf, from a template, what should happen if the system administrator (or some automated process) runs

svcadm disable {FMRI}

for the service which that package brought on?

Also how do I ensure that the manifest is removed last, because it seems that the fragment would need to be removed before the manifest, so when a refresh/stop is triggered, it must detect that the fragment is missing and remove the injected configuration lines from /etc/opt/vendor/bla.conf?

Did I even understand you correctly?

At any rate, this must be documented in detail in the packaging guide, because it is a very common scenario and lots of packages will need to be doing it, and doing it correctly.

It’s too late to make major edits to the dev guide for this version – perhaps we can clarify this in the next version and include another worked-example. In the meantime, I’ll try to answer your questions (I hope I’ve summarised them accurately)

Don’t allow them to – if your application relies on a certain piece of configuration, and that configuration is dependent on self-assembly being completed, then it’s reasonable to have your application service declare an SMF dependency on that self-assembly service. Otherwise, your application is at risk from running with a stale configuration.

2) How do you remove edits when the package that introduced the edits has just been removed – how do you know what changed? Isn’t there a problem with ordering here?

The point is that the self-assembly service only ever builds the configuration from the installed fragments on the system.

So, if your package removes one configuration fragment, then that fragment doesn’t get used as a source anymore. Don’t think of your add-on packages as delivering files that supply “edits” to an existing config file, instead, think of the self-assembly service as being responsible for constructing the entire configuration from scratch, using only the information available to it.

As mentioned in the dev-guide, there’s ways to optimise choosing whether to rebuild a configuration, or whether an existing config file is up to date.

In terms of ordering, you need to ensure that the service that performs self-assembly is delivered in a package that your application depends on, or deliver the self assembly service in your application package directly (which is another solution to question 1) above )

3) How does any delivered SMF service get removed from the system?

Any delivered SMF manifest files should have a restart_frmi actuator pointing to ‘svc:/system/manifest-import:default’ When this runs (eg. at the end of package removal) any SMF services/instances in that are no longer backed by any manifests in /lib/svc/manifest or /var/svc/manifest, the filesystem are deleted by SMF.

Vaguely. For example, “Don’t allow them to” — I am unclear as to how declaring a dependency (and where!) would prevent the system administrator from purposely or inadvertently running svcadm disable. Examples are direly needed.

“2) How do you remove edits when the package that introduced the edits has just been removed – how do you know what changed? Isn’t there a problem with ordering here?”

Is there? Usually you have some third party software which delivers its own .conf file somewhere in /etc — one does not deliver that file — so it is natural to want to inject configuration lines during package installation, and remove configuration lines during package removal. That is intuitive.

But that is exactly what they do — SVR4, and RPMs, and SD-UX PSFs. We call them “configuration overlays”. About 50% of these configuration overlays do not even have any payload, because the preinstall, postinstall, preremove and postremove scripts do all the work.

I am not unwilling to migrate to IPS if there were some concrete examples that dealt with migrating such packages to the “new way” of doing things, but the concepts you describe seem so esoteric and complex that the only way to understand what it is that we are expected to do is by showing us concrete examples. For example: how would a manifest which assembles the .conf file look like? What is it supposed to do, and how? What would the IPS’s equivalent of prototype(4) look like for such a package? What must be paid attention to when designing such packages?

What you have described so far in the last five years is completely counter-intuitive to how every software management subsystem works, so in order to migrate to this completely different way of doing things, we the software architects, developers, and packagers are going to need help. And the best way to help us is by providing lots of examples for these scenarios. The more examples you provide, the easier it will be to discern the pattern.

That is, assuming your application delivers an SMF service, add an SMF dependency on the service your application delivers, making it depend on the self-assembly service it needs. If a user disables the self-assembly service, the your application service won’t restart cleanly until the self-assembly service is enabled.

As for a fully worked example of self-assembly, that’s more than I can do in these comments. I’ll try to write a new post with such an example.

In a nutshell though, you’ve two choices if you need to allow packages to modify a static configuration file:

* Don’t use self assembly

Instead use the ‘overlay’ attribute documented in pkg(5) to allow two packages to deliver a static configuration file, allowing one package to overlay another. If multiple packages can to contribute to the same configuration file, then each configuration package must declare an ‘exclude’ dependency on the others so that only one configuration package can be installed at a time.

* Use self-assembly

Here’s how:

1. Modify your application to delivers its static configuration file to an alternate location (eg. /opt/myapplication/etc/myapp.conf.template ) and do not deliver myapp.conf in its traditional location.

2. In your application package, deliver an assembly SMF service to copy that static configuration into place (cp /opt/myapplication/myapp.conf.template /opt/myapplication/etc/myapp.conf) Treat that .conf file as being volatile.

3. Your assembly service looks for delivered fragments in a known location (eg. /opt/myapplication/etc/conf.d) , and applies the edits found in those files, in a deterministic order to the volatile myapp.conf
[how these edits are applied is up to you]

4. If your application uses an SMF service, make that SMF service depend on the assembly service so that it won’t start until assembly is complete

5. When a configuration package delivering one of those fragments gets uninstalled, an actuator in that package causes the self-assembly service to restart, which rebuilds the volatile configuration file from the template, and any remaining configuration files still on the system.

We know the dev guide needs more examples, we just ran out of time. It will be updated with examples as we write them.

When you start writing examples, please pick a piece of free open source software which is not self-assembly aware, so that the whole process of “helping it along” with self-assembly can be illustrated. It does not matter what you choose, so long as it does not support any include directives, i.e. choose something which was never designed to self-assemble.

Do you have any suggestions for common open source software which isn’t self assembly aware?

Most of the open source projects I work on upstream seem to have already moved to or are moving to this model, as it simplifies and improves installation and upgradability for all distros and packaging systems. For instance, Xorg now supports xorg.conf.d/* snippets and fontconfig split up fonts.conf into /etc/fonts/fonts.conf.d a while ago. You’ve already had the apache example earlier in this thread.

I’ve written two subsequent blog posts on how add-on packages can deliver configuration.

The first talks about where we deliver an entirely new configuration with each configuration package. The second, is really what you’re after here and can be adapted to deal with both IPFilter and init.ora cases, though I wrote both before seeing your suggested applications here.

Hi, this is Smita. how does to create an IPS package that supports interactive installation? For example, how to handle non-default base directory/accept inputs for installation of optional features etc.

We’ve moved that functionality out of the packaging system entirely, since for the most part, interactive installs aren’t performed on enterprise systems. Instead, we recommend that any post-configuration steps be performed when the functionality that the package provides is first used.

As for non-default directory locations, there’s more work to do in IPS itself to support the notion of ‘user-images’, which were intended for this kind of work. Facets are the IPS facility to allow optional packaged components to be installed, which work today and may be of interest.