Conary:Tag Handlers
From rPath Wiki
|
A tag handler in Conary is an executable which performs specific operations on a given file or list of files each time those files are changed. Appliance builders will occasionally use a tag handler to automate tasks based on file updates.
Tag handlers are only called for files that have actually changed from one version to another. The tag handler will be run after any tagged files have been changed on the system by applying Conary changesets (or updates). Tag handlers will not be called on an update if no tagged files have been changed; even if a package or group is updated, a tagged file itself must have changed for the tag handler to run.
| Keep tag handler use to a minimum! Throughout this page, note the potential issues. Only use tag handlers when alternatives present a higher cost or a higher risk to system health. |
Tag Handler API with Conary
As described in Conary:Dynamic Tags, two files make up a tag: the tag description file and the tag handler. Create a corresponding tag description file to accompany a tag handler.
A tag handler is passed a type such as files or handler as the first argument and an action such as update or preremove as the second argument. These types and actions are registered in the tag description. This makes error handling straightforward using case statements. See the two-level case statements in the tags in /usr/libexec/conary/tags/; rPath recommends using the structure of existing tag handlers as a guide to creating new ones.
The succeeding arguments passed to the tag handler are the paths of the tagged files that have changed. Recall that even if a package which contains tagged files is updated, the tag handler will not run unless at least one of the actual tagged files have changed.
File List as Arguments
In some cases, the list of files is not important to the tag handler; knowing that one of the tagged files was changed is sufficient to run the tag handler. This is common for database entries and cache entries in which the action is always a rescan of the supported paths. As an alternative, an update and remove could possibly be used to perform the same task.
In other cases, the list of files is important to the tag handler, and the list can be passed as the remaining arguments to the tag handler. In such cases, assume that more than one file can be passed because more than one tagged file may be changed in any given operation.
Multiple Packages and Package Versions
If a tag handler is expected to manage multiple versions of a package or multiple packages, it may not be called on one particular set of files or one version of a package at a time. The tag handler is run at the end of change operations, meaning it is possible that multiple items are updated at the same time.
Ordering
Conary does not provide ordering between tag handlers, and the order in which they are run is not guaranteed. A tag handler cannot expect that any other tag handler has run before it processes. This means that the runtime requirements for a given tag handler may have yet to run their own tag handlers. To handle things in a certain order, you will need to use multitag protocol handlers, in which one handler acts on more than one type of tag.
Tag Handler Updates
If a tag handler is updated, it is re-run against the tagged files on the system. This provides a means to correct errors in a tag handler, but it can expose new errors if you do not expect this behavior. For example, you may not want a tag handler to just append paths to a config file, but to also check to see if the file exists first because it is possible that the tag handler has been called on the same files before.
Shell for Tag Handlers
Though there is not specific requirement that a tag handler be written in shell, it is a best practice to ensure that dependencies are kept to a minimum.
Shell script runtime requirements are not automatically discovered, and when these dependencies are not present, the results are unpredictable. External dependencies required by the tag handler itself must be discovered and added as runtime requirements for the trove which contains the tag handler, and this is not done automatically for shell scripts. The runtime requirements must be worked out manually and assigned in the recipe. As a result, the more complex the tag handler, the greater the chance for missing runtime requirements.
Consider writing tag handler that are explicitly bash scripts and use bash conventions. For example, use ${path/*\//} instead of $(basename $path). Use the Parameter Expansion page as a reference.
Sample Tag Handler
The following example is the initscript tag handler with some additional comments to explain what it will do. Also, create a corresponding tag description file to accompany the tag handler.
#!/bin/bash # Use at least enough arguments to ensure a valid type and action, or error out. if [ $# -lt 2 ]; then echo "not enough arguments: $0 $*" >&2 exit 1 fi # Initialize type and action to leave the remaining args as the filelist. type="$1" shift action="$1" shift # Use case type to ensure that the taghandler is passed only types it can # handle. In this case, use only handle files and error out on anything # else case "$type" in files) # For file type operations, case the possible actions and error # for anything unsupported. case "$action" in update) # Iterate the file list because it is not known in advance # how many files we will be passed in a given operation. for file in $@; do /sbin/install_initd $file done ;; # Use preremove to cleanly stop a service # before removing the init file which controls it. preremove) for file in $@; do $file stop /sbin/remove_initd $file done ;; *) echo "ERROR: taghandler $0 invoked for an action ($action) that is not handled" 1>&2 exit 1 ;; esac ;; *) echo "ERROR: taghandler $0 invoked for a type ($type) that is not handled" 1>&2 exit 1 ;; esac exit 0
