9a166b9df6
Having data files in the phase subdirs is an easy source of confusion in reviews (especially when the data file is a script) and theres really no reason to be putting data files there at this point. Lets make a convention out of not doing this. Change-Id: I99571a2a49e14e8c709af20f6d13d662ac745eb4
320 lines
13 KiB
ReStructuredText
320 lines
13 KiB
ReStructuredText
Developing Elements
|
|
===================
|
|
|
|
Conform to the following conventions:
|
|
|
|
* Use the environment for overridable defaults, prefixing environment variable
|
|
names with "DIB\_". For example: DIB\_MYDEFAULT=${DIB\_MYDEFAULT:-default}
|
|
If you do not use the DIB\_ prefix you may find that your overrides are
|
|
discarded as the build environment is sanitised.
|
|
|
|
* Consider that your element co-exists with many others and try to guard
|
|
against undefined behaviours. Some examples:
|
|
|
|
* Two elements use the source-repositories element, but use the same filename
|
|
for the source-repositories config file. Files such as these (and indeed the
|
|
scripts in the various .d directories listed below) should be named such
|
|
that they are unique. If they are not unique, when the combined tree is
|
|
created by disk-image-builder for injecting into the build environment, one
|
|
of the files will be overwritten.
|
|
|
|
* Two elements copy different scripts into /usr/local/bin with the same name.
|
|
If they both use set -e and cp -n then the conflict will be caught and cause
|
|
the build to fail.
|
|
|
|
* If your element mounts anything into the image build tree ($TMP\_BUILD\_DIR)
|
|
then it will be automatically unmounted when the build tree is unmounted -
|
|
and not remounted into the filesystem image - if the mount point is needed
|
|
again, your element will need to remount it at that point.
|
|
|
|
Phase Subdirectories
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Make as many of the following subdirectories as you need, depending on what
|
|
part of the process you need to customise. The subdirectories are executed in
|
|
the order given here. Scripts within the subdirectories should be named with a
|
|
two-digit numeric prefix, and are executed in numeric order. Only files which
|
|
are marked executable (+x) will be run, so other files can be stored in these
|
|
directories if needed. As a convention, we try to only store executable scripts
|
|
in the phase subdirectories and store data files elsewhere in the element.
|
|
|
|
* root.d: Create or adapt the initial root filesystem content. This is where
|
|
alternative distribution support is added, or customisations such as
|
|
building on an existing image.
|
|
|
|
Only one element can use this at a time unless particular care is taken not
|
|
to blindly overwrite but instead to adapt the context extracted by other
|
|
elements.
|
|
|
|
* runs: outside chroot
|
|
* inputs: $ARCH=i386|amd64|armhf $TARGET\_ROOT=/path/to/target/workarea
|
|
|
|
* extra-data.d: pull in extra data from the host environment that hooks may
|
|
need during image creation. This should copy any data (such as SSH keys,
|
|
http proxy settings and the like) somewhere under $TMP\_HOOKS\_PATH.
|
|
|
|
* runs: outside chroot
|
|
* inputs: $TMP\_HOOKS\_PATH
|
|
* outputs: None
|
|
|
|
* pre-install.d: Run code in the chroot before customisation or packages are
|
|
installed. A good place to add apt repositories.
|
|
|
|
* runs: in chroot
|
|
|
|
* install.d: Runs after pre-install.d in the chroot. This is a good place to
|
|
install packages, chain into configuration management tools or do other
|
|
image specific operations.
|
|
|
|
* runs: in chroot
|
|
|
|
* post-install.d: Run code in the chroot. This is a good place to perform
|
|
tasks you want to handle after the OS/application install but before the
|
|
first boot of the image. Some examples of use would be: Run chkconfig
|
|
to disable unneeded services and clean the cache left by the package
|
|
manager to reduce the size of the image.
|
|
|
|
* runs: in chroot
|
|
|
|
* block-device.d: customise the block device that the image will be made on
|
|
(e.g. to make partitions). Runs after the target tree has been fully
|
|
populated but before the cleanup hook runs.
|
|
|
|
* runs: outside chroot
|
|
* inputs: $IMAGE\_BLOCK\_DEVICE={path} $TARGET\_ROOT={path}
|
|
* outputs: $IMAGE\_BLOCK\_DEVICE={path}
|
|
|
|
* finalise.d: Perform final tuning of the root filesystem. Runs in a chroot
|
|
after the root filesystem content has been copied into the mounted
|
|
filesystem: this is an appropriate place to reset SELinux metadata, install
|
|
grub bootloaders and so on. Because this happens inside the final image, it
|
|
is important to limit operations here to only those necessary to affect the
|
|
filesystem metadata and image itself. For most operations, post-install.d
|
|
is preferred.
|
|
|
|
* runs: in chroot
|
|
|
|
* cleanup.d: Perform cleanup of the root filesystem content. For
|
|
instance, temporary settings to use the image build environment HTTP proxy
|
|
are removed here in the dpkg element.
|
|
|
|
* runs: outside chroot
|
|
* inputs: $ARCH=i386|amd64|armhf $TARGET\_ROOT=/path/to/target/workarea
|
|
|
|
Other Subdirectories
|
|
^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Elements may have other subdirectories that are processed by specific elements
|
|
rather than the diskimage-builder tools themselves.
|
|
|
|
One example of this is the ``bin`` directory. The ``rpm-distro``, ``dpkg`` and
|
|
``opensuse`` elements install all files found in the ``bin`` directory into
|
|
``/usr/local/bin`` within the image as executable files.
|
|
|
|
Environment Variables
|
|
^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
To set environment variables for other hooks, add a file to environment.d.
|
|
This directory contains bash script snippets that are sourced before running
|
|
scripts in each phase.
|
|
|
|
DIB exposes an internal IMAGE\_ELEMENT variable which provides elements access
|
|
to the full set of elements that are included in the image build. This can
|
|
be used to process local in-element files across all the elements
|
|
(pkg-map for example).
|
|
|
|
Dependencies
|
|
^^^^^^^^^^^^
|
|
|
|
Each element can use the following files to define or affect dependencies:
|
|
|
|
* element-deps: a plain text, newline separated list of elements which will
|
|
be added to the list of elements built into the image at image creation time.
|
|
|
|
* element-provides: A plain text, newline separated list of elements which
|
|
are provided by this element. These elements will be excluded from elements
|
|
built into the image at image creation time. For example if element A depends
|
|
on element B and element C includes element B in its "element-provides"
|
|
file and A and C are included when building an image, then B is not used.
|
|
|
|
Operating system elements
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
Some elements define the base structure for an operating system -- for example,
|
|
the ``opensuse`` element builds a base openSUSE system. Such elements have
|
|
more requirements than the other elements:
|
|
|
|
* they must have ``operating-system`` in their element-provides, so this
|
|
indicates they are an "operating system".
|
|
|
|
* they must export the ``DISTRO_NAME`` environment variable with the name
|
|
of the distribution built, using an environment.d script. For example,
|
|
the ``opensuse`` element exports ``DISTRO_NAME=opensuse``.
|
|
|
|
Ramdisk Elements
|
|
^^^^^^^^^^^^^^^^
|
|
|
|
Ramdisk elements support the following files in their element directories:
|
|
|
|
* binary-deps.d : text files listing executables required to be fed into the
|
|
ramdisk. These need to be present in $PATH in the build chroot (i.e. need to
|
|
be installed by your elements as described above).
|
|
|
|
* init.d : POSIX shell script fragments that will be appended to the default
|
|
script executed as the ramdisk is booted (/init).
|
|
|
|
* ramdisk-install.d : called to copy files into the ramdisk. The variable
|
|
TMP\_MOUNT\_PATH points to the root of the tree that will be packed into
|
|
the ramdisk.
|
|
|
|
* udev.d : udev rules files that will be copied into the ramdisk.
|
|
|
|
Element coding standard
|
|
^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
- lines should not include trailing whitespace.
|
|
- there should be no hard tabs in the file.
|
|
- indents are 4 spaces, and all indentation should be some multiple of
|
|
them.
|
|
- `do` and `then` keywords should be on the same line as the if, while or
|
|
for conditions.
|
|
|
|
Global image-build variables
|
|
----------------------------
|
|
|
|
* DIB\_OFFLINE : this is always set. When not empty, any operations that
|
|
perform remote data access should avoid it if possible. If not possible
|
|
the operation should still be attempted as the user may have an external
|
|
cache able to keep the operation functional.
|
|
|
|
* DIB\_IMAGE\_ROOT\_FS\_UUID : this contains the UUID of the root fs, when
|
|
diskimage-builder is building a disk image. This works only for ext
|
|
filesystems.
|
|
|
|
Structure of an element
|
|
-----------------------
|
|
|
|
The above-mentioned global content can be further broken down in a way that
|
|
encourages composition of elements and reusability of their components. One
|
|
possible approach to this would be to label elements as either a "driver",
|
|
"service", or "config" element. Below are some examples.
|
|
|
|
- Driver-specific elements should only contain the necessary bits for that
|
|
driver::
|
|
|
|
elements/
|
|
driver-mellanox/
|
|
init - modprobe line
|
|
install.d/
|
|
10-mlx - package installation
|
|
|
|
- An element that installs and configures Nova might be a bit more complex,
|
|
containing several scripts across several phases::
|
|
|
|
elements/
|
|
service-nova/
|
|
source-repository-nova - register a source repository
|
|
pre-install.d/
|
|
50-my-ppa - add a PPA
|
|
install.d/
|
|
10-user - common Nova user accts
|
|
50-my-pack - install packages from my PPA
|
|
60-nova - install nova and some dependencies
|
|
|
|
- In the general case, configuration should probably be handled either by the
|
|
meta-data service (eg, o-r-c) or via normal CM tools
|
|
(eg, salt). That being said, it may occasionally be desirable to create a
|
|
set of elements which express a distinct configuration of the same software
|
|
components.
|
|
|
|
In this way, depending on the hardware and in which availability zone it is
|
|
to be deployed, an image would be composed of:
|
|
|
|
* zero or more driver-elements
|
|
* one or more service-elements
|
|
* zero or more config-elements
|
|
|
|
It should be noted that this is merely a naming convention to assist in
|
|
managing elements. Diskimage-builder is not, and should not be, functionally
|
|
dependent upon specific element names.
|
|
|
|
diskimage-builder has the ability to retrieve source code for an element and
|
|
place it into a directory on the target image during the extra-data phase. The
|
|
default location/branch can then be overridden by the process running
|
|
diskimage-builder, making it possible to use the same element to track more
|
|
then one branch of a git repository or to get source for a local cache. See
|
|
elements/source-repositories/README.md for more information.
|
|
|
|
Debugging elements
|
|
------------------
|
|
|
|
The build-time environment and command line arguments are captured by the
|
|
'base' element and written to /etc/dib\_environment and /etc/dib\_arguments
|
|
inside the image.
|
|
|
|
Export 'break' to drop to a shell during the image build. Break points can be
|
|
set either before or after any of the hook points by exporting
|
|
"break=[before|after]-hook-name". Multiple break points can be specified as a
|
|
comma-delimited string. Some examples:
|
|
|
|
* break=before-block-device-size will break before the block device size hooks
|
|
are called.
|
|
|
|
* break=before-pre-install will break before the pre-install hooks.
|
|
|
|
* break=after-error will break after an error during a in target hookpoint.
|
|
|
|
Images are built such that the Linux kernel is instructed not to switch into
|
|
graphical consoles (i.e. it will not activate KMS). This maximises
|
|
compatibility with remote console interception hardware, such as HP's iLO.
|
|
However, you will typicallly only see kernel messages on the console - init
|
|
daemons (e.g. upstart) will usually be instructed to output to a serial
|
|
console so nova's console-log command can function. There is an element in the
|
|
tripleo-image-elements repository called "remove-serial-console" which will
|
|
force all boot messages to appear on the main console.
|
|
|
|
Ramdisk images can be debugged at run-time by passing "troubleshoot" as a
|
|
kernel command line argument, or by pressing "t" when an error is reached. This
|
|
will spawn a shell on the console (this can be extremely useful when network
|
|
interfaces or disks are not detected correctly).
|
|
|
|
Testing Elements
|
|
----------------
|
|
|
|
An element can have functional tests encapsulated inside the element itself. In
|
|
order to create a test case, follow these steps:
|
|
|
|
* Create a directory called 'test-elements' inside your element.
|
|
|
|
* Inside the test-elements directory, create a directory with the name of your
|
|
test case. The test case directory should have the same structure as an
|
|
element.
|
|
i.e. elements/apt-sources/test-elements/test-case-1
|
|
|
|
* Assert state during each of the element build phases you would like to test.
|
|
You can exit 1 to indicate a failure.
|
|
|
|
* To exit early and indicate a success, touch a file /tmp/dib-test-should-fail
|
|
in the image chroot, then exit 1.
|
|
|
|
Additionally, elements can be tested using python unittests. To create a
|
|
a python test:
|
|
|
|
* Create a directory called 'tests' in the element directory.
|
|
|
|
* Create an empty file called '\_\_init\_\_.py' to make it into a python
|
|
package.
|
|
|
|
* Create your test files as 'test\_whatever.py', using regular python test
|
|
code.
|
|
|
|
To run all the tests use testr - `testr run`. To run just some tests provide
|
|
one or more regex filters - tests matching any of them are run -
|
|
`testr run apt-proxy`.
|
|
|
|
Third party elements
|
|
--------------------
|
|
|
|
Pending implementation. The idea is to have a search path for elements.
|
|
|
|
|