This is the second part of a series explaining how to use TTP iPrint Printer Lists. It also uses them as an example of how to leverage existing OES capabilities to extend the product to new solutions. In this article we will explain how to set up eDirectory to use printer lists, and why it is desirable to use eDirectory as data storage.
The eDirectory setup portion is actually fairly simple. First, you should already have iPrint printers working through OES (NOT the iPrint appliance) because we build on work that has already been done by that setup. Plus there must be printers before there can be a list of them.
Second, you need to extend your eDirectory schema with the file ttpiprint.ldif which is included with the files that will be published in the last of these articles (or you can look below to make your own).
There are a variety of ways to extend the eDirectory schema, and they all have the same result. When I installed printer lists in my own environment I used the command-line version of eDirectory's ICE (Import-Conversion-Export) tool. However, you could also use the GUI version of this tool, straight LDAP, or a variety of other methods.
Extending the schema is fully supported by Micro Focus and is not intended to be a dangerous operation -- the ability to support a wide variety of schema extensions is a core part of eDirectory's power and competitive advantage. The twin bedrocks of OES are its use SUSE Linux for its underlying OES and its use of eDirectory as its data source.
eDirectory is not just an LDAP server for providing user information, it is a very rich implementation of most of the X.500 suite of Directory Service standards, of which LDAP is but a tiny subset. From this standard we also get the current certificate framework (X.509) around which most Internet security is built.
The data storage layer of eDirectory is FLAIM, a database originally used by the Church of Latter Day Saints of Jesus Christ to hold vast amounts of genealogical data. I like to think that if FLAIM can hold data on everyone who has ever lived, it can probably handle whatever projects you have in mind. FLAIM is open source (although the linked source is not current) and a review of the included documentation shows that many of eDirectory's features such as attributes on objects, replication, and easy backup are actually built into FLAIM rather than in layers of business logic above the data store as is common with other directory services (I'm looking at you, OpenLDAP, with your multiple-storage options).
Numerous applications from the original version of ZENworks to Access Manager have been built around eDirectory, and GroupWise also uses FLAIM. Some of these applications moved to other data storage methods (most notably ZENworks) in order to be cross-platform and support Active Directory. In my humble opinion this change was necessary from a market-positioning perspective but for technical quality eDirectory still cannot be beat.
By choosing to use eDirectory to store our printer list data, we get to leverage a ton of functionality right out of the gate. eDirectory's automatic replication means that our data is redundant and scalable without us having to do anything extra. We can richly define data objects and their attributes with built-in validation. Complex rights and hierarchy are native to the platform. There are a multitude of backup options, and the data for our tiny application gets backed-up at the same time as the user and printer data we depend upon.
Oh yes, users and printers -- the two things our printer lists will require. Both already exist in eDirectory, so by using eDirectory to store our lists all we really need to do is create some bits of bailing wire to hold everything together. In fact, just about every tool we will need to create printer lists already exists in drawers somewhere in the eDirectory shed (to extend the metaphor).
Our printer lists will exist as eDirectory objects -- standalone entities in eDirectory with a set of attributes. If one of our list objects is damaged, the others will be unaffected. This is great when you consider how much chaos a little corruption in a couple of cells can do to the entire data set of a relational database. If our printer list becomes unreadable, we run "ndsrepair -R" to check the integrity of eDirectory and then try to recreate or even rebuild the single list that has gone awry. If the same thing happened in a SQL server we would be looking to restore the entire data set from the last good backup. And if things ever get really bad with eDirectory, we can always try fixing our problems by replacing a crashed server with data from another replica.
Okay, so how should a printer list object be represented as eDirectory data? Well, obviously we need a list of printers. This is very easy to represent: We will just have a multi-valued attribute that holds printers on our printer list object. Specifically, the attribute will contain DNs (Distinguished Names) that reference iPrint printer objects in eDirectory. Then we probably want to be able to associate these printers with users. How might we do that?
eDirectory actually already contains objects that keep lists of associated users, groups, and containers -- the standard "group" object itself! So we can get this functionality just by making our printer list object an extension of the standard group object. Using the group object as our base also gives us access to two other useful attributes, "title" and "description".
So, our printer list object in eDirectory has these characteristics:
The object itself is called ttpiPrintPrinterList .
It is based on the group object, and inherits the attributes "member", "title", and "description" that will come in handy. It also implements the required "cn" attribute that gives a short common name to all eDirectory objects.
There is one new attribute to hold the printers - ttpiPrintMemberPrinter . eDirectory lets us define and restrict the type of data that this attribute can contain and so we have decided that it can only hold DNs.
eDirectory objects and attributes are defined in the eDirectory schema, which is why we need to extend our local schema in order to add our new object and its one new attribute (and specify which existing attributes to use too).
The "ttp" prefix is used so that our implementation will not conflict with any official implementation that the iPrint team may decide to create in the future.
That is actually a very important consideration: I really wish that Micro Focus would provide this functionality instead of my version. The iPrint and OES teams are much better engineers than I am, and their implementation would have a bunch of niceties that mine does not.
For one thing, their objects would have cool icons in iManager like the iPrint objects do. I have not found an easy way to assign my own objects in eDirectory.
More importantly, their implementation would be able to support double-linking of objects. In my implementation the iPrint printer list has a list of printers that belong to it. This one-way linkage is a very "Active Directory" way to handle relationships. The "eDirectory" way is that for any object with an attribute containing a list of objects, the objects in the list will also contain an attribute that points back to the object containing the list. For example, every user in a standard eDirectory group is not only listed in a member attribute within the group but also has an attribute listing all the groups to which it belongs. This practice makes eDirectory more efficient at lookups (since we only have to look at one object for any type of membership lookup) and also more robust in complex operations such as rights calculations.
My implementation does not implement double-linking because I want the footprint to be as low-impact as possible. To implement double-linking, the iPrint printer object definition that exists in a standard deployment of OES iPrint would have to be extended to support a printer list attribute. This could lead to trouble down the line with new versions of OES.
Yes, there is one cheat in our implementation: The import process gets a bit grumpy if schema extensions do not contain an OID. An OID is a hierarchical numeric ID (similar to a Dewey-decimal number) assigned to an X.500 directory element to ensure that it does not conflict with an existing, standard element. An organization will usually have a set of OID numbers that it can use exclusively. However, the process to register your own OID space is laborious, expensive, and beyond the reach of most of us.
Still, iPrint printer lists need OIDs for our new attribute and object. What to do? Many years ago, Novell would give OIDs to developers within its own range, but it no longer does so. However, I know that there is an OID range within eDirectory specifically reserved for printer vendors to register their own NDPS printer objects (some of that documentation is here). This seems to me to be close enough to the printer list use case and so I have "borrowed" OIDs deep within this range that are highly unlikely to ever be used.
So after all that planning, what will the data in eDirectory look like? Our final schema extension ldif file looks like this:
attributeTypes: ( 2.16.840.1.113719.2.322.4.91 NAME ( 'ttpiPrintMemberPrinter' ) SYNTAX 188.8.131.52.4.1.14184.108.40.206.12 )
objectClasses: ( 2.16.840.1.113719.2.322.6 NAME ( 'ttpiPrintPrinterList' ) SUP Top MUST cn MAY ( description $ title $ ttpiPrintMemberPrinter $ member) ) X-NDS_NAMING 'cn' X-NDS_CONTAINMENT ('organization' 'organizationalUnit' 'domain') X-NDS_NOT_CONTAINER '1' )
You may copy that to an LDIF file and use it to extend the schema right now if you wish (although you probably want to wait until the end of these articles).
Let us go through it a bit.
The "version 1" is boilerplate for ldif. The "dn" and "changetype" lines let eDirectory know that we want to modify the schema. We are adding two elements -- the "ttpiPrintMemberPrinter" attribute and the "ttpiPrintPrinterList" object. The "add" line in each case tells eDirectory what type of element we are adding.
We define the attribute first since the object uses it and therefore cannot be created until it exists. The actual definition is in the "attributeTypes" line and is fairly straightforward. Within those nested parentheses we assign the lovingly borrowed OID number, the name of the attribute, and finally the type of data that can be stored in the attribute. This is the "SYNTAX" section, and you will notice that we refer to the data that the attribute can contain not by an attribute name or textual data type but by the OID of the data type -- in this case, the OID of the DN attribute.
The objectclass has a similar definition line, but it is much more complicated. After the OID and name assigned to the object type, we define the attributes that the object contains. In this case the only required attribute is "cn" (in the "MUST" section) and then the printer list object can also, optionally, have description, title, member, and ttpiPrintMemberPrinter attributes.
The rest of the line--all the bits starting with "X-NDS"--specify that the object gets its name from the cn attribute, that it can be held in O, OU, or DC containers, and that it is not itself a container object. (Sometimes some very funny objects get created as containers. NetWare licenses, for example.)
Hopefully from this example you can see that creating objects in eDirectory to store your own application is not tremendously difficult and offers quite a few advantages.
In Part 3 we will examine how to administer these objects with iManager.