File clustduct-0.0.5.obscpio of Package clustduct

07070100000000000081A4000003E800000064000000015DE541E8000003A1000000000000000000000000000000000000001800000000clustduct-0.0.5/Bugs.md# Known Bugs
## hostname is *localhost* in JeOS node
The hostname is not set to the dns name on an image create by JeOS.
This can be changed by setting the value *DHCLIENT_SET_HOSTNAME="no"* 
to *DHCLIENT_SET_HOSTNAME="yes"*
in the file 
```
/etc/sysconfig/network/dhcp
```
This file is most likely created with the template
```
/usr/share/fillup-templates/sysconfig.dhcp-network
```
where the value *DHCLIENT_SET_HOSTNAME="no"* is set and not changed as this happens with yast? in a normal setup.

## kiwi commanline order
The image can be modifed after the build step by modifying the root directory. The command for this is 
```
kiwi --type=oem system create --root=/tmp/jeos15_image3/build/image-root/  \
--target-dir=/tmp/jeos15_image3/
```
and not 
```
kiwi system create --root=/tmp/jeos15_image3/build/image-root/  \
--target-dir=/tmp/jeos15_image3/ --type=oem
```
so the *--typ=oem* is a positional dependened argument.
07070100000001000081A4000003E800000064000000015DE541E8000005CD000000000000000000000000000000000000001800000000clustduct-0.0.5/COPYINGCopyright 2018 Christian Goll <cgoll@suse.de> SUSE GmbH

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
070701000000020000A1FF000003E800000064000000015DE5445900000020000000000000000000000000000000000000001800000000clustduct-0.0.5/INSTALL/usr/share/automake-1.15/INSTALL07070100000003000081A4000003E800000064000000015DE541E800000C77000000000000000000000000000000000000001C00000000clustduct-0.0.5/Makefile.amAUTOMAKE_OPTIONS = foreign

sbin_SCRIPTS = src/clustduct.lua src/write_bf.lua src/prepare_tftp.sh

luaexec_SCRIPTS = src/bfcommons.lua

clustductconfddir = $(sysconfdir)/clustduct.d
clustductconfd_DATA = configs/grub_iptemplate configs/pxe_iptemplate

clustductconfdir = $(sysconfdir)
clustductconf_DATA = configs/clustduct.conf

clustductdocdir = $(docdir)
clustductdoc_DATA = docs/* Usage.md Readme.md COPYING Bugs.md configs/default configs/grub.cfg

#FIXME Evil hack to point to the real /
#tftpdir= $(prefix)/../srv/tftpboot/pxelinux.cfg
#tftp_DATA = configs/default
#
#efidir = $(prefix)/../srv/tftpboot/EFI/x86
#efi_DATA = configs/grub.cfg

kiwiopensusebasedir = $(docdir)/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS
kiwiopensusebase_DATA = kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/Dicefile \
            kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/config.sh \
            kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/config.xml

kiwiopensuserootdir = $(kiwiopensusebasedir)/root
kiwiopensuseroot_DATA = kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/.kiwi_grub_config.trigger

kiwiopensuseetcdir = $(kiwiopensuserootdir)/etc
kiwiopensuseetc_DATA = kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/motd

kiwiopensusenetdir = $(kiwiopensuseetcdir)/sysconfig/network
kiwiopensusenet_DATA = kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/sysconfig/network/ifcfg-lan0 \
            kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/sysconfig/network/dhcp

kiwiopensuseudevdir = $(kiwiopensuseetcdir)/udev/rules.d/
kiwiopensuseudev_DATA = kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/udev/rules.d/70-persistent-net.rules

kiwiopensusesystemdir = $(kiwiopensuserootdir)/usr/lib/systemd/system/
kiwiopensusesystem_DATA = kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/usr/lib/systemd/system/grub_config.service

kiwislebasedir = $(docdir)/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS
kiwislebase_DATA = kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/Dicefile \
            kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/config.sh \
            kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/config.xml

kiwislerootdir = $(kiwislebasedir)/root
kiwisleroot_DATA = kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/.kiwi_grub_config.trigger

kiwisleetcdir = $(kiwislerootdir)/etc
kiwisleetc_DATA = kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/motd

kiwislenetdir = $(kiwisleetcdir)/sysconfig/network
kiwislenet_DATA = kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/sysconfig/network/ifcfg-lan0 \
            kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/sysconfig/network/dhcp

kiwisleudevdir = $(kiwisleetcdir)/udev/rules.d/
kiwisleudev_DATA = kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/udev/rules.d/70-persistent-net.rules

kiwislesystemdir = $(kiwislerootdir)/usr/lib/systemd/system/
kiwislesystem_DATA = kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/usr/lib/systemd/system/grub_config.service \
                     kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/systemd/system/RegisterFirst.service
07070100000004000081A4000003E800000064000000015DE541E800001341000000000000000000000000000000000000001A00000000clustduct-0.0.5/Readme.md# clustduct reference

The deployment tool `clustduct` connects the `genders` database to the `dnsmasq` service. During initialization the files `/etc/ethers` and `/etc/hosts` are populated by `node` entries from the genders database. `clustduct` also monitors *tftp* file transfers and can so be used to deploy prebuilt images to `compute nodes`.

## components of `clustduct`
The central component of `clustduct` is the script
`/usr/sbin/clustduct.lua`
and is called directly by `dnsmasq` at every dhcp and tftp activity of `dnsmasq`.

Two scripts are used to create and maintain the directory and file structure for booting and installing the `compute nodes`. In order to copy the files from the `syslinux` package the shell script
```
/usr/sbin/prepare_tftp.sh
```
can be used. For the creation of the files used for `grub` or PXE the `lua` script
```
/usr/sbin/write_bf.lua
```
can be used. It can be used with following command line options

option | description
-------|--------------------------------------------------
-n NODE| create configuration only for given and not all nodes
-o DIRECTORY| base directory to write boot file to
-c DIRECTORY| search directory for configuration files

## configuration of `clustduct`
The script 
```
/usr/sbin/clustduc.lua
```
can be configured with the file
```
/etc/clustduct.conf
```
which is not parsed, but is itself a `lua` table. Following values can be used

option  | description
--------|--------------------------------------------------
ethers | location of the ethers files, default is `/etc/ethers`
hosts | location of the hosts files, default is `/etc/hosts`
genders |location of the genders database, default is `/etc/genders` 
domain | domain to which the nodes are expanded, *must* be the same as in `/etc/dnsmasq.conf`
linear_add | if *true*, nodes with unknown `mac` addresses will be added to the `genders` database
confdir | the directory where clustduct searches for template files, `/etc/clustduct.d/` is used as default

## template files

During the initializaton of `clustduct` or by calling `write_bf.lua` individual entries for every node are created. As templates for the menus shown at boot time, two files are used:
For the PXE boot, the file
```
/etc/clustduct.d/pxe_iptemplate
``` 
and for `grub` the file
```
/etc/clustduct.d/grub_iptemplate
```
is used. Following values are substituted

value | description
------|--------------------------------------------------
$NODE | replaced with node name
$MAC  | replaced with mac address
$IP   | replaced with ip address



## genders database
The genders database is the single flat file located under `/etc/genders`. The format is
```
IDENTIFICATION KEY=VALUE
```
as *IDENTIFICATION* the name of the node or image is used. The node entry will be expanded to the FQDN. For the use of `clustduct` every node needs a single entry for every `KEY` and `VALUE` as the scripts may add and delete whole lines. An example database is shown below:

```
compute-01 ip=192.168.100.11
compute-02 ip=192.168.100.12
compute-03 ip=192.168.100.13
compute-03 mac=aa:bb:cc:dd:ee:ff
```

### special node entries

value | description
------|--------------------------------------------------
ip | used a ip address, *must* be present for node entry
mac | used as for dhpd
install | image entry which be used as default boot for node, inferior to boot
boot | image entry for boot, takes precedence over install entry


### special characters

As `genders` does not allow white spaces and other special characters, so following translation table is used

character | character description | value in `genders`
----------|-----------------------|-------------------
' ' | whitespace | \\ws
= | equals | \\eq

### image and boot entries

If an IDENTIFICATION in the `genders` database has KEY called 'menu' it is interpreted as a boot entry for `grub` called from (U)EFI and/or pxe network boot. Following values used for the boot entries are common for PXE and `grub`. All values which are not listed below will be ignored.

value | description
------|--------------------------------------------------
menu | will be expanded the label of menu
kernel | kernel which be used to boot, could also be a chainloader
append | options appended to the kernel entry
mandatory | will be added to *all* node entries
nextboot | will be used as boot entry after trigger event
trigger | download if file name will be used as trigger event



#### Options for PXE boot

value | description
------|--------------------------------------------------
com32 | used instead of kernel, used for chainloading
initrd | used as initrd in the append entry

#### Options for `grub` entries called from EFI

value | description
------|--------------------------------------------------
initrdefi | used as initrdefi
set | used as set, like timeouts ...
chainloader | the used chainloader entries
grub | value is used without directly without 'grub'

07070100000005000081A4000003E800000064000000015DE541E800000973000000000000000000000000000000000000001800000000clustduct-0.0.5/Salt.md# Configuration management with salt
## Prerequisites
Configure a *nfs-server* with following *exports*
```
/usr/lib/hpc	*(ro,root_squash,sync,no_subtree_check)
/usr/share/lmod/modulefiles	*(ro,root_squash,sync,no_subtree_check)
/usr/share/lmod/moduledeps	*(ro,root_squash,sync,no_subtree_check)
```

## Salt formulas
The salt formula */srv/salt/compute-node.sls* is used to configure the compute nodes. The formula has the contents
```
nfs-client:
    pkg.installed: []
neovim:
    pkg.installed: []
lua-lmod:
    pkg.installed: []
genders:
    pkg.installed: []

/usr/lib/hpc:
   mount.mounted:
      - device: leap15-clustduct:/usr/lib/hpc
      - fstype: nfs
      - mkmnt: True
      - opts:
         - defaults
      - require:
        - pkg: nfs-client

/usr/share/lmod/modulefiles:
   mount.mounted:
      - device: leap15-clustduct:/usr/share/lmod/modulefiles
      - fstype: nfs
      - mkmnt: True
      - opts:
         - defaults
      - require:
        - pkg: nfs-client

/usr/share/lmod/moduledeps:
   mount.mounted:
      - device: leap15-clustduct:/usr/share/lmod/moduledeps
      - fstype: nfs
      - mkmnt: True
      - opts:
         - defaults
      - require:
        - pkg: nfs-client

/etc/profile.d/lmod.sh:
    file.managed:
      - source: salt://shared_module/lmod.sh
      - mode: 644
      - user: root
      - group: root
      - require:
        - pkg: lua-lmod

/etc/profile.d/lmod.csh:
    file.managed:
      - source: salt://shared_module/lmod.csh
      - mode: 644
      - user: root
      - group: root
      - require:
        - pkg: lua-lmod

/etc/genders:
    file.managed:
      - contents_pillar: genders:database
      - mode: 644
      - user: root
      - group: root
      - require:
        - pkg: genders
```
and the definition for the node as *srv/salt/top.sls*
```
base:
  'compute-[0-2][0-9].cluster.suse':
    - compute-node

```
we also have to create the configuration files for *lua-lmod* with
```
mkdir /srv/salt/shared_module
cp /etc/profile.d/lmod* /srv/salt/shared_module
```
and create a pillar for distributing the genders database by creating the file `/srv/pillar/top.sls` with the content
```
base:
  '*':
    - genders
```
and the genders pillar `/srv/pillar/genders.sls`
```
genders:
    database: |
        {{ salt['cmd.run']('nodeattr --expand' ) | indent(8) }}
```
Now accept the key with
```
salt-key -A
```
and the node should install the rest.
07070100000006000081A4000003E800000064000000015DE541E800001439000000000000000000000000000000000000001900000000clustduct-0.0.5/Usage.md# Bare metal deployment with dnsmasq and kiwi
To deploy a cluster with `clustduct`, following prerequisites must be met:

   * internet access
   * separate network without an active dhcp server
     * *gateway* of the *cluster network*
   * *DNS* server outside of the cluster network

In this setup one node, from now on called *managment server*, provides *DNS* and *dhcp* information to the other nodes, called *compute nodes*.  The *managment server* is also used to generate images with *kiwi* and provide them to the *compute nodes*.

## Table of used values

Key | Example value | Used value
----|---------------|----------------
*cluster network* | 192.168.100.0/24 | ___________
*gateway*         | 192.168.100.1 |___________
*DNS server*      | 192.168.100.1 |___________
*dynamic range*   | 192.168.100.50-60 |___________
*static address*  | 192.168.100.254 |___________
*domain*          | cluster.suse |___________

## Setup of *managment server*
The *managment server* may be installed via the *HPC Managment Server (Head Node)* role, but other means of setup are also possible.

After installing the package `clustduct`, all necessary components are available.
Following services must be **disabled**

  * firewall
  * apparmor

Following packages must be installed:

  * python3-kiwi

Following services must be **enabled** and **running**

  * sshd

Following service must be **enabled**

  * dnsmasq

Furthermore, set up a static IP address.

  * static ip address


NOTE: Disable apparmor

In some profiles, `apparmor` is installed and has a preconfigured profile for `dnsmasq`. It must be disabled which can be done in two ways.

   * The profile for `dnsmasq` can be disabled with
```
aa-disable /etc/apparmor.d/usr.sbin.dnsmasq
```
   * or the `apparmor` service can be disabled with

```
systemctl disable apparmor.service
```
afterwards the machine must be rebooted.

WARNING: Disabling the `apparmor` profile introduces security issues which can be ignored as the *cluster network* is assumed to be a protected network.

## Dnsmasq configuration
The package *clustduct* contains also an example configuration for *dnsmasq* in `/usr/share/doc/clustduct/dnsmasq.example` which has following differences to shipped *dnsmasq* configuration:

  * local domain (modify to your needs)
```
local=/cluster.suse/
```
  * dynamic range (modify to your needs)
```
dhcp-range=192.168.100.50,192.168.100.60,12h
```
  * tftp enabled and deployment directory
```
enable-tftp
tftp-root=/srv/tftpboot/
```
  * pxe boot option for *x86_64*
```
dhcp-boot=pxelinux.0
```
  * *clustduct* script
```
dhcp-luascript=/usr/sbin/clustduct.lua
```
  * enable mac management
```
read-ethers
```
  * `dnsmasq` is executed as root
