Commit 71b6bfad authored by hark's avatar hark
Browse files

* removed all private stuff

* new version of puppet-libvirt / debian
* put list of vm's / networks in hiera
* takes rootfs from docker registry (optional) for faster testing
parents
#!/bin/sh
set -eu
DISK=$1
INODECOUNT=$(tune2fs -l ${DISK} |grep 'Inode count' |awk '{print $3}')
INODEFREE=$(tune2fs -l ${DISK} |grep 'Free inodes' |awk '{print $3}')
INODEUSED=$((INODECOUNT - INODEFREE))
echo "${INODEUSED}"
#!/bin/bash
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
set -eux
env
DISK=$1
MOUNTDIR=$(mktemp -d)
ETH1=""
ETH2=""
cleanup(){
if [ ! -z "$MOUNTDIR" ]; then
if /bin/mountpoint -q "${MOUNTDIR}"; then
/bin/umount "${MOUNTDIR}"
fi
/bin/rm -rf "${MOUNTDIR}"
fi
}
mketh0(){
echo "intmethod is: $INTMETHOD "
if [[ "$INTMETHOD" != "dhcp" ]]
then
if [ ! "$INTIP" = "0.0.0.0" ];then
if [ "$EXTIP" = "0.0.0.0" ];then
ETH0="auto eth0\niface eth0 inet static\n address ${INTIP}\n netmask ${INTNM}\n gateway ${INTGW}\n"
else
ETH0="auto eth0\niface eth0 inet static\n address ${INTIP}\n netmask ${INTNM}\n"
fi
elif [ ! "$EXTIP" = "0.0.0.0" ]; then
ETH0="auto eth0\niface eth0 inet static\n address ${EXTIP}\n netmask ${EXTNM}\n gateway ${EXTGW}\n"
fi
else
ETH0="auto eth0\niface eth0 inet dhcp\n"
fi
}
mketh1(){
echo "extmethod is: $EXTMETHOD "
if [[ "$EXTMETHOD" != "dhcp" ]]
then
if [ ! "$INTIP" = "0.0.0.0" ];then
if [ ! "$EXTIP" = "0.0.0.0" ];then
ETH1="auto eth1\niface eth1 inet static\n address ${EXTIP}\n netmask ${EXTNM}\n gateway ${EXTGW}\n"
fi
fi
else
ETH1="auto eth1\niface eth1 inet dhcp\n"
fi
}
if [ ! -z "$DISK" ]; then
/bin/mount "$DISK" "$MOUNTDIR"
trap cleanup EXIT
if ls /usr/bin/docker
then
echo "docker installed, using that to download the image, cause its much faster then debootstrap"
CONT=`docker create "debian:$DEBIAN_VERSION"`
echo "created: $CONT"
docker export "$CONT" | tar x -C "$MOUNTDIR"
docker rm "$CONT"
chroot ${MOUNTDIR} apt-get -y update
chroot ${MOUNTDIR} apt-get -y upgrade
chroot ${MOUNTDIR} apt-get -y install systemd ifupdown netbase puppet git openssh-server curl vim lsb-release python3 udev
else
echo "using debootstrap"
/usr/sbin/debootstrap \
--include=systemd-sysv,ifupdown,netbase,puppet,git,openssh-server,curl,vim,lsb-release,python3,udev \
"$DEBIAN_VERSION" "$MOUNTDIR" http://ftp.nl.debian.org/debian/
fi
echo "${VMNAME}" > "${MOUNTDIR}/etc/hostname"
/bin/mkdir -m 0700 "${MOUNTDIR}/root/.ssh"
echo "${AUTHKEY}" > "${MOUNTDIR}/root/.ssh/authorized_keys"
/bin/chmod 600 "${MOUNTDIR}/root/.ssh/authorized_keys"
echo "/dev/vda / ext4 errors=remount-ro 0 1" > "${MOUNTDIR}/etc/fstab"
# echo "/dev/vdb none swap defaults 0 0" >> "${MOUNTDIR}/etc/fstab"
echo "source /etc/network/interfaces.d/*" > "${MOUNTDIR}/etc/network/interfaces"
echo "" >> "${MOUNTDIR}/etc/network/interfaces"
echo "auto lo" >> "${MOUNTDIR}/etc/network/interfaces"
echo "iface lo inet loopback" >> "${MOUNTDIR}/etc/network/interfaces"
echo "" >> "${MOUNTDIR}/etc/network/interfaces"
mketh0
echo -e "${ETH0}" >> "${MOUNTDIR}/etc/network/interfaces"
mketh1
echo -e "${ETH1}" >> "${MOUNTDIR}/etc/network/interfaces"
echo "nameserver ${DNS}" > "${MOUNTDIR}/etc/resolv.conf"
#FIXME: take admins from hiera https://git.puscii.nl/puppetexp/control/blob/production/site-modules/profile/manifests/lag.pp
/usr/bin/gpg --no-autostart --no-tty --homedir "${MOUNTDIR}/root/.gnupg" --import /usr/local/etc/admins.asc
/usr/bin/gpg --no-autostart --no-tty --homedir "${MOUNTDIR}/root/.gnupg" --import-ownertrust < /usr/local/etc/otrust.txt
echo "puppetmaster: $PUPPETMASTER"
#setup puppet
if [[ $PUPPETMASTER == 'none' ]]
then
echo "There is no puppetmaster, using masterless"
/usr/bin/git clone --recursive https://git.puscii.nl/puppet1/nomasters.git "${MOUNTDIR}/etc/puppet/code"
echo "[Unit]" > "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "Description=apply our puppet manifest" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "[Service]" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "Type=oneshot" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "ExecStartPre=-/usr/bin/git -C /etc/puppet/code pull --ff-only --verify-signatures --recurse-submodules=yes" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "ExecStartPre=-/usr/bin/git -C /etc/puppet/code submodule update" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "ExecStart=/usr/bin/puppet apply /etc/puppet/code/manifests/%H.pp" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "User=root" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "Group=root" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.service"
echo "[Unit]" > "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "Description=apply our puppet manifest every hour" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "[Timer]" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "OnCalendar=*:0/30" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "Persistent=true" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "[Install]" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
echo "WantedBy=timers.target" >> "${MOUNTDIR}/etc/systemd/system/run-puppet.timer"
ln -sL /etc/systemd/system/run-puppet.timer "${MOUNTDIR}/etc/systemd/system/timers.target.wants/"
puppetfingerprint="masterless, no cert"
else
# there is a puppet master
echo "There is a puppet master"
hostname="$VMNAME.$DOMAIN"
cat <<EOF > "${MOUNTDIR}/etc/puppet/puppet.conf"
[main]
ssldir = /var/lib/puppet/ssl
certname = $hostname
server = $PUPPETMASTER
[agent]
runinterval=5m
EOF
chroot ${MOUNTDIR} systemctl enable puppet
#generate puppet certs and store fingerprints
# that command will fail, but still makes certs
chroot ${MOUNTDIR} puppet agent -t || true
puppetfingerprint=`chroot ${MOUNTDIR} puppet agent --test --fingerprint | cut -d ' ' -f 2` || true
fi
# autologin on ttyS0
cat <<EOF > "${MOUNTDIR}/etc/systemd/system/serial-getty-autologin@.service"
# autologin getty
[Unit]
Description=Serial Getty on %I
Documentation=man:agetty(8) man:systemd-getty-generator(8)
Documentation=http://0pointer.de/blog/projects/serial-console.html
BindsTo=dev-%i.device
After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service getty-pre.target
After=rc-local.service
# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though
# getty.target didn't actually pull it in.
Before=getty.target
IgnoreOnIsolate=yes
# IgnoreOnIsolate causes issues with sulogin, if someone isolates
# rescue.target or starts rescue.service from multi-user.target or
# graphical.target.
Conflicts=rescue.service
Before=rescue.service
[Service]
# The '-o' option value tells agetty to replace 'login' arguments with an
# option to preserve environment (-p), followed by '--' for safety, and then
# the entered username.
ExecStart=-/sbin/agetty --autologin root -o '-p -- \\u' --keep-baud 115200,38400,9600 %I $TERM
Type=idle
Restart=always
UtmpIdentifier=%I
TTYPath=/dev/%I
TTYReset=yes
TTYVHangup=yes
KillMode=process
IgnoreSIGPIPE=no
SendSIGHUP=yes
[Install]
WantedBy=getty.target
EOF
#autologin on serial console
if rm "${MOUNTDIR}/etc/systemd/system/getty.target.wants/serial-getty@ttyS0.service"
then
echo "there was already a ttyS0 service"
fi
ln -s "/etc/systemd/system/serial-getty-autologin@.service" "${MOUNTDIR}/etc/systemd/system/getty.target.wants/serial-getty-autologin@ttyS0.service"
# enable console
chroot ${MOUNTDIR} systemctl enable serial-getty@ttyS0.service
sshfingerprint=`ssh-keygen -l -f ${MOUNTDIR}/etc/ssh/ssh_host_ed25519_key`
sshfingerprintrsa=`ssh-keygen -l -f ${MOUNTDIR}/etc/ssh/ssh_host_rsa_key`
mkdir -p /var/cache/vminfo/$hostname/
echo "$puppetfingerprint" > "/var/cache/vminfo/$hostname/puppetfp.txt"
echo "$sshfingerprint" > "/var/cache/vminfo/$hostname/sshed25519fp.txt"
echo "$sshfingerprintrsa" > "/var/cache/vminfo/$hostname/sshrsafp.txt"
#MOTD
date=`date`
cat <<EOF > "${MOUNTDIR}/etc/motd"
_____
/ \ This is: $hostname
\ x.x / Installed on: $date
|_|_| ssh ed25519 fingerprint: $sshfingerprint
Puppet fingerprint: $puppetfingerprint
EOF
fi
module Puppet::Parser::Functions
newfunction(:hypervisor_disks, :type => :rvalue) do |args|
name = args[0]
rootvg = args[1]
swapvg = args[2]
datavg = args[3]
datadisk = args[4]
disks = Array.new
disks << {'type' => 'block',
'device' => 'disk',
'source' => {'dev' => "/dev/" + rootvg + "/" + name + "-disk"},
'bus' => 'virtio',
'driver' => {'name' => 'qemu',
'type' => 'raw',
'cache' => 'directsync',
},
}
disks << {'type' => 'block',
'device' => 'disk',
'source' => {'dev' => "/dev/" + swapvg + "/" + name + "-swap"},
'bus' => 'virtio',
'driver' => {'name' => 'qemu',
'type' => 'raw',
'cache' => 'directsync',
},
}
if datadisk then
disks << {'type' => 'block',
'device' => 'disk',
'source' => {'dev' => "/dev/" + datavg + "/" + name + "-data"},
'bus' => 'virtio',
'driver' => {'name' => 'qemu',
'type' => 'raw',
'cache' => 'directsync',
},
}
end
disks
end
end
module Puppet::Parser::Functions
newfunction(:hypervisor_generate_uuid, :type => :rvalue) do |args|
# compute sha1 hash of all keys concatenated
sha1 = Digest::SHA1.hexdigest(args.join(''))
# generate a QEMU/KVM UUID
"#{sha1[0..7]}-#{sha1[8..11]}-#{sha1[12..15]}-#{sha1[16..19]}-#{sha1[20..31]}"
end
end
module Puppet::Parser::Functions
newfunction(:hypervisor_interfaces, :type => :rvalue) do |args|
Puppet::Parser::Functions.function('generate_mac')
name = args[0]
int_ip = args[1]
int_mac = args[2]
ext_ip = args[3]
ext_mac = args[4]
ext_net = args[5]
int_method = args[6]
ext_method = args[7]
interfaces = Array.new
#FIXME: put the 0.0.0.0 check back
if not int_method=='none' then
if not int_mac.empty? then
interfaces << {'filter' => name + "-internal", 'network' => 'net-internal', 'mac' => int_mac, 'type' => 'virtio', 'ip' => int_ip, 'name' => name + "-internal"}
else
interfaces << {'filter' => name + "-internal", 'network' => 'net-internal', 'mac' => function_libvirt_generate_mac([int_ip]), 'type' => 'virtio', 'ip' => int_ip, 'name' => name + "-internal"}
end
end
if not ext_method=='none' then
if not ext_mac.empty? then
interfaces << {'filter' => name + "-external", 'network' => ext_net, 'mac' => ext_mac, 'type' => 'virtio', 'ip' => ext_ip, 'name' => name + "-external"}
else
interfaces << {'filter' => name + "-external", 'network' => ext_net, 'mac' => function_libvirt_generate_mac([ext_ip]), 'type' => 'virtio', 'ip' => ext_ip, 'name' => name + "-external"}
end
end
interfaces
end
end
define hypervisor::network (
$ensure = 'present' ,
# $name = $name,
Stdlib::IP::Address $network ,
Stdlib::IP::Address $gateway = undef ,
$dns = undef,
$netmask = undef,
) {
alert($name)
libvirt::network { "$name":
forward_mode => 'bridge',
bridge => "$name",
}
network::interface { "$name":
method => 'manual',
bridge_ports => ['none'],
bridge_stp => 'off',
bridge_fd => 0,
}
}
#
# creates bridges for libvirt
#
class hypervisor::networks (
String $domain = lookup("domain", undef, undef, "no_domain_set"),
) {
#packages
$packages = [
'bridge-utils',
'ifupdown',
'ebtables',
]
ensure_packages($packages)
# create networks's defined in hiera
$networks = hiera_hash('networks')
create_resources ( hypervisor::network , $networks )
}
# a class for the router
#
# classes for creating virtual machines on the hypervisor server
#
class hypervisor::router::vm ()
{
include hypervisor::vm
lvm::logical_volume { 'router-disk':
volume_group => $hypervisor::vm::root_vg,
fs_type => 'ext4',
size => '2G',
mounted => false,
mountpath_require => false,
}
lvm::logical_volume { 'router-swap':
volume_group => $hypervisor::vm::swap_vg,
createfs => false,
size => '1G',
}
$networks = hiera('networks')
#$int_gw = $networks['internal']['gateway']
$int_ip = $networks['internal']['gateway']
$int_netmask = $networks['internal']['netmask']
$int_dns = $networks['internal']['dns']
$ext_ip = $networks['external']['gateway']
$ext_netmask = $networks['external']['netmask']
$ext_dns = $networks['external']['dns']
Exec { "/usr/local/bin/mkrootdisk.sh /dev/${hypervisor::vm::root_vg}/router-disk":
require => [ File['/usr/local/bin/mkrootdisk.sh'], File['/usr/local/bin/inodecount.sh'], Lvm::Logical_volume['router-disk'] ],
onlyif => "/usr/bin/test `/usr/local/bin/inodecount.sh /dev/${hypervisor::vm::root_vg}/router-disk` = 11",
environment => ["INTIP=$int_ip",
"INTNM=$int_netmask",
"EXTIP=$ext_ip",
"EXTGW=1.2.3.4",
"EXTNM=$ext_netmask",
"DNS=$int_dns",
'VMNAME=router',
"AUTHKEY=${hypervisor::vm::authorized_key}"],
timeout => 0,
}
# VM definition
libvirt::domain { 'router':
devices_profile => 'headless',
dom_profile => 'myprofile',
uuid => hypervisor_generate_uuid($name),
disks => [{'type' => 'block',
'device' => 'disk',
'source' => {'dev' => "/dev/${hypervisor::vm::root_vg}/router-disk"},
'bus' => 'virtio',
'driver' => {'name' => 'qemu',
'type' => 'raw',
'cache' => 'directsync',
},
},
{'type' => 'block',
'device' => 'disk',
'source' => {'dev' => "/dev/${hypervisor::vm::swap_vg}/router-swap"},
'bus' => 'virtio',
'driver' => {'name' => 'qemu',
'type' => 'raw',
'cache' => 'directsync',
},
},],
interfaces => [ {
'network' => 'internal',
'mac' => '52:54:00:ac:ab:01',
'type' => 'virtio',
'ip' => $int_ip,
'name' => 'router-int'
},
{
'network' => 'external',
'mac' => '52:54:00:ac:ab:03',
'type' => 'virtio',
'ip' => $ext_ip,
'name' => 'router-ext'
},
],
autostart => true,
require => Exec["/usr/local/bin/mkrootdisk.sh /dev/${hypervisor::vm::root_vg}/router-disk"],
}
}
#
# creates libvirt vm
#
class hypervisor::vm (
String $root_vg,
String $swap_vg,
String $data_vg,
# defined in libvirt profile
# String $kernel = '/etc/xen/boot/stable.vmlinuz',
# String $initrd = undef,
String $authorized_key = 'none',
String $domain = lookup("domain", undef, undef, "no_domain_set"),
) {
include git
#packages
$packages = [
'debootstrap',
'linux-image-4.19.0-9-cloud-amd64',
]
ensure_packages($packages)
# scripts
file { '/usr/local/bin/mkrootdisk.sh':
ensure => present,
owner => root,
group => root,
mode => '0700',
source => "puppet:///modules/${module_name}/scripts/mkrootdisk.sh",
}
file { '/usr/local/bin/inodecount.sh':
ensure => present,
owner => root,
group => root,
mode => '0700',
source => "puppet:///modules/${module_name}/scripts/inodecount.sh",
}
}
#
# resource type for deploying virtual machines
#
define hypervisor::vm::deploy (
$ensure = 'present',
String $domain = lookup("domain", undef, undef, "nodomainset.la"),
Stdlib::Fqdn $public_hostname = "${name}.${domain}",
String $rootsize = '4G',
String $swapsize = '1G',
Boolean $datadisk = false,
String $datasize = '4G',
Boolean $autostart = true,
# this is in hiera in the profiles
# String $kernel = $hypervisor::vm::kernel,
# String $initrd = $hypervisor::vm::initrd,
# Integer $memory = 1000,
# Integer $cpus = 1,
String $debian_version = 'buster',
String $internal_method = 'static',
Optional[ Stdlib::IP::Address::V4::Nosubnet ] $internal_ip = '0.0.0.0',
Optional[ Stdlib::IP::Address::V4 ] $internal_gw = '0.0.0.0',
Optional[ Stdlib::IP::Address::V4 ] $internal_nm = '255.255.255.0',
String $external_method = 'static',
Optional[ Stdlib::IP::Address::V4::Nosubnet ] $external_ip = '0.0.0.0',
Optional[ Stdlib::IP::Address::V4 ] $external_gw = '0.0.0.0',
Optional[ Stdlib::IP::Address::V4 ] $external_nm = '255.255.255.0',
Optional[ Stdlib::MAC ] $internal_mac = undef,
Optional[ Stdlib::MAC ] $external_mac = undef,
# those are not optional, if they are missing, vm doesn't start
String $internal_net ,
String $external_net ,
Optional[ Stdlib::IP::Address::V4 ] $dns = '0.0.0.0',
Array $internal_tcp_services = [22],
Array $internal_udp_services = [],
Array $internal_custom_tcp_rules = [], # syntax: [{remote_ip => port}, ... ]
Array $internal_custom_udp_rules = [], # syntax: [{remote_ip => port}, ... ]
Array $external_tcp_services = [],
Array $external_udp_services = [],
Array $external_custom_tcp_rules = [], # syntax: [{remote_ip => port}, ... ]
Array $external_custom_udp_rules = [], # syntax: [{remote_ip => port}, ... ]
) {
#include hypervisor::router::vm
include hypervisor::vm
# Storage
#FIXME: disks should not get added to fstab
lvm::logical_volume { "${name}-disk":
ensure => $ensure,