Wednesday, August 25, 2010

Karaf's Fabulous Features, and, what you can do to make them even more fabulous

I've been working for sometime with the Karaf OSGi Shell, through my exposure to the great ServiceMix 4. The features mechanism provided by Karaf/ServiceMix allows you to leverage the modularity and control of OSGi bundles by grouping sets of bundles - containing your Camel routes, web services, business logic, RESTful services - into easily manageable 'features'. In this post, I'm going to talk a little about what features are, why they're good, and what we could do in Karaf to make their usage even easier. If you like the proposals, please, follow the JIRA links and vote for them so that we can get the community behind it. These enhancements are small, but, based on my experience, they could have a big impact on ease-of-use and adoption of a very powerful deployment mechanism.

Features: a group of bundles by any other name would sell as sweet.


A feature is just a set of bundles, described using a very simple XML file - this file is called a 'feature descriptor', and is also referred to as a 'feature repository'. Here's an example that describes a single feature, 'feature-b', that depends on another feature 'feature-a', which is itself described in another repository. I've thrown in some default configuration as well that will be synched into the OSGi Config Admin service; don't worry about this for now, I'm just showing off.



<features name="feature-b-0.0.1">

<repository>mvn:com.fusesource/common-features/0.0.1/xml/features</repository>

<feature name="feature-b" version="0.0.1>
<feature version="0.0.1">feature-a</feature>
<bundle>mvn:com.fusesource/bundle-b/0.0.1</bundle>
<config name="feature-b">
a=1
b=2
</config>
</feature>

</features>



Features can have sensible names, like 'InsuranceQuoteService' or 'CustomerUpdatesFlow', and they can be versioned so that you can track their evolution and upgrade or rollback with ease. Features can 'depend on' other features, which means that when you install a feature, it and all of its dependent features get installed too. This is very neat: how many times have you realized that, yet again, all your SOA, RESTful services and integration flows all rely on the same common backend code? You can describe these dependencies easily and elegantly using Karaf features. And, there's a set of tools that allow you to suck down all of your feature dependencies from Maven servers onto a local drive in an elegant directory structure - automatically, as part of your build - so that you can tar.gz or .zip it all and and deliver your feature into the production environment. This last point is so important: these techniques allow you to use all of your Maven-style bundle URIs on production machines that don't have Maven installed and don't have access to the external Internet.


Making features really, really easy to use

While all of this goodness is there for the taking in Karaf, there are a number of small improvements that, I think, will go a big way to ease the adoption of the features mechanism. My own usage of 'features' is based on what I've learnt and observed from the Karaf source itself: I want to make it easier for other developers to create, package and deploy features. And so, I've created today a number of issues on the Karaf JIRA to get the ball rolling.


  • KARAF-165: Create an improved Maven feature-assembly plugin. Right now, to make a feature I've got to add almost a hundred lines of Maven verbage to my pom.xml in order to assemble a feature. I've got to use the attach-artifact goal of the org.codehaus.mojo/build-helper-maven-plugin to deploy my features file into Maven. I've got to use the add-features-to-repo goal from the org.apache.karaf.tooling/features-maven-plugin to suck down all the dependent bundles. I've got to a whole load of other stuff to perform the packaging to .tar.gz and .zip. The problem here is that I'm using a whole load of generic plugins to do a very specific job, and I'm having to tell the plugins what to do instead of telling them what I want done. I'd prefer to have a single more declarative plugin to do this. It might look like this:


    <plugin>
    <groupId>org.apache.karaf.tooling</groupId>
    <artifactId>feature-assembly-plugin</artifactId>
    <version>2.2.0</version>
    <executions>
    <execution>
    <id>create-repo</id>
    <phase>generate-resources</phase>
    <goals>
    <goal>create-repo</goal>
    </goals>
    <configuration>
    <!-- Specify the feature file to use. -->
    <featureFile>file:${basedir}/target/classes/features.xml</featureFile>

    <!-- Specify what features to include. This is actually optional: if no features
    are specified, then include all features in the file by default. -->
    <features>
    <feature>feature-a</feature>
    </features>
    </configuration>
    </execution>
    </executions>
    </plugin>


    The plugin should produce a .tar.gz and .zip file, containing the feature descriptor (and all dependent descriptors) and all bundles (and dependent bundles)in a Maven-style directory, similar to the system/ directory currently used in Karaf. Note that this plugin doesn't need you to list out all the feature repositories / descriptors that your feature file may transitively include - it will detect these dependencies at runtime and work out the details.


  • KARAF-151: We need to add a hot-deploy mechanism, that will detect feature assemblies dropped in the deploy/ directory, and unarchive the file into, say, a contrib/ directory. 'contrib/' would be the application-level equivalent to the current 'system/' directory; it would contain all bundles that are required to run your features. After exploding a feature assembly into the contrib/ directory, Karaf should scan the directory structure for feature repository files, and add these dynamically to the runtime.



The result? If we implement these two enhancements to Karaf, we'll end up with a double-whammy. Developers will find it incredibly easy to create feature assemblies. Administrators and operations folk will be delighted that all the have to do is copy a feature assembly to the deploy directory, and then ssh into the Karaf/ServiceMix runtime and list, install and upgrade or rollback features using the 'feature' commands.

If you like these proposals, please vote for the issues!

5 comments:

Unknown said...

These look like great features. I'm looking at doing something exactly the same as is described in the justification for KARAF-165; I'd love to have such a feature. That being said, do you have an example handy of these "100 lines in the pom" to do this today?

Ade said...

Thanks for the feedback! For those 100 lines of pom, check out the Karaf code from https://svn.apache.org/repos/asf/karaf/trunk and then take a look at the file assembly/pom.xml - all the techniques you need are in there!

Christian Mueller said...

Hey Ade,
I voted for both issues and would like to see they soon... ;o)
Cheers,
Christian

Geert Schuring said...

Hey Adrian,

I must say I like the Karaf Features too, but on a lower level (Enterprise OSGi) there is already something called 'applications'. I think we should look into that and maybe drop the karaf features for it.

(See http://incubator.apache.org/aries/applications.html)

Ade said...

Hi Geert,

I think that supporting the Aries Bundle Archive (.eba) format is a great idea. However, this format is specific to Aries; it's not a standard. I was chatting with Guillaume Nodet about this, and he reckons that the OSGi EEG will have a standard out for this sometime next year. This new format would probably take the best of ideas from Karaf's features, Aries's EBA, and ideas from SpringDM too. So, for me, I think the right approach is to: a) continue to support and enhance Karaf's features; b) strive to support EBA; and, c) get ready to move towards a standards-based approach sometime in 2011 as soon as the standard is out.