```
user=root
group=root
```
  * *gateway* for the *cluster network* (modify to your needs)
```
dhcp-option=option:router,192.168.100.1
```

Once dnsmasq has been configured, it may be (re)started.

## `genders` databases for the node configuration
The genders database connects the *mac* addresses of the *compute nodes* with the *ip* address and the corresponding FQDN . A flat file in `/etc/genders` is used as database. If the mac addresses of the hosts are known they may also be added before the node installation, if not they can be set during the boot process or, depending on the configuration, will be added in linear manner.

### Adding known `mac` addresses to `genders`
Previosily known `mac` addresses of nodes may be added to the database by adding a single line which contains the node name and mac address to the file `/etc/genders`. The format must be like
```
NODENAME mac=$MACADDRESS
```
After editing the `genders` database it is advisable to check its syntax by
executing `nodeattr -k`.

## Install image creation
Sample kiwi configurations for creating images can be found under the directory
```
/usr/share/doc/clustduct/kiwi-descriptions/SUSE/
```
and
```
/usr/share/doc/clustduct/kiwi-descriptions/openSUSE/
```
The install image is prepared with
```
cd /usr/share/doc/clustduct
kiwi --type oem system prepare\
--description kiwi-descriptions/suse/x86_64/suse-leap-15.0-JeOS \
--root /tmp/leap15_oem_pxe
```
Now the root file system for the new nodes is available under `/tmp/leap15_oem_pxe` and simple modifications can be made to it, but they will be lost if a new system is created via the `kiwi system prepare` command. To install the *compute nodes* the image has to be packed. This is done with the commands:
```
mkdir /tmp/packed_image
kiwi --type=oem system create --root=/tmp/leap15_oem_pxe  \
--target-dir=/tmp/packed_image
```

## Preparing the *tftboot* directory
For the deployment of the *compute nodes* the *tftpboot* directory `/srv/tftpboot` must be prepared with the command 
```
prepare-tftp.sh
``` 
which installs the necessary files for booting and installing the *compute nodes* over the network via *PXE* or *UEFI*. Finally the directory which holds the image for the *compute nodes* must be created with
```
mkdir -p /srv/tftpboot/leap15/
```
and the previously packed image extracted to
```
cd /srv/tftpboot/leap15/
tar xJf /tmp/packed_image/LimeJeOS-Leap-15.0.x86_64-1.15.0.install.tar.xz

```
it. 
07070100000007000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000001800000000clustduct-0.0.5/configs07070100000008000081A4000003E800000064000000015DE541E800000022000000000000000000000000000000000000002700000000clustduct-0.0.5/configs/clustduct.confclustduct = {
linear_add=false,
}
07070100000009000081A4000003E800000064000000015DE541E800000105000000000000000000000000000000000000002000000000clustduct-0.0.5/configs/defaultDEFAULT menu
PROMPT 0
MENU TITLE Hombrew pxe boot
TIMEOUT 100
ONTIMEOUT Reboot


LABEL ClustDuct
        MENU LABEL Boot as node ...
        KERNEL menu.c32
        APPEND clustduct/menu.pxe

LABEL Reboot
        MENU LABEL Reboot node
        COM32 reboot.c32
0707010000000A000081A4000003E800000064000000015DE541E8000000F3000000000000000000000000000000000000002100000000clustduct-0.0.5/configs/grub.cfgset timeout=30
echo Boot node with entry for mac ${net_default_mac}
menuentry 'Clustduct node entry' {
	configfile /pxelinux.cfg/clustduct_${net_default_mac}.grub
}
menuentry 'Clustduct default boot entry' {
	configfile /clustduct/menu.grub
}
0707010000000B000081A4000003E800000064000000015DE541E80000008B000000000000000000000000000000000000002800000000clustduct-0.0.5/configs/grub_iptemplateset timeout=10

$ENTRY

menuentry '$NODE/$IP ($MAC) reboot' {
	reboot
}

menuentry 'Go back to main' {
	configfile /clustduct/menu.grub
}

0707010000000C000081A4000003E800000064000000015DE541E8000000FE000000000000000000000000000000000000002700000000clustduct-0.0.5/configs/pxe_iptemplatePROMPT 0
MENU TITLE $NODE $IP $MAC
DEFAULT menu
TIMEOUT 100

$ENTRY

MENU SEPERATOR
LABEL save_reboot
	MENU LABEL Save to database and reboot
	COM32 reboot.c32
LABEL go_back
	MENU LABEL Go to clustduct menu
	KERNEL menu.c32
	APPEND pxelinux.cfg/default

