Conary:Group Recipe
From rPath Wiki
|
A group in Conary is defined by a group recipe. Like other recipe files, the filename is the group name followed by a .recipe extension. Conary also requires group names to be preceded by group-; a group recipe file for a group named group-example would be group-example.recipe.
Basic steps for developing the group recipe are:
- Identify and locate the packages needed to build the group.
- Write the group recipe to add the packages to the group.
- Cook the recipe in the build environment and handle the Conary messages (cvc cook group-example.recipe).
- Commit the group recipe to the repository and cook the group.
Use the following sections to create and develop a group recipe. As with all recipes, be sure to adhere to Conary's recipe conventions.
Group Recipe Template
The following is a template to get started on such a recipe.
| When creating an appliance group based on the rPath Appliance Platform, use rPath Linux:group-appliance as a template, instead. |
class GroupExample(GroupRecipe): name = 'group-example' version = '0.0.1' autoResolve = True def setup(r): r.add('example-application') r.add('example-dependency:runtime') r.add('supporting-software', '/example.rpath.org@corp:1/2.2-1-4')
- The class line informs Conary that you are cooking a group recipe.
- The name line reflects the name of the group, in this case group-example.
- The version line defines the group recipe version.
- The autoResolve line requests automatic dependency resolution when the group is built, eliminating the need to list each dependency as an additional line within the group.
- The first r.add line includes a package in the group.
- The second r.add line includes a component in the group (a runtime component that is originally part of the example-dependency package).
- The third r.add line includes a specific version of a package in the group (version /example.rpath.org@corp:1/2.2-1-4 of the supporting-software package); by installing and managing the package using the group instead of separately, developers can ensure that the package is restricted to this particular version.
Group Recipe Classes
Conary group recipe classes provide the interface for creating groups in a Conary recipe. Special group recipe parameters can be specified to the GroupRecipe class when building a group with Conary. These parameters are summarized here (with default values in parentheses), and detailed further in the PARAMETERS section of the Group Recipe API Documentation.
- depCheck (False)
- This parameter controls whether Conary should check for dependency closure in the group. If this parameter is set True (it is False by default), then Conary will raise an error if the closure in the dependencies comprising the group is not found.
- autoResolve (False)
- This parameter controls whether Conary should include the necessary troves which automatically resolve dependencies in the group.
- checkOnlyByDefaultDeps (True)
- This parameter controls whether Conary should check for dependencies in troves which are installed by default only. If this parameter is set to False, then Conary will check dependencies in troves which are not specified to be installed by default in addition to those which will be installed by default.
- checkPathConflicts (True)
- This parameter controls whether Conary should check for path conflicts in each group to ensure that the group can be installed without conflicts. Set this parameter value to False to disable checking for path conflicts.
The following group recipe classes are available for building group recipes with Conary:
| r.add | Adds a trove to a group |
| r.addAll | Add all troves directly contained in a given reference to groupName |
| r.addCopy | Create a copy of name and add that copy to groupName |
| r.addNewGroup | Adds one newly created group to another newly created group |
| r.addResolveSource | Specifies an alternate source for dependency resolution |
| r.createGroup | Creates a new group |
| r.remove | Removes a trove |
| r.removeComponents | Define components which should not be installed |
| r.Requires | Defines a runtime requirement for group |
| r.replace | Replace troves |
| r.setByDefault | Set troves to be added to group by default |
| r.setDefaultGroup | Defines default group |
| r.setLabelPath | Specify the labelPath to search for troves |
| r.setSearchPath | Specify the searchPath used to search for troves; use this to build the group for a specific version of rPath Linux |
Group Hierarchy
Some packagers may want to create a hierarchy of groups defining an installed system, such as when developing appliances. Each group may be created with a separate group recipe and assembled in another recipe defining the system. Another approach is to write a single group recipe that includes the creation of its subgroups. Use the startGroup action to start new subgroups, and note that until the next startGroup, all lines will apply to that group:
def setup(r): r.startGroup('group-sql-server', parentGroup='group-smf') r.add('mysql') r.add('mysql-server')
The startGroup definition exists in group-appliance and group-dist from rPath Linux and its derivative distributions. Most appliance builders will be building with those groups. The definition is as follows and can be used in recipes for groups that will not be built with group-appliance or group-dist:
def startGroup(r, name, parentGroup, depCheck=False, byDefault=True):
r.setDefaultGroup(parentGroup)
r.createGroup(name, autoResolve=autoResolve, depCheck=depCheck, byDefault=True)
r.addNewGroup(name, groupName=parentGroup, byDefault=byDefault)
r.setDefaultGroup(name)
Group Recipe Redirect
A Conary group redirect recipe is a way to point existing users to a completely different set of groups on a (possibly) different label. It can be used for major version updates (for example: updates.example.com@ex:product-3 -> updates.example.com@ex:product-4).
The following example assumes multiple groups making up one appliance. The top-level group is group-product-dist, which in turn contains group-product and group-product-core. All three groups are then redirected to the same group name on the new label: updates.example.com@ex:product-4:
class GroupProductDist(RedirectRecipe): name = 'group-product-dist' version = '0' def setup(r): for x in ['group-product', 'group-product-core', 'group-product-dist']: r.addRedirect(x, 'updates.example.com@ex:product-4', fromTrove = x)
In this example, any user updating a system currently on @ex:product-3 will be automatically redirected to the new groups on the new label when upgrading or installing.
If flavors are also different between the source and target of the redirect, such as redirecting from a vmware-flavored group to a non-vmware-flavored group, also add arguments sourceFlavor='vmware is:x86', targetFlavor='~!vmware is:x86'.
Group Scripts
Starting with version 1.1.20, Conary includes the group script feature for group recipes to run scripts when Conary install, update, and rollback commands are performed on the group. This feature is available for groups only (not for packages). The following shows example syntax for including group scripts in a group recipe:
class GroupExample(GroupRecipe) name = 'group-example' def setup(r): r.addPreUpdateScript(contents = '''#!/bin/bash echo now > /tmp/state ''') r.setCompatibilityClass(2, groupName = 'group-example') r.addPostInstallScript(contents = '''#!/bin/bash echo now > /tmp/state ''', groupName = 'group-example') r.addPostUpdateScript(contents = '''#!/bin/bash echo now > /tmp/state ''') r.addPostRollbackScript(contents = '''#!/bin/bash echo now > /tmp/state ''', toClass = 1)
Methods
Developers can use one of each kind of script per group: one for the group created by the group recipe, and one for each additional group created in the group recipe. Use the following methods to include group scripts:
| setCompatibilityClass(<compatibility class>, groupName = <sub-group name>) | Set the compatibility class of the group groupName is an optional argument to attach the script to an additional group created in the recipe (the default group can be set by r.setDefaultGroup()) Read more |
| addPreUpdateScript(contents = <script>, groupName = <sub-group name>) | Run the script when a Conary update is launched on the group, before Conary starts the update groupName is an optional argument to attach the script to an additional group created in the recipe (the default group can be set by r.setDefaultGroup()) Read more |
| addPostInstallScript(contents = <script>, groupName = <sub-group name>) | Run the script after the group is initially installed groupName is an optional argument to attach the script to an additional group created in the recipe (the default group can be set by r.setDefaultGroup()) Read more |
| addPostUpdateScript(contents = <script>, groupName = <sub-group name>) | Run the script after a Conary update on the group groupName is an optional argument to attach the script to an additional group created in the recipe (the default group can be set by r.setDefaultGroup()) Read more |
| addPostRollbackScript(contents = <script>, groupName = <sub-group name>, toClass = <compatibility class>) | Run the script after a Conary rollback on the group groupName is an optional argument to attach the script to an additional group created in the recipe (the default group can be set by r.setDefaultGroup()) Read more toClass is an optional argument to define which compatibility classes (default value is 0) Read more |
Script Syntax
The script uses Python's multiple-line quote syntax (triple single quotes) to allow the contents to span multiple lines.
r.addPreUpdateScript(contents = '''#!/bin/bash echo now > /tmp/state ''')
Be aware that the syntax between the triple single quotes is independent of Python formatting and should reflect the desired contents of the script. For example, there should be no newline after the opening triple single quotes and before the line defining the shell interpreter ("shebang"). Also, Python's normal indentation is not necessary between the triple single quotes.
Group Name
Use groupName, optional in each function, to attach the script to an additional group defined in the recipe, such as a sub-group or related group. If a groupName value is not specified, the script is attached to the primary group associated with the recipe.
r.addPostInstallScript(contents = <script>, groupName = 'group-example')
Compatibility Classes
Compatibility classes can be set in a group to instruct Conary what rollbacks a group should be able to perform. If no compatibility class is specified, it is assumed to be zero (0). Because of this assumption, all groups created without setCompatibilityClass are in compatibility class zero.
Use setCompatibilityClass with the compatibility class value that should be associated with this version of the group recipe.
Use the toClass optional argument for addPostRollbackScript to declare which compatibility classes in previous group versions can keep their rollbacks available if they are updated to this group version. If the group that is updated to this version is of a compatibility class not specified in this version, the rollbacks will be invalidated, making them no longer available for Conary (or rAP) rollback operations.
For example, suppose this group version is set to compatibility class 2 and has a post rollback script with toClass with the single value of 1:
r.setCompatibility(2, groupName = 'group-example') r.addPostRollbackScript(contents=<script>, toClass = 1)
The following results would occur if groups of compatibility classes 0 and 1 update to this group version:
- If the group is updated from compatibility class 0, the rollbacks would be invalidated and no longer available. Rollback data is preserved even though rollbacks are unavailable.
- If the group is updated from compatibility class 1, the rollbacks would be available.
Scripts are run regardless of the compatibility classes defined. Developers should use the environment variables to determine if compatibility class has changed.
If the post-rollback script handles multiple compatibility classes, the toClass argument can be a list of integers.
Execution Process
Conary writes all scripts to its temporary directory (set to /tmp) and executes them from there.
Script Actions During Updates
The pre update script always runs before any update that includes the group. Pre update scripts run in an undetermined order, though all pre update scripts attached to a group will execute before those attached to its subgroups.
Only one of the post scripts runs, based on the action taken in Conary (install, update, or rollback). The database is available for Conary query operations while pre and post scripts are running.
No scripts are executed at the time of a rollback. The post rollback script follows the rollback, and the script version that is run is determined by the group version prior to the rollback. For example, if version 2 is rolled back to version 1, the version 2 rollback script is run.
Reference how group scripts fit into the process of updating a group.
| Conary group redirects are always considered new group installs, even if the group name is the same as a currently installed group. |
Scripts are run only if they are provided in the update target. If an installed group does not have a script, but an update to the group includes one or more scripts, the new scripts are run as provided in the group recipe (including any pre update scripts). Likewise, if an installed group has scripts, but an update to the group does not, no scripts are run.
Points of Failure Considerations
Scripts must return an exit code of 0 to indicate success; any other value is interpreted as a failure. Consider these other points of failure:
- If an install fails for a package in the group, the entire update operation is aborted, and Conary takes no further actions. If a pre-update script is associated with a group that has not yet been updated, the pre-script will be re-executed when the update process is restarted.
- If a pre-update script fails, the entire update operation is aborted, and Conary takes no further actions. Since a pre-update script can possibly run several times, the developer should take care to write pre-update scripts in a manner that makes them robust when run multiple times.
- Failures in post scripts are ignored, though they are reported to the user.
Environment Variables
Recall that a group is unique given its Conary name, version, and flavor. These environment variables are set during the run of all scripts:
- CONARY_NEW_NAME
- CONARY_NEW VERSION
- CONARY_NEW_FLAVOR
- CONARY_NEW_COMPATIBILITY_CLASS
These environment variables are set during the run of all scripts when an installed (old) group is updated or rolled back:
- CONARY_OLD VERSION
- CONARY_OLD_FLAVOR
- CONARY_OLD_COMPATIBILITY_CLASS
The PATH environment variable for all scripts is set to /usr/bin:/usr/sbin:/bin:/sbin. No additional environment variables are set unless they are set by the script itself or the script interpreter.
Conary Developer Notes
If a root is specified during an update (using --root), scripts are executed in a change root (chroot) if the process is running as root. Otherwise the scripts are silently ignored.
Use --tag-script <filename> with a conary update command to write all scripts to /tmp and to generate the tag script file <filename> to run them. When the option is used, the tag script file and group scripts are not run. Also, pre script invocations are commented out in the tag script as they are normally used for initial installs.
Pre script invocations should be self contained. A group script can be updated from any previous version (including absolutely nothing for a fresh install). Making assumptions about what libraries will be available leads to errors. A pre-update script failure prevents the group from being installed (see Points of Failure Considerations)
