Automation de deploiements Baremetal
PXE is native bootp protocol, he is very simple and use only tftp protocol to get boot system to start.
iPXE:
iPXE usualy is not include in Bios computer ( but it's possible to write EEPROM )
Then we use a 'trick' to execute the iPXE step
On DHCP server:
If bootp call is not iPXE we upload iPXE on host, then host execute iPXE code
Normaly the filenane is fixed file to download & execute
If boot call is made by iPXE we send API url who generate dynamiquely the iPXE script to execute on host.
Note: Apps & database are containerized
| Step | Function | who generate url ? | who generate script ? |
|---|---|---|---|
| Boot Script | Set boot parameters | TFTP | Install apps |
| Install Script | Use by system autoinstaller | Define in Boot script | Install apps |
| Postintall Script | Run at the end of system autoinstallion | Define in Install script | Install apps |
| First Boot Script | Start at first boot system | Define in Post install script | Install apps (not yet implemented) |
When iPXE script is executed, you must minimal section like this:
#!ipxe
<% if @host.toinstall -%>
configurations and tasks to do for booting installation
...
...
<% end -%>
boot
@host.toinstall is boolean value set in app, Can be manually set in host view, by defaut this value is set to false
You must activate this value to true is you want host start new installation at is next boot
At the final step on installation, Post Install run a api call to instruct install is finish, this last call reset .toinstall to value false.
Results of ipxe script:
If Apps set host not to be installed, generated iPXE script just to boot on local disk
boot
else the iPXE script add informations necessary to remote installation :
#!ipxe
configurations and tasks to do for booting installation
...
...
boot
The rendering ( erb syntax ) is done by api server, the result is send to requester
The rendering use some object's variables , for exemple @host.toinstall is boolean value associated to host object (refered by @host) field named toinstall
If you want acces to other attribut, for example, description value of boot script associated to host you can acces to this value with this syntax:
@host.installtemplate.boot.description
You script can refere to all informations associated to the host (site,template, account, host etc ...)
Example, Simple post install script you can write
Script template ( erb syntax )
#!/bin/bash
curl --insecure <%= @site.apiurl %>/api/host/installed?uuid=<%= @host.uuid %>
Result:
#!/bin/bash
curl --insecure https://autoinstall.msi.stef.lan/api/host/installed?uuid=2b574d56-372e-1758-
The rendering is:
autoinstall.msi.stef.lan is apiurl field of site object refered by host
The UUID is the uuid field of host
Only refered relays are authorise to communicate with deploiement apps
Optional local filer can be deploy to minimise externals communication,download time and can be use to host specific's packages.
Start a new VM (demosrv)
Boot script : Generate iPXE script who indicate to server boot option
If host exist and is tagged to be install
If host not exist yet, apps just create a new host entry assign default template ( indicate to do nothing)
Apps render iPXE script
What iPXE script do:
If server is tagged to be install
1 - Get kernel file from filer ( http )
2 - Get initrd file from filer ( http )
3 - Boot with options necessary automatic install
If not, just said boot then the host boot on is disk
In this case boot script template is:
#!ipxe
# site name: <%= @site.name %>
<% if @host.toinstall -%> <= Check if host must be install
set filer_path http://<%= @site.fileserver_ip %><%= @site.fileserver_basepath %>
set os_path ${filer_path}/<%=@template.ostype %>/<%= @template.osversion %>
kernel ${os_path}/<%=@template.kernel %>
initrd ${os_path}/<%= @template.initrd %>
imgargs linux auto=true fb=false priority=critical preseed/url=<%= @site.apiurl %>/api/host/install?uuid=<%= @host.uuid %> debian-installer/allow_unauthenticated_ssl=true
<% end -%>
boot <= in any case boot server
#!ipxe
# site name: zen6
set filer_path http://192.168.88.73/images <= This information come from host site
set os_path ${filer_path}/Debian/Bookworm <= define where of OS ressources are located ( from site info )
kernel ${os_path}/linux <= define name of kernel to use
initrd ${os_path}/initrd.gz <= define name of initrd to use
imgargs linux auto=true fb=false priority=critical preseed/url=https://autoinstall.msi.stef.lan/api/host/install?uuid=68444d56-927f-8bb8-63bf-5ce766efd6ee debian-installer/allow_unauthenticated_ssl=true
boot
For Debian:
auto=true: indicate of autmation mode needed
preseed/url=: "Location of preseed file", in fact this is not static file.
The url call api who generate preseed file for who has the uuid value pass in call:
https://autoinstall.msi.stef.lan/api/host/install?uuid=68444d56-927f-8bb8-63bf-5ce766efd6ee
debian-installer/allow_unauthenticated_ssl=true: The apps currently use internal SSL cert (autosined) this option indicate to accept unkwon CA/SSL cert.
Next script call is the install script ( install stage in apps)
For debian the script are write in preseed format
#_preseed_V1
d-i debian-installer/locale string fr_FR.UTF-8
d-i keyboard-configuration/xkb-keymap select fr
d-i keyboard-configuration/xkb-keymap select fr(latin9)
# Network config ( dhcp )
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i netcfg/wireless_wep string
d-i hw-detect/load_firmware boolean true
...
...
# LATE COMMAND
d-i preseed/late_command string \
in-target sh -c "mkdir -m 700 /root/postinstall ; wget --no-proxy -O /root/postinstall/script.sh --no-check-certificate https://autoinstall.msi.stef.lan/api/host/postinstall?uuid=68444d56-927f-8bb8-63bf-5ce766efd6ee; chmod +x /root/postinstall/script.sh; /root/postinstall/script.sh"
# GRUB
d-i grub-installer/only_debian boolean true
d-i grub-installer/bootdev string /dev/sda
d-i debian-installer/add-kernel-opts string nousb consoleblank=0
d-i finish-install/reboot_in_progress note
Note: The LATE COMMAND section call apps server to get post installation script and execute it before reboot
The postinstall script is executed by root just before reboot , then you can do what you want
#!/bin/bash
apt-get install -y curl sudo
...
...
# Deploy host main account ssh key
mkdir -p /home/<%= @host.mainaccount.login %>/.ssh
echo "<%= @host.mainaccount.sshpubkey %>" > /home/<%= @host.mainaccount.login %>/.ssh/authorized_keys
chown -R <%= @host.mainaccount.login %>: /home/<%= @host.mainaccount.login %>/.ssh
chmod 700 /home/<%= @host.mainaccount.login %>/.ssh
chmod 600 /home/<%= @host.mainaccount.login %>/.ssh/authorized_keys
...
...
<% if not @site.cfenginehub.empty? -%>
# Add cf agent and associate to cfengine hub on <%= @site.cfenginehub %>
wget https://s3.amazonaws.com/cfengine.packages/quick-install-cfengine-enterprise.sh && bash ./quick-install-cfengine-enterprise.sh agent
/var/cfengine/bin/cf-agent --bootstrap <%= @site.cfenginehub %>
<% end -%>
# Get install informations
## default interface name
default_interface=`ip route get <%= @site.gateway %> | sed -n 's/.*dev \([^\ ]*\).*/\1/p'`
default_ip=$(hostname -I | awk '{print $1}')
# API Call to inform apps : the postinsall script is finish and update some data
curl --insecure "<%= @site.apiurl %>/api/host/installed?uuid=<%= @host.uuid %>&interface=$default_interface&ip=$default_ip"
echo "FINISH"
This script template generate this :
#!/bin/bash
apt-get install -y curl sudo
...
...
# Deploy host account user ssh key
mkdir -p /home/stef/.ssh
echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC14slyp/JGv9iqLH4D94x+7v4PB/ec0YbLUPexdBip6OJaflbmp3s25WJ+oyO6U78Ee0jZUZt0TapYozyNx9UksP9JhirwKeNJnQSzSX0RKc6kQffoCgWHZmnzuoalEzaE7XyH+K8wP+hKi052ak9yR7XWDp6CG3V1Qpyq80VD1XNUzEL2xkITGQ6KojxrOJ1O0A9ISRu1t85Ul2N0syIylE2Ukvns1/NkArhC2g8N8T5XxPq39AUH78A3I0/kHowIzW9BpPVwim0tJTLSVNnVqq1NPG+gi1XvrXKzO/jb4kT01tnMG9vKcYqdH4g0y01ADEcCgMo1jGAjwq6gPLqT imported-openssh-key" > /home/stef/.ssh/authorized_keys
chown -R stef: /home/stef/.ssh
chmod 700 /home/stef/.ssh
chmod 600 /home/stef/.ssh/authorized_keys
# Add cf agent and associate to cfengine hub on 192.168.88.71
wget https://s3.amazonaws.com/cfengine.packages/quick-install-cfengine-enterprise.sh && bash ./quick-install-cfengine-enterprise.sh agent
/var/cfengine/bin/cf-agent --bootstrap 192.168.88.71
# Get install informations
## default interface name
default_interface=`ip route get 192.168.88.254 | sed -n 's/.*dev \([^\ ]*\).*/\1/p'`
default_ip=$(hostname -I | awk '{print $1}')
# Send to zeninstall postinstall script is finish and update some data
curl --insecure "https://autoinstall.msi.stef.lan/api/host/installed?uuid=68444d56-927f-8bb8-63bf-5ce766efd6ee&interface=$default_interface&ip=$default_ip"
echo "FINISH"