0707010000000D000081A4000003E800000064000000015DE541E800000189000000000000000000000000000000000000001D00000000clustduct-0.0.5/configure.acAC_INIT([clustduct], [0.0.3], [cgoll@suse.com], [clustduct], [http://github.com/mslacken/clustduct])
AM_INIT_AUTOMAKE
AC_CONFIG_FILES([Makefile])

#AC_CONFIG_SRCDIR([src/clustduct.lua src/bfcommons.lua])
AX_PROG_LUA([5.1], [5.4],,AC_MSG_ERROR(Please provide a lua interpreter))
AC_CHECK_FILE("/usr/lib64/lua/$LUA_VERSION/genders.so",,AC_MSG_WARN(Can not find genders lua bindings))

AC_OUTPUT
0707010000000E000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000001500000000clustduct-0.0.5/docs0707010000000F000081A4000003E800000064000000015DE541E8000033E5000000000000000000000000000000000000001F00000000clustduct-0.0.5/docs/README.md# clustduct

The deployment tool `clustduct` connects the `genders` database to the `dnsmasq` service.

[genders](https://github.com/chaos/genders) is a static cluster configuration database used for cluster configuration management. The basic concept is that a
genders file, usually `/etc/genders/` containing a list of node names and their attributes is easily readable with the command `nodeattr`.

[dnsmasq](git://thekelleys.org.uk/dnsmasq.git) provides a DNS forwarder, DHCP server, router advertisement and network boot features for small computer networks.

The configuration of both to work properly with clustduct will be detailed further below. If you are already using
both tool, you'll see no special requirements are needed to integrating them with clustduct.

## How does clustduct works
During the initialization of every node, the files `/etc/ethers` and `/etc/hosts` are populated by the data provided by the `node` entries from the genders database. `clustduct` will also monitor *TFTP* file transfers and can be used to deploy prebuilt images to the `compute nodes`.

### components of `clustduct`
The central component of `clustduct` is the script `/usr/sbin/clustduct.lua`
and is called directly by `dnsmasq` at every DHCP and TFTP activity of `dnsmasq`.

Two scripts are used to create and maintain the directory and file structure for booting and installing the `compute nodes`.

* The shell script `/usr/sbin/prepare_tftp.sh`, in order to copy the files from the `syslinux` package

* The `lua` script `/usr/sbin/write_bf.lua` for the creation of the files used for `grub` or PXE.
The following command line options are available:

option | description
-------|--------------------------------------------------
-n NODE| create configuration only for given and not all nodes
-o DIRECTORY| base directory to write boot file to
-c DIRECTORY| search directory for configuration files

### configuration of `clustduct`
The script  `/usr/sbin/clustduct.lua` can be configured with the file `/etc/clustduct.conf`
which is not parsed, but is itself a `lua` table. The following values can be used:

option  | description
--------|--------------------------------------------------
ethers | location of the ethers files, default is `/etc/ethers`
hosts | location of the hosts files, default is `/etc/hosts`
genders |location of the genders database, default is `/etc/genders`
domain | domain to which the nodes are expanded, *must* be the same as in `/etc/dnsmasq.conf`
linear_add | if *true*, nodes with unknown `mac` addresses will be added to the `genders` database
confdir | the directory where clustduct searches for template files, default is `/etc/clustduct.d/`

### template files

During the initialization of `clustduct` or by calling `write_bf.lua` individual entries for every node are created. As templates for the menus shown at boot time, two files are used:

* For the PXE boot, the file `/etc/clustduct.d/pxe_iptemplate`

* For `grub` the file `/etc/clustduct.d/grub_iptemplate` with the following values being substituted

value | description
------|--------------------------------------------------
$NODE | replaced with node name
$MAC  | replaced with mac address
$IP   | replaced with ip address


## Working with the genders database
The genders database is the single flat file located under `/etc/genders`. The format is
```
IDENTIFICATION KEY=VALUE
```
as *IDENTIFICATION* the name of the node or image is used. The node entry will be expanded to the FQDN. For the use of `clustduct`, every node needs a single entry for every `KEY` and `VALUE` as the scripts may add and delete whole lines. An example database is shown below:

```
compute-01 ip=192.168.100.11
compute-02 ip=192.168.100.12
compute-03 ip=192.168.100.13
compute-03 mac=aa:bb:cc:dd:ee:ff
```

### special node entries

value | description
------|--------------------------------------------------
ip | used a IP address, *must* be present for node entry
mac | used as for DHCP
install | image entry which be used as default boot for node, inferior to boot
boot | image entry for boot, takes precedence over install entry


### special characters

As `genders` does not allow white spaces and other special characters, the following translation table is used:

character | character description | value in `genders`
----------|-----------------------|-------------------
' ' | whitespace | \\ws
= | equals | \\eq

### image and boot entries

If an *IDENTIFICATION* in the `genders` database has KEY called 'menu' it is interpreted as a boot entry for `grub` called from (U)EFI and/or PXE network boot.
The following values used for the boot entries are common for PXE and `grub`. All values which are not listed below will be ignored.

value | description
------|--------------------------------------------------
menu | will be expanded the label of menu
kernel | kernel which be used to boot, could also be a chainloader
append | options appended to the kernel entry
mandatory | will be added to *all* node entries
nextboot | will be used as boot entry after trigger event
trigger | download if file name will be used as trigger event



#### Options for PXE boot

value | description
------|--------------------------------------------------
com32 | used instead of kernel, used for chainloading
initrd | used as initrd in the append entry

#### Options for `grub` entries called from EFI

value | description
------|--------------------------------------------------
initrdefi | used as initrdefi
set | used as set, like timeouts ...
chainloader | the used chainloader entries
grub | value is used without directly without 'grub'



## Bare metal deployment with dnsmasq and kiwi
To deploy a cluster with `clustduct`, following prerequisites must be met:

  * internet access
  * separate network without an active DHCP server
  * *gateway* of the *cluster network*
  * *DNS* server outside of the cluster network

In this setup one node, called *management server*, provides *DNS* and *DHCP* information to the other nodes, called *compute nodes*. This *management server* is also used to generate images with [kiwi](https://opensuse.github.io/kiwi/) and provide them to the *compute nodes*.

### Table of used values

Key | Example value | Used value
----|---------------|----------------
*cluster network* | 192.168.100.0/24 | ___________
*gateway*         | 192.168.100.1 |___________
*DNS server*      | 192.168.100.1 |___________
*dynamic range*   | 192.168.100.50-60 |___________
*static address*  | 192.168.100.254 |___________
*domain*          | cluster.suse |___________

### Setup of *management server*
The *management server* may be installed via the *HPC Management Server (Head Node)* role, but other means of setup are also possible.

After installing the package `clustduct`, all necessary components are available.
The following services must be **disabled**

  * firewall
  * apparmor

The following packages must be installed:

  * python3-kiwi

The following services must be **enabled** and **running**

  * sshd

And the following service must be **enabled**

  * dnsmasq

Furthermore, set up a static IP address.

  * static IP address


#### Disabling apparmor

In some profiles, `apparmor` is installed and has a pre-configured profile for `dnsmasq`. It must be disabled which can be done in two ways.

   * The profile for `dnsmasq` can be disabled with
```
aa-disable /etc/apparmor.d/usr.sbin.dnsmasq
```
   * or the `apparmor` service can be disabled with
```
systemctl disable apparmor.service
```
afterwards the machine must be rebooted.

WARNING: Disabling the `apparmor` profile introduces security issues which can be ignored as the *cluster network* is assumed to be a protected network.

## Dnsmasq configuration
The package *clustduct* contains also an example configuration for *dnsmasq* in `/usr/share/doc/clustduct/dnsmasq.example` which has following differences to shipped *dnsmasq* configuration:

  * local domain (modify to your needs)
```
local=/cluster.suse/
```
  * dynamic range (modify to your needs)
```
dhcp-range=192.168.100.50,192.168.100.60,12h
```
  * tftp enabled and deployment directory
```
enable-tftp
tftp-root=/srv/tftpboot/
```
  * pxe boot option for *x86_64*
```
dhcp-boot=pxelinux.0
```
  * *clustduct* script
```
dhcp-luascript=/usr/sbin/clustduct.lua
```
  * enable mac management
```
read-ethers
```
  * `dnsmasq` is executed as root
```
user=root
group=root
```
  * *gateway* for the *cluster network* (modify to your needs)
```
dhcp-option=option:router,192.168.100.1
```

Once dnsmasq has been configured, it may be (re)started.

### `genders` databases for the node configuration
The genders database connects the *mac* addresses of the *compute nodes* with the *ip* address and the corresponding FQDN . A flat file in `/etc/genders` is used as database. If the mac addresses of the hosts are known they may also be added before the node installation, if not they can be set during the boot process or, depending on the configuration, will be added in linear manner.

### Adding known `mac` addresses to `genders`
Previously known `mac` addresses of nodes may be added to the database by adding a single line which contains the node name and mac address to the file `/etc/genders`. The format must be like
```
NODENAME mac=$MACADDRESS
```
After editing the `genders` database it is advisable to check its syntax by
executing `nodeattr -k`.

## Install image creation
Sample kiwi configurations for creating images can be found under the directory
```
/usr/share/doc/clustduct/kiwi-descriptions/SUSE/
```
and
```
/usr/share/doc/clustduct/kiwi-descriptions/openSUSE/
```
The install image is prepared with
```
cd /usr/share/doc/clustduct
kiwi --type oem system prepare\
--description kiwi-descriptions/suse/x86_64/suse-leap-15.0-JeOS \
--root /tmp/leap15_oem_pxe
```
Now the root file system for the new nodes is available under `/tmp/leap15_oem_pxe` and simple modifications can be made to it, but they will be lost if a new system is created via the `kiwi system prepare` command. To install the *compute nodes* the image has to be packed. This is done with the commands:
```
mkdir /tmp/packed_image
kiwi --type=oem system create --root=/tmp/leap15_oem_pxe  \
--target-dir=/tmp/packed_image
```

## Preparing the *tftboot* directory
For the deployment of the *compute nodes* the *tftpboot* directory `/srv/tftpboot` must be prepared with the command
```
prepare-tftp.sh
```
which installs the necessary files for booting and installing the *compute nodes* over the network via *PXE* or *UEFI*. Finally the directory which holds the image for the *compute nodes* must be created with
```
mkdir -p /srv/tftpboot/leap15/
```
and the previously packed image extracted to
```
cd /srv/tftpboot/leap15/
tar xJf /tmp/packed_image/LimeJeOS-Leap-15.0.x86_64-1.15.0.install.tar.xz

```
it.



# Configuration management with salt
## Prerequisites
Configure a *nfs-server* with following *exports*
```
/usr/lib/hpc	*(ro,root_squash,sync,no_subtree_check)
/usr/share/lmod/modulefiles	*(ro,root_squash,sync,no_subtree_check)
/usr/share/lmod/moduledeps	*(ro,root_squash,sync,no_subtree_check)
```

## Salt formulas
The salt formula */srv/salt/compute-node.sls* is used to configure the compute nodes. The formula has the contents
```
nfs-client:
    pkg.installed: []
neovim:
    pkg.installed: []
lua-lmod:
    pkg.installed: []
genders:
    pkg.installed: []

/usr/lib/hpc:
   mount.mounted:
      - device: leap15-clustduct:/usr/lib/hpc
      - fstype: nfs
      - mkmnt: True
      - opts:
         - defaults
      - require:
        - pkg: nfs-client

/usr/share/lmod/modulefiles:
   mount.mounted:
      - device: leap15-clustduct:/usr/share/lmod/modulefiles
      - fstype: nfs
      - mkmnt: True
      - opts:
         - defaults
      - require:
        - pkg: nfs-client

/usr/share/lmod/moduledeps:
   mount.mounted:
      - device: leap15-clustduct:/usr/share/lmod/moduledeps
      - fstype: nfs
      - mkmnt: True
      - opts:
         - defaults
      - require:
        - pkg: nfs-client

/etc/profile.d/lmod.sh:
    file.managed:
      - source: salt://shared_module/lmod.sh
      - mode: 644
      - user: root
      - group: root
      - require:
        - pkg: lua-lmod

/etc/profile.d/lmod.csh:
    file.managed:
      - source: salt://shared_module/lmod.csh
      - mode: 644
      - user: root
      - group: root
      - require:
        - pkg: lua-lmod

/etc/genders:
    file.managed:
      - contents_pillar: genders:database
      - mode: 644
      - user: root
      - group: root
      - require:
        - pkg: genders
```
and the definition for the node as *srv/salt/top.sls*
```
base:
  'compute-[0-2][0-9].cluster.suse':
    - compute-node

```
we also have to create the configuration files for *lua-lmod* with
```
mkdir /srv/salt/shared_module
cp /etc/profile.d/lmod* /srv/salt/shared_module
```
and create a pillar for distributing the genders database by creating the file `/srv/pillar/top.sls` with the content
```
base:
  '*':
    - genders
```
and the genders pillar `/srv/pillar/genders.sls`
```
genders:
    database: |
        {{ salt['cmd.run']('nodeattr --expand' ) | indent(8) }}
```
Now accept the key with
```
salt-key -A
```
and the node should install the rest.
07070100000010000081A4000003E800000064000000015DE541E80000001A000000000000000000000000000000000000002100000000clustduct-0.0.5/docs/_config.ymltheme: jekyll-theme-hacker07070100000011000081A4000003E800000064000000015DE541E80000015A000000000000000000000000000000000000002500000000clustduct-0.0.5/docs/default.exampleDEFAULT menu
PROMPT 0
MENU TITLE Bootmenu for clustduct deployment
TIMEOUT 600
TOTALTIMEOUT 6000
ONTIMEOUT Clustduct

LABEL Clustduct
        MENU LABEL Clustduct cluster deployment
        MENU DEFAULT
	KERNEL menu.c32
	APPEND /srv/tftpboot/clustduct/menu.pxe

LABEL local
        MENU LABEL (local)
        COM32 chain.c32
        APPEND hd0


07070100000012000081A4000003E800000064000000015DE541E800000861000000000000000000000000000000000000002500000000clustduct-0.0.5/docs/dnsmasq.example# Configuration file for dnsmasq of use by clustduct

# Add local-only domains here, queries in these domains are answered
# from /etc/hosts or DHCP only.
local=/cluster.suse/

# If you want dnsmasq to change uid and gid to something other
# than the default, edit the following lines.
user=root
group=root

# Uncomment this to enable the integrated DHCP server, you need
# to supply the range of addresses available for lease and optionally
# a lease time. If you have more than one network, you will need to
# repeat this for each network on which you want to supply DHCP
# service.
dhcp-range=192.168.100.50,192.168.100.150,12h

# Do the same thing, but using the option name
dhcp-option=option:router,192.168.100.1

# Test for the architecture of a netboot client. PXE clients are
# supposed to send their architecture as option 93. (See RFC 4578)
#dhcp-match=peecees, option:client-arch, 0 #x86-32
#dhcp-match=itanics, option:client-arch, 2 #IA64
#dhcp-match=hammers, option:client-arch, 6 #x86-64
dhcp-match=set:x86PC,option:client-arch, 7 #EFI x86-64
dhcp-match=set:x86PC,option:client-arch, 6 #EFI x86-64
dhcp-match=set:x86PC,option:client-arch, 9 #EFI x86-64
dhcp-boot=tag:x86PC,"/EFI/x86/bootx64.efi"
dhcp-boot="pxelinux.0"
# Disable re-use of the DHCP servername and filename fields  as
# extra  option space.
dhcp-no-override

# Run an executable when a DHCP lease is created or destroyed.
# The arguments sent to the script are "add" or "del",
# then the MAC address, the IP address and finally the hostname
# if there is one.
dhcp-luascript=/usr/sbin/clustduct.lua

# Enable dnsmasq's built-in TFTP server
enable-tftp

# Set the root directory for files available via FTP.
tftp-root=/srv/tftpboot/

# This option stops dnsmasq from negotiating a larger blocksize for TFTP
# transfers. It will slow things down, but may rescue some broken TFTP
# clients.
tftp-no-blocksize

# If this line is uncommented, dnsmasq will read /etc/ethers and act
# on the ethernet-address/IP pairs found there just as if they had
# been given as --dhcp-host options. Useful if you keep
# MAC-address/host mappings there for other purposes.
read-ethers
07070100000013000081A4000003E800000064000000015DE541E800000A6D000000000000000000000000000000000000002500000000clustduct-0.0.5/docs/genders.example# Sample genders file which should be the same on all nodes, with following format.
# Each line of the genders file may have one of the following formats
# The nodename(s) is the shortened[2] hostname of a node.  This is followed by
# any number of spaces or tabs, and then the comma-separated list of attributes,
# each of which can optionally have a value.  The substitution string "%n" can
# be used in an attribute value to represent the nodename.  Nodenames can be
# listed on multiple lines, so a node's attributes can be specified on multiple
# lines. However, no single node may have duplicate attributes. Genders database
# accepts ranges of nodenames in the general form: prefix[n-m,l-k,...],
# where n < m and l < k, etc., as an alternative to explicit lists of nodenames.
#
# Example file for clustduct with ten nodes and a entry to boot the nodes
# from the local disk
#
# example for kiwi generated install entry
#
# openSUSE Leap15 example entry
#
LEAP15     initrd=/leap15/pxeboot.initrd.xz,append=rd.kiwi.install.pxe\wsrd.kiwi.install.image\eqtftp://192.168.100.254/leap15/LimeJeOS-Leap-15.1.xz,kernel=/leap15/LimeJeOS-Leap-15.1.kernel,nextboot=local,trigger=LimeJeOS-Leap-15.1.xz
#
# SLE-HPC-15-1 example entry
#
SLE-HPC-15_2     initrd=/sle-hpc15.2/pxeboot.initrd.xz,append=rd.kiwi.install.pxe\wsrd.kiwi.install.image\eqtftp://192.168.100.254/sle-hpc15.2/LimeJeOS-SLE-HPC-15.2.xz,kernel=/sle-hpc15.2/LimeJeOS-SLE-HPC-15.2.kernel,nextboot=local,trigger=LimeJeOS-SLE-HPC-15.2.xz
#
# local boot entry
#
local menu=Boot\wsfrom\wslocal\wsdisk,com32=chain.c32,mandatory,grub=configfile\ws(hd0\cogpt3)/boot/grub2/grub.cfg
#
# node entries
#
compute-01 ip=192.168.100.11
compute-02 ip=192.168.100.12
compute-03 ip=192.168.100.13
compute-04 ip=192.168.100.14
compute-05 ip=192.168.100.15
compute-06 ip=192.168.100.16
compute-07 ip=192.168.100.17
compute-08 ip=192.168.100.18
compute-09 ip=192.168.100.19
compute-10 ip=192.168.100.20
#
# install the kiwi image on all the nodes
# Uncomment for target system

# Install Leap 15.0
#
#compute-01 install=LEAP15
#compute-02 install=LEAP15
#compute-03 install=LEAP15
#compute-04 install=LEAP15
#compute-05 install=LEAP15
#compute-06 install=LEAP15
#compute-07 install=LEAP15
#compute-08 install=LEAP15
#compute-09 install=LEAP15
#compute-10 install=LEAP15


# Install SLE-HPC-15-SP1
#
#compute-01 install=SLE-HPC-15_2
#compute-02 install=SLE-HPC-15_2
#compute-03 install=SLE-HPC-15_2
#compute-04 install=SLE-HPC-15_2
#compute-05 install=SLE-HPC-15_2
#compute-06 install=SLE-HPC-15_2
#compute-07 install=SLE-HPC-15_2
#compute-08 install=SLE-HPC-15_2
#compute-09 install=SLE-HPC-15_2
#compute-10 install=SLE-HPC-15_2
07070100000014000081ED000003E800000064000000015DE541E800000341000000000000000000000000000000000000001F00000000clustduct-0.0.5/docs/query.lua#!/usr/bin/lua
-- simple print function for tables
function tprint (t, s)
    for k, v in pairs(t) do
        local kfmt = '["' .. tostring(k) ..'"]'
        if type(k) ~= 'string' then
            kfmt = '[' .. k .. ']'
        end
        local vfmt = '"'.. tostring(v) ..'"'
        if type(v) == 'table' then
            tprint(v, (s or '')..kfmt)
        else
            if type(v) ~= 'string' then
                vfmt = tostring(v)
            end
            print(type(t)..(s or '')..kfmt..' = '..vfmt)
        end
    end
end

db_file = "/etc/genders"
g_db = require("genders")
handle = g_db.new(db_file)
print("opened genders database "..db_file.." with " ..#handle:getnodes().." nodes")
query = handle:query("~ip")
tprint(query)
nodes = handle:query("ip")
for index,node in pairs(nodes) do
	print(index.." "..node)
end

07070100000015000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000002200000000clustduct-0.0.5/kiwi-descriptions07070100000016000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000002700000000clustduct-0.0.5/kiwi-descriptions/SUSE07070100000017000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000002E00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_6407070100000018000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004000000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS07070100000019000081A4000003E800000064000000015DE541E80000003C000000000000000000000000000000000000004900000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/DicefileDice.configure do |config|
  config.buildhost = :DOCKER
end
0707010000001A000081ED000003E800000064000000015DE541E800000915000000000000000000000000000000000000004A00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/config.sh#!/bin/bash
#================
# FILE          : config.sh
#----------------
# PROJECT       : OpenSuSE KIWI Image System
# COPYRIGHT     : (c) 2006 SUSE LINUX Products GmbH. All rights reserved
#               :
# AUTHOR        : Marcus Schaefer <ms@suse.de>
#               :
# BELONGS TO    : Operating System images
#               :
# DESCRIPTION   : configuration script for SUSE based
#               : operating systems
#               :
#               :
# STATUS        : BETA
#----------------
#======================================
# Functions...
#--------------------------------------
test -f /.kconfig && . /.kconfig
test -f /.profile && . /.profile

#======================================
# Greeting...
#--------------------------------------
echo "Configure image: [$kiwi_iname]..."

#======================================
# Mount system filesystems
#--------------------------------------
baseMount

#======================================
# Setup baseproduct link
#--------------------------------------
suseSetupProduct

#======================================
# Add missing gpg keys to rpm
#--------------------------------------
suseImportBuildKey

#======================================
# Activate services
#--------------------------------------
suseInsertService sshd
suseInsertService RegisterFirst
if [[ ${kiwi_type} =~ oem|vmx ]];then
    suseInsertService grub_config
else
    suseRemoveService grub_config
fi

#======================================
# Setup default target, multi-user
#--------------------------------------
baseSetRunlevel 3

#==========================================
# remove package docs
#------------------------------------------
rm -rf /usr/share/doc/packages/*
rm -rf /usr/share/doc/manual/*
rm -rf /opt/kde*

#======================================
# only basic version of vim is
# installed; no syntax highlighting
#--------------------------------------
sed -i -e's/^syntax on/" syntax on/' /etc/vimrc

#======================================
# SuSEconfig
#--------------------------------------
suseConfig

#======================================
# Remove yast if not in use
#--------------------------------------
suseRemoveYaST

#======================================
# Umount kernel filesystems
#--------------------------------------
baseCleanMount

exit 0
0707010000001B000081A4000003E800000064000000015DE541E800000FBD000000000000000000000000000000000000004B00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/config.xml<?xml version="1.0" encoding="utf-8"?>

<image schemaversion="6.8" name="SLE-HPC-15.1-JeOS">
    <description type="system">
        <author>Christian Goll</author>
        <contact>cgoll@suse.de</contact>
        <specification>
            SUSE Linux Enterprise HPC 15 JeOS, small text based image
        </specification>
    </description>
    <preferences>
        <version>1.15.0</version>
        <packagemanager>zypper</packagemanager>
        <locale>en_US</locale>
        <keytable>us</keytable>
        <timezone>Europe/Berlin</timezone>
        <rpm-excludedocs>true</rpm-excludedocs>
        <rpm-check-signatures>false</rpm-check-signatures>
        <bootsplash-theme>SLE</bootsplash-theme>
        <bootloader-theme>SLE</bootloader-theme>
    </preferences>
    <preferences>
	    <type image="vmx" filesystem="ext4" bootloader="grub2" kernelcmdline="splash" firmware="efi" format="qcow2">
		    <size>
			    32768
		    </size>
	    </type>
        <type image="oem" filesystem="ext4" initrd_system="dracut" installpxe="true" bootloader="grub2" kernelcmdline="splash" firmware="efi">
            <oemconfig>
                <oem-systemsize>2048</oem-systemsize>
                <oem-swap>true</oem-swap>
                <oem-device-filter>/dev/ram</oem-device-filter>
                <oem-multipath-scan>false</oem-multipath-scan>
		<oem-unattended>true</oem-unattended>
            </oemconfig>
            <machine memory="512" guestOS="suse" HWversion="4">
                <vmdisk id="0" controller="ide"/>
                <vmnic driver="e1000" interface="0" mode="bridged"/>
            </machine>
        </type>
    </preferences>
    <users>
	<!-- password is linux -->
        <user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/root" name="root" groups="root"/>
    </users>
    <repository type="rpm-md" alias="kiwi" priority="1">
        <source path="obs://Virtualization:Appliances:Builder/SLE_15_SP1"/>
    </repository>
    <repository type="yast2" alias="SLE_installer">
	    <source path="iso:// /root/SLE-15SP1-Installer-DVD-x86_64-GA-Media1.iso"/>
    </repository>
    <repository type="yast2" alias="SLE_packages">
	    <source path="iso:// /root/SLE-15SP1-Packages-x86_64-GA-Media1.iso"/>
    </repository>

    <packages type="image">
	<package name="checkmedia"/>
        <package name="patterns-base-minimal_base"/>
        <package name="grub2-branding-SLE-15"/>
        <package name="iputils"/>
      	<package name="vim"/>
        <package name="grub2"/>
        <package name="grub2-x86_64-efi" arch="x86_64"/>
        <package name="grub2-i386-pc"/>
        <package name="haveged"/>
      	<package name="syslinux"/>
        <package name="fontconfig"/>
        <package name="fonts-config"/>
        <package name="tar"/>
        <package name="openssh"/>
        <package name="iproute2"/>
        <package name="less"/>
      	<package name="lvm2"/>
      	<package name="psmisc"/>
      	<package name="parted"/>
        <package name="bash-completion"/>
        <package name="dhcp-client"/>
        <package name="which"/>
      	<package name="udev"/>
      	<package name="salt-minion"/>
        <package name="shim"/>
      	<package name="systemd"/>
      	<package name="systemd-sysvinit"/>
      	<package name="dracut"/>
        <package name="kernel-default"/>
        <package name="timezone"/>
      	<package name="SLE_HPC-release"/>
      	<package name="SUSEConnect"/>
      	<package name="suse-build-key"/>
      	<package name="sle-module-basesystem-release"/>
    </packages>
    <packages type="oem">
        <package name="dracut-kiwi-oem-repart"/>
        <package name="dracut-kiwi-oem-dump"/>
    </packages>
    <packages type="bootstrap">
        <package name="udev"/>
        <package name="filesystem"/>
        <package name="glibc-locale"/>
        <package name="cracklib-dict-full"/>
        <package name="ca-certificates"/>
	<package name="SLE_HPC-release"/>
	<package name="sle-module-basesystem-release"/>
    </packages>
</image>
0707010000001C000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004500000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root0707010000001D000081A4000003E800000064000000015DE541E800000000000000000000000000000000000000000000005F00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/.kiwi_grub_config.trigger0707010000001E000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004900000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc0707010000001F000081A4000003E800000064000000015DE541E80000008B000000000000000000000000000000000000004E00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/motdThis is the Leap 15.0 JeOS SuSE Linux System.
To upgrade your system call:

        zypper refresh
        zypper up

Have a lot of fun...
07070100000020000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005300000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/sysconfig07070100000021000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005B00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/sysconfig/network07070100000022000081A4000003E800000064000000015DE541E80000325F000000000000000000000000000000000000006000000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/sysconfig/network/dhcp## Type:        list(enabled,disabled,default,)
## Default:     ""
#
# Default is to use the FQDN option, when the DHCLIENT_HOSTNAME_OPTION
# variable is set to a full hostname, that is, when it contains a dot.
# When DHCLIENT_HOSTNAME_OPTION is set to AUTO, short hostname from
# /etc/hostname is send via hostname option 12 (same as SLES-11).
#
DHCLIENT_FQDN_ENABLED=""

## Type:        list(both,ptr,none,)
## Default:     ""
#
# Request to update A and PTR or only the PTR DNS records using the
# hostname specified in DHCLIENT_HOSTNAME_OPTION variable.
# Default is to update 'both' when hostname is set or 'none' when
# the hostname is empty and DHCLIENT_FQDN_ENABLED is set to enabled.
#
DHCLIENT_FQDN_UPDATE=""

## Type:        yesno
## Default:     yes
#
# Qualify relative sub-domains/hostname in the DHCLIENT_HOSTNAME_OPTION
# variable adding a final dot ('foo.bar' -> 'foo.bar.').
# When disabled, the DHCP server may append it's update domain to the
# hostname (e.g. 'foo.bar' -> 'foo.bar.example.net').
#
DHCLIENT_FQDN_QUALIFY="yes"

## Type:        yesno
## Default:     yes
#
# The FQDN option is encoding hostnames using canonical DNS wire format
# by default. This flag permits to enable use of the deprecated ascii
# format limited to a single label (host hostname) for compatibility
# purposes with draft implementation, which may be unsupported and cause
# that a DHCP server ignores the fqdn option request completely.
#
DHCLIENT_FQDN_ENCODE="yes"

## Type:	list(,default,none,all,dns,ntp,nis,tz,boot,smb,nds,slp,sip,log)
## Default:	""
#
# This variable permits to specify a space separated list of build-in
# facility names supported by the dhcp4 client modifying the default
# options used in requests and to update system settings (via netconfig).
#
# When empty, default settings configured in wicked-config(5) or built-in
# defaults are used. The special "default", "all", and "none" sets enable
# to request none, the built-in default set or all supported options,
# respectively. A "no-" or "-" in the front of a facility name permit to
# remove/disable it from the currently applied set, e.g. "default,-nis"
# disables request for nis options.
# More specific variables as DHCLIENT_SET_DEFAULT_ROUTE,_SET_HOSTNAME or
# the MTU option have higher precedence.
#
DHCLIENT_UPDATE=""

## Type:        list(enabled,disabled,default,)
## Default:     ""
#
# Default is to use the FQDN option, when the DHCLIENT6_HOSTNAME_OPTION
# variable provides a hostname.
# When DHCLIENT6_HOSTNAME_OPTION is set to AUTO, short hostname from the
# /etc/hostname file is send (same to SLES-11).
#
DHCLIENT6_FQDN_ENABLED=""

## Type:        list(both,ptr,none,)
## Default:     ""
#
# Request to update AAAA and PTR or only the PTR DNS records using the
# hostname specified in DHCLIENT6_HOSTNAME_OPTION variable.
# Default is to update \fIboth\fR when hostname is given or \fInone\fR
# when hostname is empty and DHCLIENT6_FQDN_ENABLED is set to enabled.
#
DHCLIENT6_FQDN_UPDATE=""

## Type:        yesno
## Default:     yes
#
# Qualify relative sub-domains/hostname in the DHCLIENT6_HOSTNAME_OPTION
# variable adding a final dot ('foo.bar' -> 'foo.bar.').
# When disabled, the DHCP server may append it's update domain to the
# hostname (e.g. 'foo.bar' -> 'foo.bar.example.net').
#
DHCLIENT6_FQDN_QUALIFY="yes"

## Type:	list(,default,none,all,dns,ntp,tz,boot,nis,sip)
## Default:	""
#
# This variable permits to specify a space separated list of build-in
# facility names supported by the dhcp6 client modifying the default
# options used in requests and to update system settings (via netconfig).
#
# When empty, default settings configured in wicked-config(5) or built-in
# defaults are used. The special "default", "all", and "none" sets enable
# to request none, the built-in default set or all supported options,
# respectively. A "no-" or "-" in the front of a facility name permit to
# remove/disable it from the currently applied set, e.g. "default,-nis"
# disables request for nis options.
# The more specific variable DHCLIENT6_SET_HOSTNAME has higher precedence.
#
DHCLIENT6_UPDATE=""
## Path:	Network/DHCP/DHCP client
## Description:	DHCPv4 client configuration variables
#
# Note: 
# To configure one or more interfaces for DHCP configuration, you have to
# change the BOOTPROTO variable in /etc/sysconfig/network/ifcfg-<interface>
# to 'dhcp' (and possibly set STARTMODE='onboot'). 
#
# Most of the options can and should be overridden by per-interface
# settings in the ifcfg-* files.
#
# Note: NetworkManager is not using any sysconfig settings.
#

## Type:	yesno
## Default:	no
#
# Should the DHCPv4 client set the hostname? (yes|no)
# 
# When it is likely that this would occur during a running X session, 
# your DISPLAY variable could be screwed up and you won't be able to open
# new windows anymore, then this should be "no". 
#
# If it happens during booting it won't be a problem and you can 
# safely say "yes" here. For a roaming notebook with X kept running, "no"
# makes more sense. 
#
DHCLIENT_SET_HOSTNAME="yes"

## Type:	string
## Default:	AUTO
#
# Specifies the hostname option field when DHCPv4 client sends messages.
# Some DHCP servers will update nameserver entries (dynamic DNS) to it.
# Also, some DHCP servers, notably those used by @Home Networks, require
# the hostname option field containing a specific string in the DHCP
# messages from clients.
#
# When set to "AUTO", the current hostname from /etc/hostname is sent.
# Use this variable to override it with another hostname, or leave it
# empty to not send any hostname.
#
DHCLIENT_HOSTNAME_OPTION="AUTO"

## Type:	yesno
## Default:	yes
#
# Should the DHCP client set a default route (default Gateway) (yes|no)
#
# When multiple copies of dhcp client run, it would make sense that only
# one of them does it. 
#
DHCLIENT_SET_DEFAULT_ROUTE="yes"

## Type:        integer
## Default:     "0"
#
# This option allows to set a metrics/priority for DHCPv4 routes.
#
DHCLIENT_ROUTE_PRIORITY="0"

## Type:	string
## Default:	""
#
# specify a client ID
#
# Specifies a client identifier string. By default an id derived from the
# hardware address of the network interface is sent as client identifier.
#
DHCLIENT_CLIENT_ID=""

## Type:	string
## Default:	""
#
# Specifies the vendor class identifier string. The default is dhcp client
# specific.
#
DHCLIENT_VENDOR_CLASS_ID=""

## Type:        list<rfc3004,string>
## Default:     string
#
# Specifies the format of the DHCLIENT_USER_CLASS_ID variable.
#
# The DHCPv4 option and it's format is specified by RFC3004 as an array
# of class identifiers, but most DHCP clients/servers aren't compliant
# with the specification and send/expect a single string without proper
# RFC3004 length-value tuple format instead.
#
# When set to "rfc3004" DHCLIENT_USER_CLASS_ID[SUFFIX] permit an RFC
# compliant array, otherwise DHCLIENT_USER_CLASS_ID is used as string.
#
DHCLIENT_USER_CLASS_FORMAT=""

## Type:        string
## Default:     ""
## Suffix:      yes
#
# Specifies the user class identifier (array) to send in dhcp requests.
# The DHCLIENT_USER_CLASS_FORMAT variable specified how to interpret it.
#
DHCLIENT_USER_CLASS_ID=""

## Type:	integer
## Default:	""
#
# Specifies the lease time (in seconds), that is suggested to the
# server. Default is to use the lease time offered by the server.
#
DHCLIENT_LEASE_TIME=""

## Type:        yesno
## Default:     yes
#
# This setting controls whether dhcp client should try to use DHCP settings
# provided in its last lease when the dhcp-server is not reachable and
# the lease hasn't expired yet.
# Set this variable to "no" to disable the fallback to the last lease.
#
DHCLIENT_USE_LAST_LEASE="yes"

## Type:	yesno
## Default:	no
#
# Send a DHCPRELEASE to the server (sign off the address)? (yes|no)
# This may lead to getting a different address/hostname next time an address
# is requested. But some servers require it.
#
DHCLIENT_RELEASE_BEFORE_QUIT="no"

## Type:	integer
## Default:	0
#
# Some interfaces need time to initialize and/or do not report correct status.
# Add the latency time in seconds so these can be handled properly. Should
# probably set per interface rather than here.
# This setting causes a sleep time before dhcp clients are started regardless
# of the link status.
#
# Note: RFC 2131 specifies, that the dhcp client should wait a random time
# between one and ten seconds to desynchronize the use of DHCP at startup.
# We do not use this initial delay to not slow down start/boot time.
#
DHCLIENT_SLEEP="0"

## Type:	integer
## Default:	15
#
# The DHCPv4 client will try to get a lease for DHCLIENT_WAIT_AT_BOOT seconds,
# then inform ifup waiting for it, that it continues in background.
# When you increase this time, increase also the WAIT_FOR_INTERFACES variable
# e.g. to a value twice as high as the time specified here.
#
DHCLIENT_WAIT_AT_BOOT="15"

## Type:	integer
## Default:	"0"
#
# The DHCPv4 client will stop processing / fail after this time when it does
# not get a reply from the dhcp server. Before you set this variable, take a
# look at DHCLIENT_WAIT_AT_BOOT allowing to continue in background instead.
#
DHCLIENT_TIMEOUT="0"

## Path:	Network/DHCP/DHCPv6 client
## Description:	Global DHCPv6 client configuration

## Type:        list(auto,managed,info)
## Default:     auto
#
# This option allows to specify the request mode used by the DHCPv6
# client when the BOOTPROTO is set to dhcp or dhcp6, and overrides
# the "Managed Address Configuration" and the "Other Configuration"
# flags provided by the IPv6 router its Router Advertisement (RA)
# for the network connected to this interface.
#
#   auto:    follow RA flags, remain silent when no RA flag is set
#   info:    request other configuration (dns,ntp) only, no IP address
#   managed: request IP address as well as other configuration
#
DHCLIENT6_MODE="auto"

## Type:        yesno
### Default:     yes
#
# This option allows the DHCPv6 client to indicate its desire to accept
# rapid commit leases using two-packet exchange (solicitation, lease ack)
# instead of the four packet (solicitation, offer, request, lease ack).
#
DHCLIENT6_RAPID_COMMIT="yes"

## Type:	yesno
## Default:	no
#
# Should the DHCPv6 client set the hostname? (yes|no)
#
# When it is likely that this would occur during a running X session,
# your DISPLAY variable could be screwed up and you won't be able to
# open new windows anymore, then this should be "no".
#
# If it happens during booting it won't be a problem and you can
# safely say "yes" here. For a roaming notebook with X kept running,
# "no" makes more sense.
#
DHCLIENT6_SET_HOSTNAME="no"

## Type:        string
### Default:     AUTO
#
# Specifies the hostname option field when DHCPv6 client sends messages.
# Some DHCP servers will update nameserver entries (dynamic DNS) to it.
#
# When set to "AUTO", the current hostname from /etc/hostname is sent.
# Use this variable to override it with another hostname, or leave it
# empty to not send any hostname.
#
DHCLIENT6_HOSTNAME_OPTION="AUTO"

## Type:        integer
### Default:     ""
#
# Specifies the preferred lifetime (in seconds) used as T1/renewal
# (1/2 of it) and T1/rebind (4/5 of it) in DHCPv6 IA NA requests.
#
# Default is to not propose anything but use the times as offered
# by the DHCPv6 server.
#
DHCLIENT6_LEASE_TIME=""

## Type:        yesno
## Default:     yes
#
# This setting controls whether DHCPv6 client should try to use settings
# provided in its last lease when the DHCPv6-server is not reachable and
# the lease hasn't expired yet.
# Set this variable to "no" to disable the fallback to the last lease.
#
DHCLIENT6_USE_LAST_LEASE="yes"

## Type:	yesno
## Default:	no
#
# Send a DHCPv6 RELEASE to the server (sign off the address)? (yes|no)
# This may lead to getting a different address/hostname next time an address
# is requested. But some servers require it.
#
DHCLIENT6_RELEASE_BEFORE_QUIT="no"

## Type:	integer
## Default:	0
#
# Some interfaces need time to initialize and/or do not report correct status.
# By default, DHCPv6 waits until the link-local address (fe80::) is available
# and then ~1 second as specified by RFC3315.
# This setting allows override to use a non-standsrd initial delay.
#
DHCLIENT6_SLEEP="0"

## Type:	integer
## Default:	15
#
# The DHCPv6 client will try to get a lease for DHCLIENT6_WAIT_AT_BOOT seconds,
# then inform ifup waiting for it, that it continues in background.
# When you increase this time, increase also the WAIT_FOR_INTERFACES variable
# e.g. to a value twice as high as the time specified here.
#
DHCLIENT6_WAIT_AT_BOOT="15"

## Type:	integer
## Default:	"0"
#
# The dhcpv6 client will stop processing / fail after this time when it does
# not get a reply from the dhcp server. Before you set this variable, take a
# look at DHCLIENT6_WAIT_AT_BOOT allowing to continue in background instead.
#
DHCLIENT6_TIMEOUT="0"
07070100000023000081A4000003E800000064000000015DE541E80000003C000000000000000000000000000000000000006600000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/sysconfig/network/ifcfg-lan0BOOTPROTO='dhcp'
MTU=''
REMOTE_IPADDR=''
STARTMODE='onboot'
07070100000024000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005100000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/systemd07070100000025000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005800000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/systemd/system07070100000026000081A4000003E800000064000000015DE541E80000013D000000000000000000000000000000000000006E00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/systemd/system/RegisterFirst.service[Unit]
Description=Register System at first boot
After=network.target
Before=getty.target
ConditionFileNotEmpty=!/etc/zypp/repos.d/HPC_Module_15_SP1_x86_64:SLE-Module-HPC15-SP1-Pool.repo

[Service]
ExecStart=/usr/sbin/SUSEConnect -e EMAIL -r REGCODE
Type=oneshot
RemainAfterExit=true

[Install]
WantedBy=basic.target
07070100000027000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004E00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/udev07070100000028000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005600000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/udev/rules.d07070100000029000081A4000003E800000064000000015DE541E800000085000000000000000000000000000000000000006E00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/etc/udev/rules.d/70-persistent-net.rulesSUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="?*", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="?*", NAME="lan0"
0707010000002A000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004900000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/usr0707010000002B000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004D00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/usr/lib0707010000002C000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005500000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/usr/lib/systemd0707010000002D000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005C00000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/usr/lib/systemd/system0707010000002E000081A4000003E800000064000000015DE541E800000126000000000000000000000000000000000000007000000000clustduct-0.0.5/kiwi-descriptions/SUSE/x86_64/sle-hpc-15.2-JeOS/root/usr/lib/systemd/system/grub_config.service[Unit]
Description=Rebuild grub config from distro toolkit
ConditionPathExists=/.kiwi_grub_config.trigger

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'grub2-mkconfig -o /boot/grub2/grub.cfg'
ExecStartPost=/bin/bash -c 'rm -f /.kiwi_grub_config.trigger'

[Install]
WantedBy=multi-user.target
0707010000002F000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000002B00000000clustduct-0.0.5/kiwi-descriptions/openSUSE07070100000030000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000003200000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_6407070100000031000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004500000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS07070100000032000081A4000003E800000064000000015DE541E80000003C000000000000000000000000000000000000004E00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/DicefileDice.configure do |config|
  config.buildhost = :DOCKER
end
07070100000033000081ED000003E800000064000000015DE541E8000008F5000000000000000000000000000000000000004F00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/config.sh#!/bin/bash
#================
# FILE          : config.sh
#----------------
# PROJECT       : OpenSuSE KIWI Image System
# COPYRIGHT     : (c) 2006 SUSE LINUX Products GmbH. All rights reserved
#               :
# AUTHOR        : Marcus Schaefer <ms@suse.de>
#               :
# BELONGS TO    : Operating System images
#               :
# DESCRIPTION   : configuration script for SUSE based
#               : operating systems
#               :
#               :
# STATUS        : BETA
#----------------
#======================================
# Functions...
#--------------------------------------
test -f /.kconfig && . /.kconfig
test -f /.profile && . /.profile

#======================================
# Greeting...
#--------------------------------------
echo "Configure image: [$kiwi_iname]..."

#======================================
# Mount system filesystems
#--------------------------------------
baseMount

#======================================
# Setup baseproduct link
#--------------------------------------
suseSetupProduct

#======================================
# Add missing gpg keys to rpm
#--------------------------------------
suseImportBuildKey

#======================================
# Activate services
#--------------------------------------
suseInsertService sshd
if [[ ${kiwi_type} =~ oem|vmx ]];then
    suseInsertService grub_config
else
    suseRemoveService grub_config
fi

#======================================
# Setup default target, multi-user
#--------------------------------------
baseSetRunlevel 3

#==========================================
# remove package docs
#------------------------------------------
rm -rf /usr/share/doc/packages/*
rm -rf /usr/share/doc/manual/*
rm -rf /opt/kde*

#======================================
# only basic version of vim is
# installed; no syntax highlighting
#--------------------------------------
sed -i -e's/^syntax on/" syntax on/' /etc/vimrc

#======================================
# SuSEconfig
#--------------------------------------
suseConfig

#======================================
# Remove yast if not in use
#--------------------------------------
suseRemoveYaST

#======================================
# Umount kernel filesystems
#--------------------------------------
baseCleanMount

exit 0
07070100000034000081A4000003E800000064000000015DE541E800000EC3000000000000000000000000000000000000005000000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/config.xml<?xml version="1.0" encoding="utf-8"?>

<image schemaversion="6.8" name="Leap-HPC-15.0-JeOS">
    <description type="system">
        <author>Marcus Schaefer</author>
        <contact>ms@suse.de</contact>
        <specification>
            Leap 15.0 JeOS, is a small text based image
        </specification>
    </description>
    <preferences>
        <type image="iso" primary="true" flags="overlay" hybrid="true" firmware="efi" kernelcmdline="splash" hybridpersistent_filesystem="ext4" hybridpersistent="true" mediacheck="true"/>
        <version>1.15.0</version>
        <packagemanager>zypper</packagemanager>
        <locale>en_US</locale>
        <keytable>us</keytable>
        <timezone>Europe/Berlin</timezone>
        <rpm-excludedocs>true</rpm-excludedocs>
        <rpm-check-signatures>false</rpm-check-signatures>
        <bootsplash-theme>openSUSE</bootsplash-theme>
        <bootloader-theme>openSUSE</bootloader-theme>
    </preferences>
    <preferences>
        <type image="vmx" filesystem="ext4" bootloader="grub2" kernelcmdline="splash" firmware="efi"/>
        <type image="oem" filesystem="ext4" initrd_system="dracut" installpxe="true" bootloader="grub2" kernelcmdline="splash" firmware="efi">
            <oemconfig>
                <oem-systemsize>2048</oem-systemsize>
                <oem-swap>true</oem-swap>
                <oem-device-filter>/dev/ram</oem-device-filter>
                <oem-multipath-scan>false</oem-multipath-scan>
		<oem-unattended>true</oem-unattended>
            </oemconfig>
            <machine memory="512" guestOS="suse" HWversion="4">
                <vmdisk id="0" controller="ide"/>
                <vmnic driver="e1000" interface="0" mode="bridged"/>
            </machine>
        </type>
    </preferences>
    <users>
        <user password="$1$wYJUgpM5$RXMMeASDc035eX.NbYWFl0" home="/root" name="root" groups="root"/>
    </users>
    <repository type="rpm-md" alias="kiwi" priority="1">
        <source path="obs://Virtualization:Appliances:Builder/openSUSE_Leap_15.0"/>
    </repository>
    <repository type="rpm-md" alias="Leap_15_0" imageinclude="true">
        <source path="obs://openSUSE:Leap:15.0/standard"/>
    </repository>
    <packages type="image">
        <package name="checkmedia"/>
        <package name="patterns-openSUSE-base"/>
        <package name="ifplugd"/>
        <package name="iputils"/>
        <package name="vim"/>
        <package name="grub2"/>
        <package name="grub2-x86_64-efi" arch="x86_64"/>
        <package name="grub2-i386-pc"/>
        <package name="haveged"/>
        <package name="syslinux"/>
        <package name="lvm2"/>
        <package name="fontconfig"/>
        <package name="fonts-config"/>
        <package name="tar"/>
        <package name="parted"/>
        <package name="openssh"/>
        <package name="iproute2"/>
        <package name="less"/>
        <package name="bash-completion"/>
        <package name="dhcp-client"/>
        <package name="which"/>
        <package name="salt-minion"/>
        <package name="shim"/>
        <package name="kernel-default"/>
        <package name="timezone"/>
    </packages>
    <packages type="iso">
        <package name="gfxboot-branding-openSUSE"/>
        <package name="dracut-kiwi-live"/>
    </packages>
    <packages type="oem">
        <package name="gfxboot-branding-openSUSE"/>
        <package name="dracut-kiwi-oem-repart"/>
        <package name="dracut-kiwi-oem-dump"/>
    </packages>
    <packages type="bootstrap">
        <package name="udev"/>
        <package name="filesystem"/>
        <package name="glibc-locale"/>
        <package name="cracklib-dict-full"/>
        <package name="ca-certificates"/>
        <package name="openSUSE-release"/>
    </packages>
</image>
07070100000035000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004A00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root07070100000036000081A4000003E800000064000000015DE541E800000000000000000000000000000000000000000000006400000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/.kiwi_grub_config.trigger07070100000037000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004E00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc07070100000038000081A4000003E800000064000000015DE541E80000008B000000000000000000000000000000000000005300000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/motdThis is the Leap 15.0 JeOS SuSE Linux System.
To upgrade your system call:

        zypper refresh
        zypper up

Have a lot of fun...
07070100000039000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005800000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/sysconfig0707010000003A000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000006000000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/sysconfig/network0707010000003B000081A4000003E800000064000000015DE541E80000325F000000000000000000000000000000000000006500000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/sysconfig/network/dhcp## Type:        list(enabled,disabled,default,)
## Default:     ""
#
# Default is to use the FQDN option, when the DHCLIENT_HOSTNAME_OPTION
# variable is set to a full hostname, that is, when it contains a dot.
# When DHCLIENT_HOSTNAME_OPTION is set to AUTO, short hostname from
# /etc/hostname is send via hostname option 12 (same as SLES-11).
#
DHCLIENT_FQDN_ENABLED=""

## Type:        list(both,ptr,none,)
## Default:     ""
#
# Request to update A and PTR or only the PTR DNS records using the
# hostname specified in DHCLIENT_HOSTNAME_OPTION variable.
# Default is to update 'both' when hostname is set or 'none' when
# the hostname is empty and DHCLIENT_FQDN_ENABLED is set to enabled.
#
DHCLIENT_FQDN_UPDATE=""

## Type:        yesno
## Default:     yes
#
# Qualify relative sub-domains/hostname in the DHCLIENT_HOSTNAME_OPTION
# variable adding a final dot ('foo.bar' -> 'foo.bar.').
# When disabled, the DHCP server may append it's update domain to the
# hostname (e.g. 'foo.bar' -> 'foo.bar.example.net').
#
DHCLIENT_FQDN_QUALIFY="yes"

## Type:        yesno
## Default:     yes
#
# The FQDN option is encoding hostnames using canonical DNS wire format
# by default. This flag permits to enable use of the deprecated ascii
# format limited to a single label (host hostname) for compatibility
# purposes with draft implementation, which may be unsupported and cause
# that a DHCP server ignores the fqdn option request completely.
#
DHCLIENT_FQDN_ENCODE="yes"

## Type:	list(,default,none,all,dns,ntp,nis,tz,boot,smb,nds,slp,sip,log)
## Default:	""
#
# This variable permits to specify a space separated list of build-in
# facility names supported by the dhcp4 client modifying the default
# options used in requests and to update system settings (via netconfig).
#
# When empty, default settings configured in wicked-config(5) or built-in
# defaults are used. The special "default", "all", and "none" sets enable
# to request none, the built-in default set or all supported options,
# respectively. A "no-" or "-" in the front of a facility name permit to
# remove/disable it from the currently applied set, e.g. "default,-nis"
# disables request for nis options.
# More specific variables as DHCLIENT_SET_DEFAULT_ROUTE,_SET_HOSTNAME or
# the MTU option have higher precedence.
#
DHCLIENT_UPDATE=""

## Type:        list(enabled,disabled,default,)
## Default:     ""
#
# Default is to use the FQDN option, when the DHCLIENT6_HOSTNAME_OPTION
# variable provides a hostname.
# When DHCLIENT6_HOSTNAME_OPTION is set to AUTO, short hostname from the
# /etc/hostname file is send (same to SLES-11).
#
DHCLIENT6_FQDN_ENABLED=""

## Type:        list(both,ptr,none,)
## Default:     ""
#
# Request to update AAAA and PTR or only the PTR DNS records using the
# hostname specified in DHCLIENT6_HOSTNAME_OPTION variable.
# Default is to update \fIboth\fR when hostname is given or \fInone\fR
# when hostname is empty and DHCLIENT6_FQDN_ENABLED is set to enabled.
#
DHCLIENT6_FQDN_UPDATE=""

## Type:        yesno
## Default:     yes
#
# Qualify relative sub-domains/hostname in the DHCLIENT6_HOSTNAME_OPTION
# variable adding a final dot ('foo.bar' -> 'foo.bar.').
# When disabled, the DHCP server may append it's update domain to the
# hostname (e.g. 'foo.bar' -> 'foo.bar.example.net').
#
DHCLIENT6_FQDN_QUALIFY="yes"

## Type:	list(,default,none,all,dns,ntp,tz,boot,nis,sip)
## Default:	""
#
# This variable permits to specify a space separated list of build-in
# facility names supported by the dhcp6 client modifying the default
# options used in requests and to update system settings (via netconfig).
#
# When empty, default settings configured in wicked-config(5) or built-in
# defaults are used. The special "default", "all", and "none" sets enable
# to request none, the built-in default set or all supported options,
# respectively. A "no-" or "-" in the front of a facility name permit to
# remove/disable it from the currently applied set, e.g. "default,-nis"
# disables request for nis options.
# The more specific variable DHCLIENT6_SET_HOSTNAME has higher precedence.
#
DHCLIENT6_UPDATE=""
## Path:	Network/DHCP/DHCP client
## Description:	DHCPv4 client configuration variables
#
# Note: 
# To configure one or more interfaces for DHCP configuration, you have to
# change the BOOTPROTO variable in /etc/sysconfig/network/ifcfg-<interface>
# to 'dhcp' (and possibly set STARTMODE='onboot'). 
#
# Most of the options can and should be overridden by per-interface
# settings in the ifcfg-* files.
#
# Note: NetworkManager is not using any sysconfig settings.
#

## Type:	yesno
## Default:	no
#
# Should the DHCPv4 client set the hostname? (yes|no)
# 
# When it is likely that this would occur during a running X session, 
# your DISPLAY variable could be screwed up and you won't be able to open
# new windows anymore, then this should be "no". 
#
# If it happens during booting it won't be a problem and you can 
# safely say "yes" here. For a roaming notebook with X kept running, "no"
# makes more sense. 
#
DHCLIENT_SET_HOSTNAME="yes"

## Type:	string
## Default:	AUTO
#
# Specifies the hostname option field when DHCPv4 client sends messages.
# Some DHCP servers will update nameserver entries (dynamic DNS) to it.
# Also, some DHCP servers, notably those used by @Home Networks, require
# the hostname option field containing a specific string in the DHCP
# messages from clients.
#
# When set to "AUTO", the current hostname from /etc/hostname is sent.
# Use this variable to override it with another hostname, or leave it
# empty to not send any hostname.
#
DHCLIENT_HOSTNAME_OPTION="AUTO"

## Type:	yesno
## Default:	yes
#
# Should the DHCP client set a default route (default Gateway) (yes|no)
#
# When multiple copies of dhcp client run, it would make sense that only
# one of them does it. 
#
DHCLIENT_SET_DEFAULT_ROUTE="yes"

## Type:        integer
## Default:     "0"
#
# This option allows to set a metrics/priority for DHCPv4 routes.
#
DHCLIENT_ROUTE_PRIORITY="0"

## Type:	string
## Default:	""
#
# specify a client ID
#
# Specifies a client identifier string. By default an id derived from the
# hardware address of the network interface is sent as client identifier.
#
DHCLIENT_CLIENT_ID=""

## Type:	string
## Default:	""
#
# Specifies the vendor class identifier string. The default is dhcp client
# specific.
#
DHCLIENT_VENDOR_CLASS_ID=""

## Type:        list<rfc3004,string>
## Default:     string
#
# Specifies the format of the DHCLIENT_USER_CLASS_ID variable.
#
# The DHCPv4 option and it's format is specified by RFC3004 as an array
# of class identifiers, but most DHCP clients/servers aren't compliant
# with the specification and send/expect a single string without proper
# RFC3004 length-value tuple format instead.
#
# When set to "rfc3004" DHCLIENT_USER_CLASS_ID[SUFFIX] permit an RFC
# compliant array, otherwise DHCLIENT_USER_CLASS_ID is used as string.
#
DHCLIENT_USER_CLASS_FORMAT=""

## Type:        string
## Default:     ""
## Suffix:      yes
#
# Specifies the user class identifier (array) to send in dhcp requests.
# The DHCLIENT_USER_CLASS_FORMAT variable specified how to interpret it.
#
DHCLIENT_USER_CLASS_ID=""

## Type:	integer
## Default:	""
#
# Specifies the lease time (in seconds), that is suggested to the
# server. Default is to use the lease time offered by the server.
#
DHCLIENT_LEASE_TIME=""

## Type:        yesno
## Default:     yes
#
# This setting controls whether dhcp client should try to use DHCP settings
# provided in its last lease when the dhcp-server is not reachable and
# the lease hasn't expired yet.
# Set this variable to "no" to disable the fallback to the last lease.
#
DHCLIENT_USE_LAST_LEASE="yes"

## Type:	yesno
## Default:	no
#
# Send a DHCPRELEASE to the server (sign off the address)? (yes|no)
# This may lead to getting a different address/hostname next time an address
# is requested. But some servers require it.
#
DHCLIENT_RELEASE_BEFORE_QUIT="no"

## Type:	integer
## Default:	0
#
# Some interfaces need time to initialize and/or do not report correct status.
# Add the latency time in seconds so these can be handled properly. Should
# probably set per interface rather than here.
# This setting causes a sleep time before dhcp clients are started regardless
# of the link status.
#
# Note: RFC 2131 specifies, that the dhcp client should wait a random time
# between one and ten seconds to desynchronize the use of DHCP at startup.
# We do not use this initial delay to not slow down start/boot time.
#
DHCLIENT_SLEEP="0"

## Type:	integer
## Default:	15
#
# The DHCPv4 client will try to get a lease for DHCLIENT_WAIT_AT_BOOT seconds,
# then inform ifup waiting for it, that it continues in background.
# When you increase this time, increase also the WAIT_FOR_INTERFACES variable
# e.g. to a value twice as high as the time specified here.
#
DHCLIENT_WAIT_AT_BOOT="15"

## Type:	integer
## Default:	"0"
#
# The DHCPv4 client will stop processing / fail after this time when it does
# not get a reply from the dhcp server. Before you set this variable, take a
# look at DHCLIENT_WAIT_AT_BOOT allowing to continue in background instead.
#
DHCLIENT_TIMEOUT="0"

## Path:	Network/DHCP/DHCPv6 client
## Description:	Global DHCPv6 client configuration

## Type:        list(auto,managed,info)
## Default:     auto
#
# This option allows to specify the request mode used by the DHCPv6
# client when the BOOTPROTO is set to dhcp or dhcp6, and overrides
# the "Managed Address Configuration" and the "Other Configuration"
# flags provided by the IPv6 router its Router Advertisement (RA)
# for the network connected to this interface.
#
#   auto:    follow RA flags, remain silent when no RA flag is set
#   info:    request other configuration (dns,ntp) only, no IP address
#   managed: request IP address as well as other configuration
#
DHCLIENT6_MODE="auto"

## Type:        yesno
### Default:     yes
#
# This option allows the DHCPv6 client to indicate its desire to accept
# rapid commit leases using two-packet exchange (solicitation, lease ack)
# instead of the four packet (solicitation, offer, request, lease ack).
#
DHCLIENT6_RAPID_COMMIT="yes"

## Type:	yesno
## Default:	no
#
# Should the DHCPv6 client set the hostname? (yes|no)
#
# When it is likely that this would occur during a running X session,
# your DISPLAY variable could be screwed up and you won't be able to
# open new windows anymore, then this should be "no".
#
# If it happens during booting it won't be a problem and you can
# safely say "yes" here. For a roaming notebook with X kept running,
# "no" makes more sense.
#
DHCLIENT6_SET_HOSTNAME="no"

## Type:        string
### Default:     AUTO
#
# Specifies the hostname option field when DHCPv6 client sends messages.
# Some DHCP servers will update nameserver entries (dynamic DNS) to it.
#
# When set to "AUTO", the current hostname from /etc/hostname is sent.
# Use this variable to override it with another hostname, or leave it
# empty to not send any hostname.
#
DHCLIENT6_HOSTNAME_OPTION="AUTO"

## Type:        integer
### Default:     ""
#
# Specifies the preferred lifetime (in seconds) used as T1/renewal
# (1/2 of it) and T1/rebind (4/5 of it) in DHCPv6 IA NA requests.
#
# Default is to not propose anything but use the times as offered
# by the DHCPv6 server.
#
DHCLIENT6_LEASE_TIME=""

## Type:        yesno
## Default:     yes
#
# This setting controls whether DHCPv6 client should try to use settings
# provided in its last lease when the DHCPv6-server is not reachable and
# the lease hasn't expired yet.
# Set this variable to "no" to disable the fallback to the last lease.
#
DHCLIENT6_USE_LAST_LEASE="yes"

## Type:	yesno
## Default:	no
#
# Send a DHCPv6 RELEASE to the server (sign off the address)? (yes|no)
# This may lead to getting a different address/hostname next time an address
# is requested. But some servers require it.
#
DHCLIENT6_RELEASE_BEFORE_QUIT="no"

## Type:	integer
## Default:	0
#
# Some interfaces need time to initialize and/or do not report correct status.
# By default, DHCPv6 waits until the link-local address (fe80::) is available
# and then ~1 second as specified by RFC3315.
# This setting allows override to use a non-standsrd initial delay.
#
DHCLIENT6_SLEEP="0"

## Type:	integer
## Default:	15
#
# The DHCPv6 client will try to get a lease for DHCLIENT6_WAIT_AT_BOOT seconds,
# then inform ifup waiting for it, that it continues in background.
# When you increase this time, increase also the WAIT_FOR_INTERFACES variable
# e.g. to a value twice as high as the time specified here.
#
DHCLIENT6_WAIT_AT_BOOT="15"

## Type:	integer
## Default:	"0"
#
# The dhcpv6 client will stop processing / fail after this time when it does
# not get a reply from the dhcp server. Before you set this variable, take a
# look at DHCLIENT6_WAIT_AT_BOOT allowing to continue in background instead.
#
DHCLIENT6_TIMEOUT="0"
0707010000003C000081A4000003E800000064000000015DE541E80000003C000000000000000000000000000000000000006B00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/sysconfig/network/ifcfg-lan0BOOTPROTO='dhcp'
MTU=''
REMOTE_IPADDR=''
STARTMODE='onboot'
0707010000003D000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005300000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/udev0707010000003E000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005B00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/udev/rules.d0707010000003F000081A4000003E800000064000000015DE541E800000085000000000000000000000000000000000000007300000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/etc/udev/rules.d/70-persistent-net.rulesSUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="?*", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="?*", NAME="lan0"
07070100000040000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000004E00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/usr07070100000041000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005200000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/usr/lib07070100000042000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000005A00000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/usr/lib/systemd07070100000043000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000006100000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/usr/lib/systemd/system07070100000044000081A4000003E800000064000000015DE541E800000126000000000000000000000000000000000000007500000000clustduct-0.0.5/kiwi-descriptions/openSUSE/x86_64/leap-hpc-15.0-JeOS/root/usr/lib/systemd/system/grub_config.service[Unit]
Description=Rebuild grub config from distro toolkit
ConditionPathExists=/.kiwi_grub_config.trigger

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'grub2-mkconfig -o /boot/grub2/grub.cfg'
ExecStartPost=/bin/bash -c 'rm -f /.kiwi_grub_config.trigger'

[Install]
WantedBy=multi-user.target
07070100000045000041ED000003E800000064000000015DE541E800000000000000000000000000000000000000000000001400000000clustduct-0.0.5/src07070100000046000081ED000003E800000064000000015DE541E800003922000000000000000000000000000000000000002200000000clustduct-0.0.5/src/bfcommons.lua#!/usr/bin/lua
-- simple print function for tables
function tprint (t, s)
    for k, v in pairs(t) do
        local kfmt = '["' .. tostring(k) ..'"]'
        if type(k) ~= 'string' then
            kfmt = '[' .. k .. ']'
        end
        local vfmt = '"'.. tostring(v) ..'"'
        if type(v) == 'table' then
            tprint(v, (s or '')..kfmt)
        else
            if type(v) ~= 'string' then
                vfmt = tostring(v)
            end
            print(type(t)..(s or '')..kfmt..' = '..vfmt)
        end
    end
end
-- common lua pxe/efi file functions is called from clustuct
-- and clustuctbf

function create_entry_pxe(entry,name)
	name = name or "Boot_to_the_unknown"
	ret_str = ""
	ret_str = ret_str.."LABEL "..name.."\n"
	if entry["menu"] ~= nil then 
		ret_str = ret_str.."\tMENU LABEL "..entry["menu"].."\n"
	else
		ret_str = ret_str.."\tMENU LABEL "..name.."\n"
	end
	if entry["com32"] ~= nil then 
		ret_str = ret_str.."\tCOM32 "..entry["com32"].."\n"
	end
	if entry["kernel"] ~= nil then 
		ret_str = ret_str.."\tKERNEL "..entry["kernel"].."\n"
	end
	if entry["append"] ~= nil or entry["initrd"] ~= nil then 
		ret_str = ret_str.."\tAPPEND "
		if entry["append"] ~= nil then
			ret_str = ret_str..entry["append"].." " end
		if entry["initrd"] ~= nil then
			ret_str = ret_str.."initrd="..entry["initrd"].." " end
	end
	for i = 0,100 do 
		local pxe_key = "pxe"..i
		if entry[pxe_key] ~= nil then
			ret_str = ret_str..entry[pxe_key].."\n" end
	end
	ret_str = ret_str.."\n"
	return ret_str
end

function create_pxe_node_file(node,handle,config) 
	if config.clustduct["overwrite"] == nil then config.clustduct["overwrite"] = false end
	local file, err = io.open(config.clustduct["confdir"].."/pxe_iptemplate","r")
	if not file then error(err) end
	local pxe_template = file:read("*a")
	file:close()
	-- now create boot entry table
	local sentr = ""
	local entry_name = {}
	local node_args = handle:getattr(node)
	pxe_template = string.gsub(pxe_template,"$NODE",node)	
	if node_args["ip"] ~= nil then 
		pxe_template = string.gsub(pxe_template,"$IP",node_args["ip"]) end
	if node_args["mac"] ~= nil then 
		pxe_template = string.gsub(pxe_template,"$MAC",node_args["mac"]) 
	else
		pxe_template = string.gsub(pxe_template,"$MAC","No mac specified") 
	end
	if node_args["boot"] ~= nil then
		local boot_args = handle:getattr(node_args["boot"])
		if boot_args ~= nil then
			sentr = sentr..create_entry_pxe(boot_args,node_args["boot"]) 
			entry_name[node_args["boot"]] = true
	end end
	if node_args["install"] ~= nil then
		local boot_args = handle:getattr(node_args["install"])
		if boot_args ~= nil then
			sentr = sentr..create_entry_pxe(boot_args,node_args["install"]) 
			entry_name[node_args["install"]] = true
	end end
	local mand_entries = handle:query("mandatory")
	if mand_entries ~= nil then  
		for key,value in pairs(mand_entries) do
			if entry_name[value] == nil then 
				local boot_args = handle:getattr(value)
				sentr = sentr..create_entry_pxe(boot_args,value)
				entry_name[value] = true
			end
		end
	end
	sentr = clean_genders_str(sentr)
	pxe_template = string.gsub(pxe_template,"$ENTRY",sentr)	

	local ofile_name = config.clustduct['tftpdir']..'/'..config.clustduct["outdir"].."/"
	ofile_name = string.gsub(ofile_name,"//","/")
	ofile_name = ofile_name.."clustduct_node."..node..".pxe"
	if not file_exists(ofile_name) or config.clustduct["overwrite"] then
		local ofile, err = io.open(ofile_name,"w")
		if err ~= nil then
			error(err)
		end
		ofile:write(pxe_template)
		ofile:close()
	end
	if node_args["mac"] ~= nil then 
		local mac_filename = config.clustduct["tftpdir"].."/"
		mac_filename = mac_filename.."pxelinux.cfg/"..config.clustduct["netclass"].."-"..node_args["mac"]
		mac_filename = string.gsub(mac_filename,":","-")
		mac_filename = string.gsub(mac_filename,"//","/")
		if not file_exists(mac_filename) or config.clustduct["overwrite"] then
			local mac_file_out = "# Hardware specific node file automatically generated by clustduct\nDEFAULT menu.c32\nAPPEND "..ofile_name
			local ofile, err = io.open(mac_filename,"w")
			if err ~= nil then
				error(err)
			end
			ofile:write(mac_file_out)
			ofile:close()
		end
	end
end
function create_entry_grub(entry,name)
	ret_str = ""
	ret_str = ret_str.."menuentry"
	name = name or "Boot_to_the_unknown"
	if entry["menu"] ~= nil then 
		ret_str = ret_str.." '"..entry["menu"].."' {\n\tset gfxpayload=keep\n"
	else
		ret_str = ret_str.." '"..name.."' {\n\tset gfxpayload=keep\n"
	end
	if entry["kernel"] ~= nil then 
		ret_str = ret_str.."\techo 'Loading kernel ...'\n\tlinuxefi "..entry["kernel"] end
	if entry["linuxefi"] ~= nil then 
		ret_str = ret_str.."\techo 'Loading kernel ...'\n\tlinuxefi "..entry["linuxefi"] end
	if entry["append"] ~= nil and 
		(entry["kernel"] ~= nil or entry["linuxefi"] ~= nil ) then
		ret_str = ret_str.." "..entry["append"].."\n" end
	if entry["initrd"] ~= nil then
		ret_str = ret_str.."\techo 'Loading initial ramdisk ...'\n\tinitrdefi "..entry["initrd"].."\n" end
	if entry["initrdefi"] ~= nil then
		ret_str = ret_str.."\tinitrdefi "..entry["initrdefi"].."\n" end
	if entry["set"] ~= nil then
		ret_str = ret_str.."\tset "..entry["set"].."\n" end
	if entry["chainloader"] ~= nil then
		ret_str = ret_str.."\tchainloader"..entry["chainloader"].."\n" end
	if entry["grub"] ~= nil then
		ret_str = ret_str.."\t"..entry["grub"].."\n" end
	for i = 0,100 do 
		local grub_key = "grub"..i
		if entry[grub_key] ~= nil then
			ret_str = ret_str..entry[grub_key].."\n" end
	end
	ret_str = ret_str.."\n}\n"
	return ret_str
end

function create_grub_node_file(node,handle,config) 
	if config.clustduct["overwrite"] == nil then config.clustduct["overwrite"] = false end
	local file, err = io.open(config.clustduct["confdir"].."/grub_iptemplate","r")
	if not file then error(err) end
	local grub_template = file:read("*a")
	file:close()
	-- now create boot entry table
	local sentr = ""
	local entry_name = {} 
	local node_args = handle:getattr(node)
	grub_template = string.gsub(grub_template,"$NODE",node)	
	if node_args["ip"] ~= nil then 
		grub_template = string.gsub(grub_template,"$IP",node_args["ip"]) end
	if node_args["mac"] ~= nil then 
		grub_template = string.gsub(grub_template,"$MAC",node_args["mac"]) 
	else
		grub_template = string.gsub(grub_template,"$MAC","No mac specified") 
	end
	if node_args["boot"] ~= nil then
		local boot_args = handle:getattr(node_args["boot"])
		if boot_args ~= nil then
			sentr = sentr..create_entry_grub(boot_args,node_args)
			entry_name[node_args["boot"]] = true
	end end
	if node_args["install"] ~= nil then
		local boot_args = handle:getattr(node_args["install"])
		if boot_args ~= nil then
			sentr = sentr..create_entry_grub(boot_args,node_args["install"])
			entry_name[node_args["install"]] = true
	end end
	local mand_entries = handle:query("mandatory")
	if mand_entries ~= nil then  
		for key,value in pairs(mand_entries) do
			if entry_name[value] == nil then 
				local boot_args = handle:getattr(value)
				sentr = sentr..create_entry_grub(boot_args,value)
				entry_name[value] = true
			end
		end
	end
	sentr = clean_genders_str(sentr)
	grub_template = string.gsub(grub_template,"$ENTRY",sentr)	

	local ofile_name = config.clustduct['tftpdir']..'/'..config.clustduct["outdir"].."/"
	ofile_name = string.gsub(ofile_name,"//","/")
	ofile_name = ofile_name.."clustduct_node."..node..".grub"
	if not file_exists(ofile_name) or config.clustduct["overwrite"] then
		local ofile, err = io.open(ofile_name,"w")
		if err ~= nil then
			error(err)
		end
		ofile:write(grub_template)
		ofile:close()
	end
	local ip_filename = config.clustduct['tftpdir']..'/'..config.clustduct["outdir"].."/"
	ip_filename = string.gsub(ip_filename,"//","/")
	ip_filename = ip_filename.."grub.cfg."..node_args["ip"]
	if not file_exists(ip_filename) or config.clustduct["overwrite"] then
		local ip_file_out = "# IP specific configfile automatically generated by clustduct\nconfigfile "..config.clustduct["outdir"].."/".."clustduct_node."..node..".grub"
		ip_file_out = string.gsub(ip_file_out,"//","/")
		local ofile, err = io.open(ip_filename,"w")
		if err ~= nil then
			error(err)
		end
		ofile:write(ip_file_out)
		ofile:close()
	end
	if node_args["mac"] ~= nil then 
		local mac_filename = config.clustduct["tftpdir"].."/"
		mac_filename = mac_filename.."pxelinux.cfg/clustduct_"..node_args["mac"]..".grub"
		mac_filename = string.gsub(mac_filename,"//","/")
		if not file_exists(mac_filename) or config.clustduct["overwrite"] then
			local mac_file_out = "# Hardware specific node file automatically generated by clustduct\nset timeout=1\nmenuentry 'Call node specific file' {\n\tconfigfile "..ofile_name.."\n}"
			local ofile, err = io.open(mac_filename,"w")
			if err ~= nil then
				error(err)
			end
			ofile:write(mac_file_out)
			ofile:close()
		end
	end

end

function create_pxe_structure(handle,config)
	if config.clustduct["overwrite"] == nil then config.clustduct["overwrite"] = false end
	if config.clustduct["base"] == nil then config.clustduct["base"] = 10 end
	local incrementcount=0
	local nodes = handle:query("ip")
	-- nr_nodes=$(nodeattr -f $GENDERSFILE -n ip | wc -l)
	-- base=${BASE:-10}
	local exponent = math.floor(math.log(#nodes)/math.log(config.clustduct["base"]))
	local counter=1
	local level=0
	local i=1
	local output_str = "# Syslinux boot structure automatically generated by clustduct\n"
	-- clean up preexisting entries
	local ofile_name = config.clustduct['tftpdir']..'/'..config.clustduct["outdir"].."/"
	ofile_name = string.gsub(ofile_name,"//","/")
	ofile_name = ofile_name.."menu.pxe"
	if not config.clustduct["overwrite"] then
		if file_exists(ofile_name) then return end
	end
	for key, node in pairs(nodes)  do
		if counter == 1  then
			for n = 1, exponent  do
				local modulo = (i-1)%(config.clustduct["base"]^n)
				if modulo == 0  then
					output_str = output_str.."MENU BEGIN list_"..node.."\nMENU LABEL Boot "..node.." to ENDNODE\n"
					level = level+1
				end
			end
		end	
		-- to pxe menu structure
		output_str = output_str.."LABEL "..node.."\n\tMENU LABEL Boot as node "..node.."\n\tKERNEL menu.c32\n\tAPPEND "..config.clustduct["outdir"].."/clustduct_node."..node..".pxe\n"
		-- to the node file
		create_pxe_node_file(node,handle,config) 
		if counter == config.clustduct["base"] or i == #nodes then
			for n = 1, exponent do
				local modulo = i%(config.clustduct["base"]^n)
				if modulo == 0 or i == #nodes then
					output_str = output_str.."LABEL go_back\n\tMENU LABEL Go back...\n\tMENU EXIT\nMENU END\n"
					output_str = string.gsub(output_str,"ENDNODE",node)

					level = level - 1
				end
			end
		end
		if counter < config.clustduct["base"]  then
			counter = counter + 1
		else
			counter = 1
		end
		i = i + 1
	end
	for n = 1, level do
		output_str = output_str.."LABEL go_back\n\tMENU LABEL Go back...\n\tMENU EXIT\n\tMENU END\n"
	end
	output_str = output_str.."LABEL reboot\n\tMENU LABEL Reboot\n\tCOM32 reboot.c32\n"
	if not file_exists(ofile_name) or config.clustduct["overwrite"] then
		local ofile, err = io.open(ofile_name,"w")
		if err ~= nil then
			error(err)
		end
		ofile:write(output_str)
		ofile:close()
	end

end

function create_grub_structure(handle,config)
	if config.clustduct["overwrite"] == nil then config.clustduct["overwrite"] = false end
	if config.clustduct["base"] == nil then config.clustduct["base"] = 10 end
	local incrementcount=0
	local nodes = handle:query("ip")
	-- nr_nodes=$(nodeattr -f $GENDERSFILE -n ip | wc -l)
	-- base=${BASE:-10}
	local exponent = math.floor(math.log(#nodes)/math.log(config.clustduct["base"]))
	local counter = 1
	local i=1
	local output_str = "# Grub boot structure automatically generated by clustduct\n"
	local menu_str = ""
	-- clean up preexisting entries
	local ofile_name_base = config.clustduct['tftpdir']..'/'..config.clustduct["outdir"].."/"
	ofile_name_base = string.gsub(ofile_name_base,"//","/")
	local ofile_name = ""
	for key, node in pairs(nodes)  do
		if counter == 1  then
			output_str = "set timeout=10\n"
			for n = 1, exponent  do
				local modulo = (i-1)%(config.clustduct["base"]^n)
				if modulo == 0  then
					-- output_str = "set timeout=10\nmenuentry 'Boot from node "..node.." to ENDNODE {\n"
					ofile_name = ofile_name_base.."node_"..i
					menu_str = menu_str.."menuentry 'Boot from "..node
				end
			end
		end	
		-- to grub menu structure
		output_str = output_str.."menuentry 'Boot as "..node.."' {\n\tconfigfile "..config.clustduct["outdir"].."/clustduct_node."..node..".grub\n}\n"
		-- to the node file
		create_grub_node_file(node,handle,config) 
		if counter < config.clustduct["base"] and i ~= #nodes then
			counter = counter + 1
		else
			output_str = output_str.."menuentry 'Go back...' {\n\tconfigfile "..config.clustduct["outdir"].."/menu.grub\n}\n"
			ofile_name = ofile_name.."_to_node_"..i..".grub"
			menu_str = menu_str.." to "..node.."' {\n\t".."configfile "..ofile_name.."\n}\n"
			-- dirty trick to remove leading configdir
			menu_str = string.gsub(menu_str,config.clustduct['tftpdir'],'')
			if not file_exists(ofile_name) or config.clustduct["overwrite"] then
				local ofile, err = io.open(ofile_name,"w")
				if err ~= nil then
					error(err)
				end
				ofile:write(output_str)
				ofile:close()
			end
			counter = 1
		end
		i = i + 1
	end
	local menu_file_str = config.clustduct['tftpdir']..'/'..config.clustduct["outdir"].."/"
	menu_file_str = string.gsub(menu_file_str,"//","/")
	menu_file_str = menu_file_str.."menu.grub"
	if not file_exists(menu_file_str) or config.clustduct["overwrite"] then
		local ofile, err = io.open(menu_file_str,"w")
		if err ~= nil then
			error(err)
		end
		ofile:write(menu_str)
		ofile:close()
	end
	-- output_str = output_str.."LABEL go_back\n\tMENU LABEL Go back...\n\tKERNEL menu.c32\n\tAPPEND ~\n"


end

function clean_genders(table)
	for key,value in pairs(table) do 
		local t_str = value
		t_str = string.gsub(t_str,"\\ws"," ")
		t_str = string.gsub(t_str,"\\eq","=")
		t_str = string.gsub(t_str,"\\co",",")
		table[key] = t_str
	end
end

function clean_genders_str(str)
	str = string.gsub(str,"\\ws"," ")
	str = string.gsub(str,"\\eq","=")
	str = string.gsub(str,"\\co",",")
	return str
end

function create_entry(entry,entries,handle)
	-- avoid double entries
	if entries[entry] ~= nil then return end
	local boot_args = handle:getattr(entry)
	if boot_args ~= nil then 
		-- do the pattern substiutions like \eq -> = here
		clean_genders(boot_args)
		entries[entry] = boot_args
	end

end

function file_exists(name)
	local f=io.open(name,"r")
	if f~=nil then io.close(f) return true else return false end
end
07070100000047000081ED000003E800000064000000015DE541E8000027F9000000000000000000000000000000000000002200000000clustduct-0.0.5/src/clustduct.lua#!/usr/bin/lua
-- handle must be global
handle = nil
cnf_filename = "/etc/clustduct.conf"
need_signal = false
-- read the config
local config = {}

-- update given file with the line first_arg.." "..second_arg
-- but checks if string is present in file
-- also the variable need_signal is set to true if the file is modified

function update_file(first_arg,second_arg,filename)
	-- print("clustduct: will manipulate file "..config.clustduct["ethers"])
	local file, err = io.open(filename,"r")
	if not file then error(err) end
	local file_content = file:read("*a")
	file:close()
	-- escape as the search args could have magical characted like -
	ff_arg = string.gsub(first_arg,"(%W)","%%%1")
	sf_arg = string.gsub(second_arg,"(%W)","%%%1")
	-- look if we allready got the right string
	if string.find(file_content,ff_arg.." "..sf_arg) then
		return
	end
	need_signal = true
	-- search for first_arg and second_arg
	local first_pos = string.find(file_content,ff_arg.."%s+%g+")
	local second_pos = string.find(file_content,"%g+%s+"..sf_arg)
	if first_pos then
		file_content = string.gsub(file_content,ff_arg.."[%g%s]+\n","")
		-- print("clustduct: found ip, content is now [snip]\n"..file_content.."\n[snap]")
	elseif second_pos then
		file_content = string.gsub(file_content,"%g+%s+"..sf_arg,"")
		-- print("clustduct: found mac, content is now [snip]\n"..file_content.."\n[snap]")
	end
	file = io.open(filename,"w")
	file_content=file_content..first_arg.." "..second_arg.."\n"
	file:write(file_content)
	file:close()
end

function update_db(node, attr)
	local db_file = config.clustduct["genders"]
	local file = io.open(db_file,"a")
	if not file then error("could not open file "..db_file) end
	file:write(node.." "..attr.."\n")
	file:close()
	need_signal = true
end

function send_signal()
	if need_signal then
		-- print("clustduct: sending SIGHUP to dnsmasq")
		os.execute("pkill --signal SIGHUP dnsmasq")
		need_signal = false
	end
end

function allowfromhost(node)
	local node_attrs = handle:getattr(node)
	-- should not happen but be sure
	if node_attrs == nil then return false end
	if node_attrs["block"] then
		return false
	else
		return true
	end
	return false
end

-- following functions must be present for a working together with dnsmasq
function init() 
	g_db = require("genders")
	require("bfcommons")
	print("clustduct: init was called")
	local cnf_file,err = loadfile(cnf_filename,"t",config)
	-- initialize with defaults
	if cnf_file then
		print("clustduct: found config file "..cnf_filename)
		cnf_file()
	else
		-- no config file found
		print("clustduct: "..err)
	end
	if config["clustduct"] == nil then config["clustduct"] = {} end
	if config.clustduct["ethers"] == nil then config.clustduct["ethers"]="/etc/ethers" end
	if config.clustduct["hosts"] == nil then config.clustduct["hosts"]="/etc/hosts"  end
	if config.clustduct["genders"] == nil then config.clustduct["genders"]="/etc/genders"  end
	if config.clustduct["linear_add"] == nil then config.clustduct["linear_add"]=false  end
	if config.clustduct["confdir"] == nil then config.clustduct["confdir"]="/etc/clustduct.d/"  end
	if config.clustduct["outdir"]  == nil then config.clustduct["outdir"] = "/clustduct" end
	if config.clustduct["tftpdir"]  == nil then config.clustduct["tftpdir"] = "/srv/tftpboot" end
	if config.clustduct["netclass"]  == nil then config.clustduct["netclass"] = "01" end
	if config.clustduct["overwrite"] == nil then config.clustduct["overwrite"] = true end
	handle = g_db.new(config.clustduct["genders"])
	print("clustduct: opened genders database "..config.clustduct["genders"].." with "..#handle:getnodes().." nodes")
	-- will update hosts file now
	nodes = handle:query("ip")
	for index,node in pairs(nodes) do
		local node_attrs = handle:getattr(node)
		local node_names = node
		if config.clustduct["domain"] then
			node_names = node.."."..config.clustduct["domain"].." "..node
		end
		update_file(node_attrs["ip"],node_names,config.clustduct["hosts"])
	end
	send_signal()
	if config.clustduct["linear_add"] then print("clustduct: will add nodes linear") else print("clustduct: do nothing with new nodes") end
	print("clustduct: end init")
end

function shutdown()
	print("clustduct: shutdown was called")
end

function lease(action,args)
	print("clustduct: lease was called with action "..action)
	if action == "old" then
		print("clustduct: in old tree")
		local node=handle:query("mac="..args["mac_address"])
		if node~= nil and #node == 1 then
			-- found node in genders, update ethers/hosts
			local node_attrs = handle:getattr(node[1])
			print("clustduct: found node "..node[1].." with mac="..args["mac_address"].." updating hosts and ethers")
			local node_names = node[1]
			if config.clustduct["domain"] then
				node_names = node[1].."."..config.clustduct["domain"].." "..node[1]
			end
			update_file(node_attrs["ip"],node_names,config.clustduct["hosts"])
			update_file(node_attrs["mac"],node_attrs["ip"],config.clustduct["ethers"])
			print(type(node[1]),type(handle),type(config))
			create_pxe_node_file(node[1],handle,config) 
			create_grub_node_file(node[1],handle,config) 
			-- hosts/ethers is reread after signal is sned
			send_signal()
		else
			print("clustduct: node with mac "..args["mac_address"].." is not known to genders")
		end
	elseif action == "add" then
		print("clustduct: in add tree")
		-- query genders for mac
		local node = handle:query("mac="..args["mac_address"])
		if node~= nil and #node == 1 then
			-- found node in genders, update ethers/hosts
			local node_attrs = handle:getattr(node[1])
			print("clustduct: found node "..node[1].." with mac="..args["mac_address"].." updating hosts and ethers")
			local node_names = node[1]
			if config.clustduct["domain"] then
				node_names = node[1].."."..config.clustduct["domain"].." "..node[1]
			end
			update_file(node_attrs["ip"],node_names,config.clustduct["hosts"])
			update_file(node_attrs["mac"],node_attrs["ip"],config.clustduct["ethers"])
			-- hosts/ethers is reread after signal is sned
			send_signal()
		elseif config.clustduct["linear_add"] then
			-- add the new node to genders, update ethers/hosts
			local node = handle:query("~mac&&ip")
			if #node >= 1 then
				print("clustduct: add node with mac "..args["mac_address"].." as "..node[1])
				local node_attr = handle:getattr(node[1])
				if node_attr["mac"] == nil then
					update_db(node[1],"mac="..args["mac_address"])
					handle:reload(config.clustduct["genders"])
				else
					print("clustduct: WARNING: mac="..mac.." is already in database")
				end
				-- reload handle
				handle:reload(config.clustduct["genders"])
				local node_names = node[1]
				if config.clustduct["domain"] then
					node_names = node[1].."."..config.clustduct["domain"].." "..node[1]
				end
				update_file(node_attr["ip"],node_names,config.clustduct["hosts"])
				update_file(args["mac_address"],node_attr["ip"],config.clustduct["ethers"])
				create_pxe_node_file(node[1],handle,config)
				create_grub_node_file(node[1],handle,config)
				-- hosts/ethers is reread after signal is send
				send_signal()
			else
				print("clustduct: WARNING: node count: "..#node)
			end
		else
			print("clustduct: not adding unknown node")
		end

	elseif action == "del" then
		print("clustduct: in del, but do not care about vanished leases")
	else
		print("clustduct: unknown action "..action.." doing nothing")
	end
end

function tftp(action,args)
	-- print("clustduct: tftp was called with:")
	-- tprint(args)
	local node = handle:query("ip="..args["destination_address"])
	-- check if node specific config was selected, which may called from other ip
	local nodefromfile = string.match(args["file_name"],"%g+/clustduct_node%.(%g+)%.%g+")
	if nodefromfile ~= nil then
		if not handle:isnode(nodefromfile) then return end
		-- check for valid nodename and check if ip is in database
		if node[1] ~= nodefromfile then
			print("clustduct: Will set node with ip="..args["destination_address"].." to "..nodefromfile)
			if not allowfromhost(nodefromfile) then return end
			-- read adress from the arp table
			local shellhandle = io.popen("ip neigh show "..args["destination_address"])
			local shellresult = shellhandle:read("*a")
			shellhandle:close()
			local mac = string.match(shellresult,"%g+%s%g+%s%g+%s%g+%s(%g+)%s%g+")
			if mac ~= nil then
				-- just update the mac in genders, the rest will be handled by old
				-- and check if mac is in the database
				local genders_mac = handle:query("mac="..mac)
				if genders_mac == nil or #genders_mac == 0 then
					update_db(nodefromfile,"mac="..mac)
					handle:reload(config.clustduct["genders"])
					send_signal()
				else
					print("clustduct: WARNING: mac="..mac.." is already in database")
				end
			end
		end
	end
	-- ip is not in database and was not added, so return
	if node == nil then
		return
	end
	if #node ~= 1 then
		return
	end
	local node_attrs = handle:getattr(node[1])
	-- check if boot exists and return, check for install=$IMAGE
	-- afterwards, so that the boot preceeds the install
	-- after installation the boot=local may be added, ram only
	-- installation will only provide a boot
	-- for reinstalltion the boot entry must be removed
	-- check if node has boot entry
	if node_attrs["boot"] ~= nil then return end
	-- also do nothing if install was node defined
	if node_attrs["install"] == nil then return end
	-- check if the install entry is valid
	if not handle:isnode(node_attrs["install"]) then return end
	-- check is we have trigger
	local install_attr = handle:getattr(node_attrs["install"])
	if install_attr == nil then return end
	if install_attr["trigger"] == nil then return end
	-- check if trigger is in the transfered file
	if args["file_name"] ~= nil then
		local ftrigger = string.gsub(install_attr["trigger"],"(%W)","%%%1")
		if string.find(args["file_name"],"%g*"..ftrigger.."%g*") and install_attr["nextboot"] ~= nil then
			print("clustduct: trigger "..install_attr["trigger"].." setting "..node[1].." boot="..install_attr["nextboot"])
			update_db(node[1],"boot="..install_attr["nextboot"])
			handle:reload(config.clustduct["genders"])
			send_signal()
			create_pxe_node_file(node[1],handle,config) 
			create_grub_node_file(node[1],handle,config) 
		end
	end
end

07070100000048000081A4000003E800000064000000015DE541E800000236000000000000000000000000000000000000002400000000clustduct-0.0.5/src/prepare_tftp.sh#!/bin/bash
TFTPDIR=${TFTPDIR-/srv/tftpboot}
test -d $TFTPDIR || mkdir -pv $TFTPDIR
cp -v /usr/share/syslinux/chain.c32 /usr/share/syslinux/menu.c32 /usr/share/syslinux/pxelinux.0 /usr/share/syslinux/reboot.c32 $TFTPDIR
mkdir -pv ${TFTPDIR}/pxelinux.cfg/
cp -v /usr/share/doc/clustduct/default.example ${TFTPDIR}/pxelinux.cfg/default
mkdir -pv ${TFTPDIR}/EFI/x86/
cp -v /usr/lib64/efi/shim.efi ${TFTPDIR}/EFI/x86/bootx64.efi
cp -v /usr/lib64/efi/grub.efi ${TFTPDIR}/EFI/x86/
cp -v /usr/share/doc/clustduct/grub.cfg ${TFTPDIR}/EFI/x86/
mkdir -pv ${TFTPDIR}/clustduct
07070100000049000081ED000003E800000064000000015DE541E8000006DF000000000000000000000000000000000000002100000000clustduct-0.0.5/src/write_bf.lua#!/usr/bin/lua
g_db = require("genders")
require("bfcommons")
-- handle must be global
local cnf_filename = "/etc/clustduct.conf"
-- read the config
local config = {}
local cnf_file,err = loadfile(cnf_filename,"t",config)
if cnf_file then cnf_file() else print(err) end
if config.clustduct["confdir" ]== nil then config.clustduct["confdir"]="/etc/clustduct.d/" end
if config.clustduct["tftpdir"] == nil then config.clustduct["tftpdir"] = "/srv/tftpboot" end
if config.clustduct["outdir"] == nil then config.clustduct["outdir"] = "/clustduct" end
if config.clustduct["netclass"] == nil then config.clustduct["netclass"] = "01" end
if config.clustduct["genders"] == nil then config.clustduct["genders"] = "/etc/genders" end
local handle = g_db.new(config.clustduct["genders"])
-- always overwrite files
config.clustduct['overwrite'] = true
-- variables
local node = nil
local force = false


-- parse commandline
getopt = require 'posix.unistd'.getopt
for r, optarg, optind in getopt(arg, 'hfc:n:o:b:') do
	if r == '?' then
		return print('unrecognized option', arg[optind -1])
	end
	if r == 'h' then
		print '-h      print this help text'
		print '-n NODE create config only for given and not all nodes'
		print '-o ARG  output dir'
		print '-c ARG  confguration dir'
		return 0
	elseif r == 'c' then
		config.clustduct["confdir"] = optarg
	elseif r == 'b' then
		config.clustduct["base"] = optarg
	elseif r == 'o' then
		config.clustduct["outdir"] = optarg
		config.clustduct["tftpdir"] = optarg
	elseif r == 'n' then
		node = optarg
	end
end

local nodes = handle:query("ip")
if node ~= nil then
	create_pxe_node_file(node,handle,config)
	create_grub_node_file(node,handle,config)
end
create_pxe_structure(handle,config)
create_grub_structure(handle,config)
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!233 blocks
openSUSE Build Service is sponsored by