Part XXI - Patch Management in OpenText Content Server

# Introduction

A Content Server patch is an effective way to fix a bug without having to install a new version of a module. The idea is simple: create a text file with the deltas, copy it to the opentext/patch/ directory, and restart Content Server. Content Server loads the patch at startup and applies the changes to the code base.

Removing a patch is even easier: just delete the patch from the file system and restart Content Server.

The simplicity of installing and removing a patch is why many customers prefer receiving a patch instead of a new version of a module. The overhead is less and rolling back is painless.

But how is the lifecycle of a patch maintained once it's installed? In other words, how does an administrator know when a patch should be removed? It's not obvious, and over the years I've seen numerous installations littered with old patches. This can cause all sorts of problems when a patch has become obsolete.

In most cases the header of a patch will contain documentation stating its purpose and to what module and version it applies. An administrator can open the patch in a text editor, read the documentation, and make an educated guess as to whether the patch can be removed. However, doing this for potentially hundreds of patch files is a manual, tedious, and error prone task.

OpenText has addressed this problem with the Cluster Agent, which is now part of a standard Content Server installation. This works well, but doesn't address third-party modules that are not distributed by OpenText.

After writing numerous patches over the years I needed to find a way to expedite the creation process, automate the lifecycle, and make the entire management less error prone. The solution is now part of RHCore. Let's dive in.

# Creating a Patch

The traditional steps to creating a patch are as follows:

  • Create an OSpace matching the name of the patch (typically of the form patNNNNNNNNNN.oll.
  • Orphan target objects from your module into the patch OSpace.
  • Override target features and scripts in the orphan.
  • Add a Comments feature to the Root object and add documentation. Each line must be prefixed with a hash (#). The documentation should describe what the patch does and to which module versions it applies. This gets inserted into the header of the patch file.
  • Generate the patch by executing $PatchUtils.Dump('patNNNNNNNNNN').

The resulting patch has the filename patNNNNNNNNNN.txt, and is ready to be deployed (after testing, of course).

RHCore simplifies the last two steps by:

  • providing a generic $RHCore.OScriptUtils.PatchDump() function, which automatically calls $PatchUtils.Dump() on any open OSpace with a name starting with "pat" (this is much easier than having to remember and write out the syntax each time); and
  • automatically populating the Comments feature (correctly formatted with each line prefixed with a hash) with details of the patch.

The last point is a major time saver since the generated documentation describes which module the patch applies to, in which module version the patch was merged (i.e., which module version makes the patch obsolete), who wrote the patch, and the date the patch was created. A developer can add additional comments to the .Documentation feature, which is automatically included in the comment.

The following is a sample header from a patch generated with RHCore:

# Patch PAT2016081101 created at Fri Oct 07 06:40:12 2016
#
# Modules:		rhcore
# Author:		Christopher Meyer (chris@rhouse.ch)
# Date:			2016-10-07
# Merged:		rhcore build 279
#
# Fixes an issue with `$RHCore.DBUtils.FilterToSQL()` when `daterange` has only one value defined.
#
# <patchinfo>{"author":"Christopher Meyer (chris@rhouse.ch)","build":279,"date":"2016-10-07T06:40:12","module":"rhcore","patch":"pat2016081101"}</patchinfo>
1
2
3
4
5
6
7
8
9
10

The header tells us the patch can be removed once RHCore build 279 or later is installed. But how can we determine this without having to manually open the patch in a text editor?

The added value is in the last line of the header. Details of the patch are injected as a parsable string in the <patchinfo>...</patchinfo> tags. This can be read by Content Server and leads to the next topic.

# Removing Obsolete Patches

RHCore adds a new "Patch Info" page to the admin.index pages. Executing it does the following:

  • iterates the patch files located in opentext/patch/;
  • attempts to extract the information from the <patchinfo>...</patchinfo> tags; and
  • if the information could be extracted then compare it to what's installed and display a warning if the patch can be removed.

A sample screenshot of the page is as follows:

With this information the Administrator can take the necessary steps to remove any obsolete patches.

# Wrapping up

I've been using this solution for a few years and it has made patch creation and management a less time consuming and error-prone task. I can create a patch and know it will be appropriately removed in the future once it has become obsolete.