User Defined Scripts



This chapter describes the purpose of the user defined scripts,, and, which can be used to further customize an image in ways that are not possible via the image description alone.

KIWI NG supports the following optional scripts that it runs in a root environment (chroot) containing your new appliance:

runs at the end of the bootstrap phase as part of the prepare step. The script can be used to configure the package manager with additional settings that should apply in the following chroot based installation step which completes the installation. The script is not dedicated to this use and can also be used for other tasks.

runs at the end of the prepare step and after users have been set and the overlay tree directory has been applied. It is usually used to apply a permanent and final change of data in the root tree, such as modifying a package provided config file.

Available only if delta_root="true" is set. In this case the script runs at the end of the prepare step prior the umount of the overlay root tree. It runs after an eventually given and is the last entry point to change the delta root tree.

Available only if delta_root="true" is set. In this case the script runs at the end of the prepare step prior the umount of the overlay root tree. The script is called NOT CHROOTED from the host with the image root directory as its working directory. It runs after an eventually given and is together with an eventually given script, the last entry point to change the delta root tree.

is executed at the beginning of the image creation process. It runs in the same image root tree that has been created by the prepare step but is invoked any time an image should be created from that root tree. It is usually used to apply image type specific changes to the root tree such as a modification to a config file that should be done when building a live iso but not when building a virtual disk image.

is executed for the disk image type oem only and runs right before the synchronization of the root tree into the disk image loop file. The can be used to change content of the root tree as a last action before the sync to the disk image is performed. This is useful for example to delete components from the system which were needed before or cannot be modified afterwards when syncing into a read-only filesystem.

is executed for the disk image type oem only and runs after the synchronization of the root tree into the disk image loop file. The chroot environment for this script call is the virtual disk itself and not the root tree as with and The script is usually used to apply changes at parts of the system that are not an element of the file based root tree such as the partition table, the contents of the final initrd, the bootloader, filesystem attributes and more.

KIWI NG executes scripts via the operating system if their executable bit is set (in that case a shebang is mandatory) otherwise they will be invoked via the BASH. If a script exits with a non-zero exit code then KIWI NG will report the failure and abort the image creation.

Developing/Debugging Scripts

When creating a custom script it usually takes some iterations of try and testing until a final stable state is reached. To support developers with this task KIWI NG calls scripts associated with a screen session. The connection to screen is only done if KIWI NG is called with the --debug option.

In this mode a script can start like the following template:

# The magic bits are still not set

echo "break"

At call time of the script a screen session executes and you get access to the break in shell. From this environment the needed script code can be implemented. Once the shell is closed the KIWI NG process continues.

Apart from providing a full featured terminal throughout the execution of the script code, there is also the advantage to have control on the session during the process of the image creation. Listing the active sessions for script execution can be done as follows:

$ sudo screen -list

There is a screen on:
     19699.pts-4.asterix     (Attached)
1 Socket in /run/screens/S-root.


As shown above the screen session(s) to execute script code provides extended control which could also be considered a security risk. Because of that KIWI NG only runs scripts through screen when explicitly enabled via the --debug switch. For production processes all scripts should run in their native way and should not require a terminal to operate correctly !

Script Template for /

KIWI NG provides a collection of methods and variables that supports users with custom operations. For details see Functions and Variables Provided by KIWI NG. The following template shows how to import this information in your script:

# Include functions & variables
test -f /.kconfig && . /.kconfig
test -f /.profile && . /.profile



Modifications of the unpacked root tree

Keep in mind that there is only one unpacked root tree the script operates in. This means that all changes are permanent and will not be automatically restored!

Functions and Variables Provided by KIWI NG

KIWI NG creates the .kconfig and .profile files to be sourced by the shell scripts and .kconfig contains various helper functions which can be used to simplify the image configuration and .profile contains environment variables which get populated from the settings provided in the image description.


The .kconfig file provides a common set of functions. Functions specific to SUSE Linux Enterprise and openSUSE begin with the name suse, functions applicable to all Linux distributions start with the name base.

The following list describes all functions provided by .kconfig:

baseSetRunlevel {value}

Set the default run level.

baseStripAndKeep {list of info-files to keep}

Helper function for the baseStrip* functions, reads the list of files to check from stdin for removing params: files which should be kept

baseStripLocales {list of locales}

Remove all locales, except for the ones given as the parameter.

baseStripTranslations {list of translations}

Remove all translations, except for the ones given as the parameter.


Remove libraries which are not directly linked against applications in the bin directories.

baseUpdateSysConfig {filename} {variable} {value}

Update the contents of a sysconfig variable

baseSystemdServiceInstalled {service}

Prints the path of the first found systemd unit or mount with name passed as the first parameter.

baseSysVServiceInstalled {service}

Prints the name ${service} if a SysV init service with that name is found, otherwise it prints nothing.

baseSystemdCall {service_name} {args}

