The Oracle VM Guest Additions include a set of packages that can help with the automatic configuration of virtual machine as they are created from a template and booted for the first time. The master package for this facility is known as ovm-template-config. The Oracle VM template configuration script can be used to configure a virtual machine remotely using the Oracle VM messaging facility via ovmd.
The Oracle VM Template Configuration Script,
ovm-template-config works in conjunction with a
set of modular configuration scripts that function in a manner very
similar to the standard Linux System V, init.d
and chkconfig
, script model. Control over how
configuration modules are run is handled within the
/etc/template.d
directory on the
guest virtual
machine. The configuration module scripts are stored in
/etc/template.d/scripts
.
The ovm-template-config script is the master
script that is used to control all enabled modules. Running
ovm-template-config with the
--help
parameter provides a usage breakdown.
For remote configuration, ovm-template-config is
used in conjunction with ovmd to capture
configuration parameters that have been sent to the guest using the
Oracle VM messaging facility. When this is the case,
ovm-template-config targets are presented to
ovmd as --script
parameters:
# ovmd -s cleanup # ovmd -s configure
When performing remote configuration, using ovmd to process messages containing configuration keys, the authentication module must be enabled. Processing of messages can only be completed if the final message contains the root user password. See Section 8.8.2, “Enabling and Disabling Configuration Modules (ovm-chkconfig)” for more information on this module.
See Section 8.8.4, “Triggering Configuration Changes” for more information on calling this script directly.
Syntax
ovm-template-config
[
-e
|
--enumerate
] [
--human-readable
] [
{
-i
|
--input=
}
] [
{
input
-o
|
--output=
}
] [
output
--stdin
] [
--console-input
] [
--ovf-transport-iso
] [
{
-s
|
--script=
}
] [
script
--logfile=
] [
logfile
--loglevel=
] [
loglevel
--version
] [
{
-h
|
--help
}
]
target
Where
is:
target
{
configure
|
unconfigure
|
reconfigure
|
cleanup
|
suspend
|
resume
|
migrate
|
shutdown
}
Options
The following table shows the available options for this command.
Option | Description |
---|---|
[
|
Enumerate the parameters for
|
| Print in human readable format when enumerate parameters. |
{
| Input parameters from this file descriptor. |
{
| Output parameters to this file descriptor. |
|
Build parameters from |
| Build parameters from the console input. |
| Build parameters from the OVF transport ISO. |
{
| Specify a script. |
| Set the name of the log file. |
| Set the logging level. |
| Show the ovm-template-config script version number and exit. |
{
| Show help on the ovm-template-config command options. |
Examples
Example 8.8 Listing the key pairs in configuration modules
# ovm-template-config --enumerate configure
Example 8.9 Listing the key pairs specific to the network configuration module
# ovm-template-config --enumerate --script network configure
Example 8.10 Passing configuration information to the script from STDIN
# ovm-template-config --stdin configure
Example 8.11 Passing configuration information from the command line prompt (prompting for values)
# ovm-template-config --console-input configure
Example 8.12 Passing configuration information from an OVF transport mounted on a CDROM device
# ovm-template-config --ovf-transport-iso configure
When a module is enabled, symlinks to the module script are made to
other subdirectories within /etc/template.d
based on the type of target the module provides, in much the same
way that the System V init
process works. When
a module gets added, the header of the module script is read to
verify the name, priority and targets and then a symlink is made to
the corresponding subdirectories under
/etc/template.d
.
Enabling and disabling targets for any module is handled using the
ovm-chkconfig script. Usage of this command is
outlined using the --help
parameter.
Syntax
ovm-chkconfig
[
--list
[
]
] [
name
--add
] [
name
--del
] [
name
--target=
...
target
{
name
on
|
off
}
] [
--version
] [
{
-h
|
--help
}
]
Where
is:
target
{
configure
|
unconfigure
|
reconfigure
|
cleanup
|
suspend
|
resume
|
migrate
|
shutdown
}
Options
The following table shows the available options for this command.
Option | Description |
---|---|
[
|
Lists the status of the script
|
[
|
Add a new script |
[
|
Delete a script |
[
|
Specify the
|
| Show the ovm-chkconfig script version number and exit. |
{
| Show help on the ovm-chkconfig command options. |
Examples
Example 8.13 Listing available modules and their target runtime status
# ovm-chkconfig --list name configure unconfigure reconfigure cleanup suspend resume migrate shutdown authentication on:90 off off off off off off off datetime on:50 off off off off off off off firewall on:41 off off off off off off off network off off off off off off off off selinux off off off off off off off off ssh off off off off off off off off system off off off off off off off off user off off off off off off off off
To obtain a full listing of all of the key pairs that are used to trigger configuration changes through the ovm-template-config configuration modules, run the following command on the guest system where ovm-template-config is installed:
# ovm-template-config --human-readable --enumerate configure
The output from this command is printed as a Python data structure,
that is easy to parse and understand. Content can be limited to the
information specific to a configuration module by using the
--script
parameter as presented below:
# ovm-template-config --human-readable --enumerate configure --script datetime [('50', 'datetime', [{u'description': u'System date and time in format year-month-day-hour-minute-second, e.g., "2011-4-7-9-2-42".', u'hidden': True, u'key': u'com.oracle.linux.datetime.datetime'}, {u'description': u'System time zone, e.g., "America/New_York".', u'hidden': True, u'key': u'com.oracle.linux.datetime.timezone'}, {u'description': u'Whether to keep hardware clock in UTC: True or False.', u'hidden': True, u'key': u'com.oracle.linux.datetime.utc'}, {u'description': u'Whether to enable NTP service: True or False.', u'hidden': True, u'key': u'com.oracle.linux.datetime.ntp'}, {u'description': u'NTP servers separated by comma, e.g., "time.example.com,0.example.pool.ntp.org".', u'hidden': True, u'key': u'com.oracle.linux.datetime.ntp-servers'}, {u'description': u'Whether to enable NTP local time source: True or False.', u'hidden': True, u'key': u'com.oracle.linux.datetime.ntp-local-time-source'}])]
From the output, it becomes clear as to which configuration modules are triggered at which runlevel and what keys and values they accept. Note that all key names are structured so that they are prefixed with com.oracle, to avoid conflicts with any custom modules that you may intend to develop for your own purposes.
Key value pairs are actually passed to ovm-template-config in JSON format:
{"com.oracle.linux.datetime.ntp":"True"} {"com.oracle.linux.datetime.ntp-servers":"0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org"} {"com.oracle.linux.root-password":"mysecret"}
There are a variety of approaches that can be used to trigger a configuration change using ovm-template-config. Most commonly, this is done by setting the ovmd service to run using in enable-initial-config mode. This causes the virtual machine to wait to be provided with configuration parameters either on via the console, or via the ovmd messaging facility, after the next boot. This is the usual approach when configuring a virtual machine to act as a template.
To manually force ovmd to pass messages to the
ovm-template-config script, simply run
ovmd with the --script
parameter
set to point to one of the ovm-template-config
targets:
# ovmd --list
{"com.oracle.linux.datetime.ntp":"True"}
{"com.oracle.linux.datetime.ntp-servers":"0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org"}
{"com.oracle.linux.root-password":"password
"}
# ovmd -s configure
To perform an action using messaging parameters and ovm-template-config, the authentication module must be enabled and your final message should include an authentication request in the form of a key-value message:
{"com.oracle.linux.root-password":"password
"}
When running ovmd like this, ovmd prepares two pipes (infd and outfd) and calls the ovm-template-config script transparently in the background in the following way:
# ovm-template-config --input <infd> --output <outfd> configure
During testing, it may be useful to simply pass configuration
information directly to the script from STDIN on the command line.
This can be achieved by calling the script directly with the
--stdin
parameter:
# ovm-template-config --stdin configure <<EOF > {"com.oracle.linux.selinux.mode": "disabled"} > {"com.oracle.linux.root-password": "ovsroot"} > EOF
Configuration can also be achieved directly from the console by
running the script using the --console-input
option. Doing this will prompt you for values for each of the keys
that need to be defined for any enabled modules:
# ovm-template-config --console-input configure
The provided module scripts are developed in Python. Theoretically, it is possible to develop module scripts in a different language, as long as the input, output and argument handling remains the same. The example provided in this section makes use of the Python programming language.
Each module script consists of two main parts:
The script header, which contains information like script name, targets, priorities and description.
The actual script, which handles a small set of parameters.
For examples of functional module scripts, refer to the existing
modules in the /etc/template.d/scripts
directory.
Module Script Header
Module script headers require a very specific comment block in order for ovm-chkconfig to handle enabling and disabling your script functionality. The format for the script header is as follows:
### BEGIN PLUGIN INFO # name: [script name] # [target]: [priority] # [target]: [priority] # description: a description that can # cross multiple lines. ### END PLUGIN INFO
When developing your own module script, you must include a header following the exact same format. Provide your own script name, which will be used when calling ovm-chkconfig, the targets that your script will support, and the priority for your script. The priority will specify in what order the script gets executed. You do not have to implement all targets. If you have a configure target but no cleanup target, this is still acceptable. The configure target gets called when a first boot/initial start of the virtual machine happens. The cleanup target happens when you manually initiate a cleanup in your virtual machine or when you want to restore the virtual machine to its original state. An example of the network module script header is provided below:
### BEGIN PLUGIN INFO # name: network # configure: 50 # cleanup: 50 # description: Script to configure template network. ### END PLUGIN INFO
Module Script Body
The main requirement for the module script body is that it accepts at least one target parameter. Target parameters that might get presented by the ovm-template-configure script include:
configure
unconfigure
reconfigure
cleanup
suspend
resume
migrate
shutdown
Your script can handle any other arguments that you require. There
is one optional parameter which is useful to implement and this is
-e
or --enumerate
.
ovm-template-config uses this to be able to
enumerate or list the parameters for a target supported by your
script.
A very basic template to use for your script body follows:
try: import json except ImportError: import simplejson as json from templateconfig.cli import main def do_enumerate(target): param = [] if target == 'configure': param += [] elif target == 'cleanup': param += [] return json.dumps(param) def do_configure(param): param = json.loads(param) return json.dumps(param) def do_cleanup(param): param = json.loads(param) return json.dumps(param) if __name__ == '__main__': main(do_enumerate, {'configure': do_configure, 'cleanup': do_cleanup})
This script supports the configure and cleanup targets.
You can fill out the script with your own code. For instance, for
the do_enumerate
function, you would populate the
parameters that are supported for each target in the script. An
example from the firewall module is presented below:
def do_enumerate(target): param = [] if target == 'configure': param += [{'key': 'com.oracle.linux.network.firewall', 'description': 'Whether to enable network firewall: True or False.', 'hidden': True}] return json.dumps(param)
Each target function begins by reading the JSON parameters passed to
the script, using the param = json.loads(param)
statement. From this point, code can be written to perform actions
based on the values of the keys that the script expects to receive.
Once again, the example provided below is from the firewall module:
def do_configure(param): param = json.loads(param) firewall = param.get('com.oracle.linux.network.firewall') if firewall == 'True': shell_cmd('service iptables start') shell_cmd('service ip6tables start') shell_cmd('chkconfig --level 2345 iptables on') shell_cmd('chkconfig --level 2345 ip6tables on') elif firewall == 'False': shell_cmd('service iptables stop') shell_cmd('service ip6tables stop') shell_cmd('chkconfig --level 2345 iptables off') shell_cmd('chkconfig --level 2345 ip6tables off') return json.dumps(param)
Module Script Packaging
Once you have written one or more configuration module scripts, you
may want to package them as RPMs that can be deployed on other
systems. In order to install and configure template configure
scripts, they have to be packaged in an RPM, with a specific naming
convention. Package the script as
ovm-template-config-[scriptname]
. Ideally in
the post install of the RPM you should add the script automatically
by executing # /usr/sbin/ovm-chkconfig --add
. When uninstalling a
script/RPM, remove it at uninstall time using scriptname
#
/usr/sbin/ovm-chkconfig --del
. This is illustrated
in the following example of an RPM spec file that can be used:
scriptname
Name: ovm-template-config-example Version: 3.0 Release: 1%{?dist} Summary: Oracle VM template example configuration script. Group: Applications/System License: GPL URL: http://www.oracle.com/virtualization Source0: %{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) BuildArch: noarch Requires: ovm-template-config %description Oracle VM template example configuration script. %prep %setup -q %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT %clean rm -rf $RPM_BUILD_ROOT %post if [ $1 = 1 ]; then /usr/sbin/ovm-chkconfig --add example fi %preun if [ $1 = 0 ]; then /usr/sbin/ovm-chkconfig --del example fi %files %defattr(-,root,root,-) %{_sysconfdir}/template.d/scripts/example %changelog * Tue Mar 22 2011 John Smith - 3.0-1 - Initial build.
Edit the example spec file to reference your own script name.
In order to create RPMs, you must install
rpmbuild
:
# yum install rpm-build
The following is an example Makefile that you might assist in automating the build process:
You must edit this Makefile to reference your own script.
DESTDIR= PACKAGE=ovm-template-config-example VERSION=3.0 help: @echo 'Commonly used make targets:' @echo ' install - install program' @echo ' dist - create a source tarball' @echo ' rpm - build RPM packages' @echo ' clean - remove files created by other targets' dist: clean mkdir $(PACKAGE)-$(VERSION) tar -cSp --to-stdout --exclude .svn --exclude .hg --exclude .hgignore \ --exclude $(PACKAGE)-$(VERSION) * | tar -x -C $(PACKAGE)-$(VERSION) tar -czSpf $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION) rm -rf $(PACKAGE)-$(VERSION) install: install -D example $(DESTDIR)/etc/template.d/scripts/example rpm: dist rpmbuild -ta $(PACKAGE)-$(VERSION).tar.gz clean: rm -fr $(PACKAGE)-$(VERSION) find . -name '*.py[cdo]' -exec rm -f '{}' ';' rm -f *.tar.gz .PHONY: dist install rpm clean
Create a working directory, copy over your script, the spec file and the Makefile. Run the following command to create a src tarball of your code:
# make dist
Run the following command to generate an RPM file:
# make rpm
The preceding command generates an RPM in the
RPMS/noarch
directory within your working
directory, for example:
RPMS/noarch/ovm-template-config-test-3.0-1.el6.noarch.rpm
.