Example initialize And finalize Scripts
Example initialize And finalize Scripts
The node-installer executes any initialize and finalize scripts at particular stages of its 13-step run during node-provisioning (section 5.4). They are sometimes useful for troubleshooting or workarounds during those stages. The scripts are stored in the CMDaemon database, rather than in the filesystem as plain text files, because they run before the node’s init process takes over and establishes the final filesystem.
Default initialize and finalize scripts are provided with the default category:
E.1 When Are They Used?
The initialize and finalize scripts are sometimes used as an alternative configuration option out of a choice of other possible options (section 3.20.1). As a solution it can be a bit of a hack, but sometimes there is no reasonable alternative other than using an initialize or finalize script.
An initialize script: is used well before the init process starts, to execute custom commands before partitions and mounting devices are checked. Typically, initialize script commands are related to partitioning, mounting, or initializing special storage hardware. Often an initialize script is needed because the commands in it cannot be stored persistently anywhere else.
A finalize script: (also run before init, but shortly before init starts) is used to set a file configuration or to initialize special hardware, sometimes after a hardware check. It is run in order to make software or hardware work before, or during the later init stage of boot. Thus, often a finalize script is needed because its commands must be executed before init, and the commands cannot be stored persistently anywhere else, or it is needed because a choice between (otherwise non-persistent) configuration files must be made based on the hardware before init starts.
E.2 Accessing From Base View And cmsh
The initialize and finalize scripts are accessible for viewing and editing:
-
In Base View, via the
Node CategoriesorNodeswindow, under theSettingswindow. The navigation paths for these are:-
Grouping>Node categories[default]>Edit>Settings -
Devices>Nodes[node001]>Edit>Settings
-
-
In
cmsh, using thecategoryordevicemodes. Thegetcommand is used for viewing the script, and thesetcommand to start up the default text editor to edit the script. Output is truncated in the two following examples at the point where the editor starts up:Example
Example
E.3 Environment Variables Available To initialize And finalize Scripts
When CMDaemon is fully up, the environment variables available to CMDaemon scripts are fully available and can be listed by the CMDaemon front-ends (here).
That full range of environment variables is not available for initialize and finalize scripts, since only a subset of the full environment is defined during the stages associated with the scripts.
For the initialize and finalize scripts, node-specific customizations can still be made from a script using the environment variables that are available. For initialize scripts, this is discussed briefly in section E.5.1.
For finalize scripts, the available environment variables can be listed using the following script as a finalizescript:
Example
After the node comes up, the contents of the saved file on that node are the available variables:
Example
The following table shows the available variables with some example values:
* The value for this variable is a string with spaces, not an array. Eg:
CMD_FSMOUNTS=“_SLASH_dev_SLASH_pts _SLASH_proc _SLASH_sys _SLASH_dev_SLASH_shm …”
** The name of this variable varies according to the interfaces available. So,
eth0 can be replaced by eth1, eth2, ipmi0, and so on.
E.4 Using Environment Variables Stored In Multiple Variables
Some data values, such as those related to interfaces (CMD_INTERFACES_*), mount points (CMD_FSMOUNT__SLASH_*) and exports (CMD_FSEXPORT__SLASH_cm__SLASH_node-installer_*) are stored in multiple variables. The following finalize script set for node001 shows how they can be used:
Example
The technique of storage of values in a file under the path within the node of /localdisk/ is described later on in section E.5.2. When the node boots up and runs the finalize script, then files stored under /localdisk/, end up under the path of / after the node is fully up.
The detailed workings of the parser function in the preceding bash script are not easy, but the result is that the parser function returns output so that the interface type, IP address, and netmask are listed for each interface. The parser works for physical interfaces, VLAN interfaces, and alias interfaces. For example, if there are two interfaces, eth0 and eth0:1, then the file env might be seen to have the following data:
Example
For remotely mounted devices, the name of the environment variables for mount entries have the following naming convention:
For the names, the entries <x> are substituted with the local mount point path, such as “/cm/shared”, but with the “/” character replaced with the text “_SLASH_”. So, for a local mount point path “/cm/shared”, the name of the associated volume environment variable becomes CMD_FSMOUNT__SLASH_cm_SLASH_shared_DEVICE.
A similar naming convention is applicable to the names of the environment variables for the export entries:
Here, the entry <y> is replaced by the file path to the exported filesystem on the exporting node. This is actually the same as the value of “CMD_FSMOUNT_ <y>_PATH”, but with the “/” character replaced with the text “_SLASH_”.
The entries for the local mount values and the export values in the table in section E.3 are the default values for a newly installed cluster. If the administrator wishes to add more devices and mount entries, this is done by configuring fsexports on the head node, and fsmounts on the regular nodes, using Base View or cmsh (section 3.13).
E.5 Storing A Configuration To A Filesystem
E.5.1 Storing With Initialize Scripts
The initialize script (section 5.4.5) runs after the install-mode type and execution have been determined (section 5.4.4), but before unloading specific drivers and before partitions are checked and filesystems mounted (section 5.4.6). Data output cannot therefore be written to a local drive. It can however be written by the script to the tmpfs, but data placed there is lost quite soon, namely during the pivot_root process that runs when the node-installer hands over control to the init process running from the local drive. However, if needed, the data can be placed on the local drive later by using the finalize script to copy it over from the tmpfs.
Due to this, and other reasons, a finalize script is easier to use for an administrator than an initialize script, and the use of the finalize script is therefore preferred.
E.5.2 Ways Of Writing A Finalize Script To Configure The Destination Nodes
E.5.2.1 Basic Example—Copying A File To The Image
For a finalize script (section 5.4.11), which runs just before switching from using the ramdrive to using the local hard drive, the local hard drive is mounted under /localdisk. Data can therefore be written to the local hard drive if needed, but is only persistent until a reboot, when it gets rewritten. For example, predetermined configuration files can be written from the NFS drive for a particular node, or they can be written from an image prepared earlier and now running on the node at this stage, overwriting a node-installer configuration:
Example
This technique is used in a finalize script example in section 3.20.4, except that an append operation is used instead of a copy operation, to overcome a network issue by modifying a network configuration file slightly.
There are three important considerations for most finalize scripts:
-
Running A Finalize Script Without
exit 0Considered HarmfulFailed Finalize Script Logic Flow: For a default configuration without a finalize script, if PXE boot fails from the network during node provisioning, the node then goes on to attempt booting from the local drive via iPXE (section 5.1.2).
However, if the configuration has a finalize script, such as in the preceding example, and if the finalize script fails, then the failure is passed to the node-installer.
Avoiding Remote Node Hang During A Finalize Script:
exit 0Recommended: If the node-installer fails, then no attempt is made to continue booting, and the node remains hung at that stage. This is usually undesirable, and can also make remote debugging of a finalize script annoying.Adding an
exit 0to the end of the finalize script is therefore recommended, and means that an error in the script will still allow the node-installer to continue with an attempt to boot from the local drive.Debugging Tips When A Node Hangs During A Finalize Script: If there is a need to understand the failure, then if the node-installer hangs, the administrator can ssh into the node into the node-installer environment, and run the finalize script manually to debug it. Once the bug has been understood, the script can be copied over to the appropriate location in the head node, for nodes or categories.
Additional aid in understanding a failure may be available by looking through the node-installer logs. The debug mode for the node-installer can be enabled by setting
debug=trueinstead ofdebug=falsein the file/cm/node-installer/scripts/node-installer.conf(for multiarch/multidistro configurations the path takes the form:/cm/node-installer-<distribution>-<architecture>/scripts/node-installer.conf).Another way to help debug a failure could be by setting custom event messages in the script, as explained here.
-
Protecting A Configuration File Change From Provisioning Erasure With
excludelistupdateIn the preceding example, the finalize script saves a file
/etc/myapp.confto the destination nodes.To protect such a configuration file from erasure, its file path must be covered in the second sublist in the
excludelistupdatelist (section 5.6.1). -
Finalize scripts cannot modify
/proc,/sys, and/devfilesystems of end result on node directly.The
/proc,/sys, and/devfilesystems are unmounted after the finalize script is run before pivoting into the root filesystem under the/localdiskdirectory, which means any changes made to them are simply discarded. To change values under these filesystems on the node, anrc.localfile inside the software image can be used.For example, if swappiness is to be set to 20 via the
/procfilesystem, one way to do it is to set it in therc.localfile:Example
The preceding way of using
rc.localset to run a command to modify the image just for illustration. A better way to get the same result in this case would be to not involverc.local, but to add a line within the/cm/images/<image-name>/etc/sysctl.conffile:vm.swappiness = 20
E.5.2.2 Copying A File To The Image—Decision Based On Detection
Detection within a basic finalize script is useful extra technique. The finalize script example of section 3.20.4 does detection too, to decide if a configuration change is to be done on the node or not.
A further variation on a finalize script with detection is a script selecting from a choice of possible configurations. A symlink is set to one of the possible configurations based on hardware detection or detection of an environment variable. The environment variable can be a node parameter or similar, from the table in section E.3. If it is necessary to overwrite different nodes with different configurations, then the previous finalize script example might become something like:
Example
In the preceding example, the configuration file in the image has several versions: /etc/myapp.conf.<first|second|third>. Nodes node001 to node007 are configured with the first version, nodes node015 to node018 with the second version, and nodes node023 to node026 with the third version. It is convenient to add more versions to the structure of this decision mechanism.
E.5.2.3 Copying A File To The Image—With Environment Variables Evaluated In The File
Sometimes there can be a need to use the CMDaemon environment variables within a finalize script to specify a configuration change that depends on the environment.
For example a special service may need a configuration file, test, that requires the hostname myhost, as a parameter=value pair:
Example
Ideally the placeholder value myhost would be the hostname of the node rather than the fixed value myhost. Conveniently, the CMDaemon environment variable CMD_HOSTNAME has the name of the host as its value.
So, inside the configuration file, after the administrator changes the host name from its placeholder name to the environment variable:
then when the node-installer runs the finalize script, the file could be modified in-place by the finalize script, and ${CMD_HOSTNAME} be substituted by the actual hostname.
A suitable finalize Bash script, which runs an in-line Perl substitution, is the following:
Here, /some/directory/file means that, if for example the final configuration file path for the node is to be /var/spool/test then the file name should be set to /localdisk/var/spool/test inside the finalize script.
The finalize script replaces all lines within the file that have environment variable names of the form:
with the value of that environment variable. Thus, if <environment variable name> is CMD_HOSTNAME, then that variable is replaced by the name of the host.
E.5.3 Restricting The Script To Nodes Or Node Categories
As mentioned in section 2.1.3, node settings can be adjusted within a category. So the configuration changes to ifcfg-eth0 is best implemented per node by accessing and adjusting the finalize script per node if only a few nodes in the category are to be set up like this. If all the nodes in a category are to be set up like this, then the changes are best implemented in a finalize script accessed and adjusted at the category level. Accessing the scripts at the node and category levels is covered in section E.2.
People used to normal object inheritance behavior should be aware of the following when considering category level and node level finalize scripts:
With objects, a node item value overrules a category level value. On the other hand, finalize scripts, while treated in an analogous way to objects, cannot always inherit properties from each other in the precise way that true objects can. Thus, it is possible that a finalize script run at the node level may not have anything to do with what is changed by running it at the category level. However, to allow it to resemble the inheritance behavior of object properties a bit, the node-level finalize script, if it exists, is always run after the category-level script. This gives it the ability to “overrule” the category level.