Calls systemctl ${args} ${service_name} if a systemd unit, a systemd mount or a SysV init service with the ${service_name} exist.

baseInsertService {servicename}

Activate the given service via systemctl.

baseRemoveService {servicename}

Deactivate the given service via systemctl.

baseService {servicename} {on|off}

Activate or deactivate a service via systemctl. The function requires the service name and the value on or off as parameters.

Example to enable the sshd service on boot:

baseService sshd on
suseInsertService {servicename}

Calls baseInsertService and exists only for compatibility reasons.

suseRemoveService {servicename}

Calls baseRemoveService and exists only for compatibility reasons.

suseService {servicename} {on|off}

Calls baseService and exists only for compatibility reasons.


Creates the /etc/products.d/baseproduct link pointing to the product referenced by either /etc/SuSE-brand or /etc/os-release or the latest prod file available in /etc/products.d


Configures the image to work as a vagrant box by performing the following changes:

  • add the vagrant user to /etc/sudoers or /etc/sudoers.d/vagrant

  • insert the insecure vagrant ssh key, apply recommended ssh settings and start the ssh daemon

  • create the default shared folder /vagrant

Debug {message}

Helper function to print the supplied message if the variable DEBUG is set to 1 (it is off by default).

Echo {echo commandline}

Helper function to print a message to the controlling terminal.

Rm {list of files}

Helper function to delete files and log the deletion.

Profile Environment Variables

The .profile environment file is created by KIWI NG and contains a specific set of variables which are listed below.


The value of the compressed attribute set in the type element in config.xml.


A list of all packages which are children of the packages element with type="delete" in config.xml.


A comma separated list of the driver entries as listed in the drivers section of the config.xml.


The name of the image as listed in config.xml.


The image version as a string.


The contents of the keytable setup as done in config.xml.


The contents of the locale setup as done in config.xml.


A comma separated list of profiles used to build this image.


The contents of the timezone setup as done in config.xml.


The image type as extracted from the type element in config.xml.



If there is the file /.profile.extra available in the initrd, KIWI NG will import this additional environment file after the import of the /.profile file.

Configuration Tips

  1. Locale configuration:

    KIWI in order to set the locale relies on systemd-firstboot, which in turn writes the locale configuration file /etc/locale.conf. The values for the locale settings are taken from the description XML file in the <locale> element under <preferences>.

    KIWI assumes systemd adoption to handle these locale settings, in case the build distribution does not honor /etc/locale.conf this is likely to not produce any effect on the locale settings. As an example, in SLE12 distribution the locale configuration is already possible by using the systemd toolchain, however this approach overlaps with SUSE specific managers such as YaST. In that case using systemd-firstboot is only effective if locales in /etc/sysconfig/language are not set or if the file does not exist at all. In SLE12 /etc/sysconfig/language has precendence over /etc/locale.conf for compatibility reasons and management tools could still relay on sysconfig files for locale settings.

    In any case the configuration is still possible in KIWI by using any distribution specific way to configure the locale setting inside the script or by adding any additional configuration file as part of the overlay root-tree.

  2. Stateless systemd UUIDs:

    Machine ID files (/etc/machine-id, /var/lib/dbus/machine-id) may be created and set during the image package installation depending on the distribution. Those UUIDs are intended to be unique and set only once in each deployment.

    If /etc/machine-id does not exist or contains the string uninitialized (systemd v249 and later), this triggers firstboot behaviour in systemd and services using ConditionFirstBoot=yes will run. Unless the file already contains a valid machine ID, systemd will generate one and write it into the file, creating it if necessary. See the machine-id man page for more details.

    Depending on whether firstboot behaviour should be triggered or not, /etc/machine-id can be created, removed or filled with uninitialized by

    To prevent that images include a generated machine ID, KIWI will clear /etc/machine-id if it exists and does not contain the string uninitialized. This only applies to images based on a dracut initrd, it does not apply for container images.


    rw might be necessary if /etc/machine-id does not exist

    For systemd to be able to write /etc/machine-id on boot, it must either exist already (so that a bind mount can be created) or /etc must be writable.

    By default, the root filesystem is mounted read-only by dracut/systemd, thus a missing /etc/machine-id will result in an error on boot. The rw option can be added to the kernel commandline to force the initial mount to be read-write.


    Avoid inconsistent /var/lib/dbus/machine-id

    Note that /etc/machine-id and /var/lib/dbus/machine-id must contain the same unique ID. On modern systems /var/lib/dbus/machine-id is already a symlink to /etc/machine-id. However on older systems those might be two different files. This is the case for SLE-12 based images. If you are targeting these older operating systems, it is recommended to add the symlink creation into

    # Make machine-id consistent with dbus
    if [ -e /var/lib/dbus/machine-id ]; then
        rm /var/lib/dbus/machine-id
    ln -s /etc/machine-id /var/lib/dbus/machine-id