Introducing Cobbler4j

I've been doing some work recently on cobbler4j, a small Java library for interacting with Cobbler over XMLRPC based on the work done to integrate Cobbler into Spacewalk.

Right now the library basically allows you to open up a connection, and interact with the core object types (repos, distros, profiles, systems) as if they were actual Java objects. In the future this will likely grow to include other operations and background tasks. And as a required disclaimer, this is still very much a work in progress and should not be considered stable.

The cobbler4j wiki page covers most of the high level details on what it does and how to use it.

Here's a sample program:

import org.fedorahosted.cobbler.CobblerConnection;
import org.fedorahosted.cobbler.Finder;
import org.fedorahosted.cobbler.ObjectType;
import org.fedorahosted.cobbler.autogen.Distro;
import org.fedorahosted.cobbler.autogen.Profile;

import java.util.List;
import java.util.LinkedList;

public class Cobbler4jDemo {

public static String DEMO_PROFILE = "demoprofile";

public static void main(String [] args) {

CobblerConnection xmlrpc = new CobblerConnection("http://192.168.1.1", "testing",
"testing");
Finder finder = Finder.getInstance();
List distros = (List)finder.listItems(xmlrpc,
ObjectType.DISTRO);
System.out.println("Distros list:");
for (Distro d : distros) {
System.out.println(" " + d.getName());
}
System.out.println();
System.out.println();

// Delete the demo profile if it got left laying around:
Profile demoProfile = (Profile)finder.findItemByName(xmlrpc,
ObjectType.PROFILE, DEMO_PROFILE);
if (demoProfile != null) {
System.out.println("Deleting profile: " + DEMO_PROFILE);
demoProfile.remove();
System.out.println();
System.out.println();
}

// Create a demo profile, set the required properties:
System.out.println("Creating profile: " + DEMO_PROFILE);
demoProfile = new Profile(xmlrpc);
demoProfile.setName(DEMO_PROFILE);
demoProfile.setDistro("centos-5.3-i386");
demoProfile.commit();
System.out.println();
System.out.println();

System.out.println(DEMO_PROFILE + " settings:");
System.out.println(" kickstart = " + demoProfile.getKickstart());
System.out.println(" virt file size = " + demoProfile.getVirtFileSize());
System.out.println(" Red Hat management key = " + demoProfile.getRedhatManagementKey());
System.out.println();
System.out.println();

List profiles = (List)finder.listItems(xmlrpc,
ObjectType.PROFILE);
System.out.println("Profile list:");
for (Profile p : profiles) {
System.out.println(" " + p.getName());
}
System.out.println();
System.out.println();

// Lookup our specific demo profile:
demoProfile = (Profile)finder.findItemByName(xmlrpc,
ObjectType.PROFILE, DEMO_PROFILE);

}
}

Some interesting things to note, firstly rather than maintain Java classes with a bevy of irritating getters/setters, Michael Dehaan started us down the path of auto-generating the Java classes from a template and the FIELDS metadata in the Cobbler Python code itself. (which describes each property on an object, it's type, and some other information) This posed some build problems early on but in the end it actually came out ok, and the build is relatively seamless with ant.

In the above example a couple magical things happen. The first relates to object creation, when creating the profile we specify only the bare minimum of information. If you were to do this from the cobbler CLI however your object would immediately have a number of other default settings applied. To replicate this behaviour after doing a commit on any cobbler object we immediately repoll the state from cobbler and update the object state internally for you.

Similarly another problem arises with Cobbler's notion of inheritance known as "blending". The implementation of this basically results in object properties being set to an inherit string constant if they're to use their parent object's value. This gets complicated however when you're auto-generating a Java class that expects a Boolean, but gets a String instead. Usually not a catastrophic problem in a dynamic language like Python, but Java is not so happy about it. To solve this we also maintain a hash of the "blended" properties as well which are obtained via a separate API call. Whenever we call a getter, and that object supports inheritance, and the property comes back as inherit, we instead return the value from the parent. This has the added benefit of not inadvertently setting parent values directly on the object itself whenever we do a commit.

So definitely a bit of magic going on but so far I haven't thought of situation where it would break down, and thus I'm content with it for now. There's some minimal overhead involved in the refresh calls but in local testing it's blazing fast, and likely not calls that will be used under heavy load. (as far as I can forsee)

While the bindings are definitely not yet considered stable, wheels are in motion and as always contributions would be welcome if anyone would like to participate. Special thanks to Partha Aji for his assistance, ideas, and contribution of the Finder class used for querying/listing objects.

Comments

Post new comment

The content of this field is kept private and will not be shown publicly.
Type the characters you see in this picture. (verify using audio)
Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.