Commit ae209dbb authored by glucas's avatar glucas

Add Ganeti stuff.

parent 7397bcb9
For explanations and how-to, see https://wiki.arn-fai.net/technique:ganeti (in french, sorry).
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Debian GNU/Linux: store this in /etc/ganeti/
#
# This file is included by ARN's ganeti stuff:
# * VM creation script
# * Install hooks (/etc/ganeti/instance-debootstrap/hooks)
# * Routing hook (/etc/ganeti/kvm-vif-bridge)
# * Hooks (/etc/ganeti/hooks)
# Where to store specific VM's stuff like VNC password, SSH pubkey, network addresses...
# One subdirectory will be created per VM, of course
CONFDIR=/etc/ganeti/arn
# Used by aptsources install hook to retrieve valid sources.list file
APTSOURCES_DIR=/etc/ganeti/instance-debootstrap/aptsources
# Default root password if there is no SSH key
DEFAULT_ROOT_PASSWORD="<password_here>"
#!/bin/bash
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Create a virtual machine on ARN's ganeti infrastructure.
#
# Debian GNU/Linux: store this where you want. For example: /usr/local/sbin/
# Include ARN variables
. /etc/ganeti/common-arn-vars
# Vars init
name=
disk='50'
ram='1024'
ipv4=
ipv6=
suite='jessie'
sshkey=
iso=
show_usage() {
echo -e "\nError: $1\n" >&2
cat <<EOF >&2
Usage: $(basename $0) -n name [-d size] [-r size] [-4 IPv4prefixe(s)] [-6 IPv6prefixe(s)] [-s suite] [-k file] -i [file]
-n <vm-name> Name of the VM to create (required)
-d <disk-size> Disk size in GB (default: $disk)
-r <memory-size> Memory size in MB (default: $ram)
-4 <ipv4> IPv4 route(s) (optional)
-6 <ipv6> IPv6 route(s) (optional)
-s <suite> Debian suite to install (wheezy, jessie, ...) (default: $suite)
-k <file> SSH public key to allow for root login (optional)
-i <file> ISO to boot on (optional)
EOF
exit 1
}
# Parse args
while getopts "s:n:d:r:4:6:k:i:" opt; do
case $opt in
n) name=$OPTARG ;;
d) disk=$OPTARG ;;
r) ram=$OPTARG ;;
4) ipv4="$OPTARG" ;;
6) ipv6="$OPTARG" ;;
s) suite=$OPTARG ;;
k) sshkey="$OPTARG" ;;
i) iso="$OPTARG";;
esac
done
# check inputs
[ "$suite" = 'jessie' ] || show_usage 'Invalid suite'
[ -n "$name" ] || show_usage 'Name empty'
[ "$disk" -ge 2 ] || show_usage 'Disk too small'
[ "$ram" -ge 128 ] || show_usage 'Too few RAM'
# should be sufficient…
[[ -z "$ipv4" || "$ipv4" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}/[0-9]{1,2}( |$) ]] || show_usage 'Invalid IPv4'
[[ -z "$ipv6" || "$ipv6" =~ ^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{1,4}/[0-9]{1,3}( |$) ]] || show_usage 'Invalid IPv6'
# create config dir
VMCONFDIR="$CONFDIR/$name"
gnt-cluster command --failure-only mkdir -p "$VMCONFDIR"
# VNC
# No VNC for internal VM
vnc='-H kvm:vnc_bind_address=127.0.0.1'
# Generate VNC password for VPS
if [[ "$name" =~ ^vps- ]]; then
vncpass=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 24)
VNCCONF="$VMCONFDIR/vncpwd.conf"
echo $vncpass > "$VNCCONF"
gnt-cluster copyfile "$VNCCONF"
vnc="-H kvm:vnc_bind_address=0.0.0.0,vnc_password_file=$VNCCONF"
fi
# Create & propagate IP config
NETCONF="$VMCONFDIR/net.conf"
[ -n "$ipv4" -o -n "$ipv6" ] && osparam=( -O )
[ -n "$ipv4" -a -z "$ipv6" ] && osparam+=( ipv4=$ipv4 )
[ -n "$ipv6" -a -z "$ipv4" ] && osparam+=( ipv6=$ipv6 )
[ -n "$ipv6" -a -n "$ipv4" ] && osparam+=( ipv4=$ipv4,ipv6=$ipv6 )
[ -n "$ipv4" -o -n "$ipv6" ] && truncate -s 0 "$NETCONF"
[ -n "$ipv4" ] && echo "IPV4_NET=\"$ipv4\"" >> "$NETCONF"
[ -n "$ipv6" ] && echo "IPV6_NET=\"$ipv6\"" >> "$NETCONF"
[ -n "$ipv4" -o -n "$ipv6" ] && gnt-cluster copyfile "$NETCONF"
# place optional SSH public key
[ -n "$sshkey" -a -r "$sshkey" ] && cp "$sshkey" "$VMCONFDIR/rootssh.pub"
[ -r "$VMCONFDIR/rootssh.pub" ] && gnt-cluster copyfile "$VMCONFDIR/rootssh.pub"
# start the work (exiting if any error)
set -e
# disable wipe for non-VPS
if ! [[ "$name" =~ ^vps- ]]; then
gnt-cluster modify --prealloc-wipe-disks no > /dev/null
trap "gnt-cluster modify --prealloc-wipe-disks yes > /dev/null" EXIT
fi
echo '### Installing instance'
if [ -n "$iso" ]; then
gnt-instance add -t drbd --no-wait-for-sync -s $((disk * 1024)) -B memory=${ram}MB -o debootstrap+"$suite" "${osparam[@]}" --no-install --net 0:ip=10.0.0.42 $vnc --no-start --no-name-check --no-ip-check "$name"
echo '### Starting the instance on iso'
# The ISO is needed on all nodes, otherwise it doesn't work
gnt-cluster copyfile "$iso"
gnt-instance start -H boot_order=cdrom,cdrom_image_path=${iso},serial_console=false "$name"
else
gnt-instance add -t drbd --no-wait-for-sync -s $((disk * 1024)) -B memory=${ram}MB -o debootstrap+"$suite" "${osparam[@]}" --net 0:ip=10.0.0.42 $vnc --no-start --no-name-check --no-ip-check "$name"
echo '### Starting instance on temporary external linux/initrd for GRUB setup'
gnt-instance start --paused -H kernel_path=/vmlinuz,kernel_args="ro root=/dev/vda1",initrd_path=/initrd.img "$name"
gnt-instance console "$name"
echo '### Starting the instance'
gnt-instance start "$name"
fi
echo -e "\n###VM summary for tech:\n"
[ -n "$ipv4" ] && ip=$ipv4 && echo "IPv4: ${ipv4%%/*}"
[ -n "$ipv6" ] && ip=$ipv6 && echo "IPv6: ${ipv6%%/*}"
if [ -n "$ip" ] && [ -z "$iso" ]; then
echo -e "\nWaiting while the VM generates its SSH host keys (to retrieve them)..."
sleep 30
echo -e "\nSSH fingerprints:"
# FUTURE: ssh-keygen >= 7.2 is capable of reading from stdin/pipe so no need for tmp file. Debian Jessie has version 6.7.
tmp_vps_keyfile=$(mktemp)
ssh-keyscan "${ip%%/*}" >"$tmp_vps_keyfile" 2>/dev/null
ssh-keygen -l -f "$tmp_vps_keyfile"
fi
if [[ "$name" =~ ^vps- ]]; then
echo -e "\n### VM summary for subscriber:"
echo -en "\nInfos VPS ARN $name"
echo -en "\n\nSystème d'exploitation : "
[ -z "$iso" ] && echo -n "Debian GNU/Linux stable x86-64" || echo -n "personnalisé"
echo -e "\n\n"
[ -n "$ipv4" ] && echo "Adresse IPv4 : ${ipv4%%/*}"
[ -n "$ipv6" ] && echo -e "Adresse IPv6 : ${ipv6%%/*} \nBloc d'adresses IPv6 : ${ipv6%%::*}::/56"
echo "Reverses IP : aucun"
if [ -z "$iso" ]; then
echo -e "\n\nSSH :"
echo " Commandes d'accès : "
[ -n "$ipv4" ] && echo " * ssh root@${ipv4%%/*}"
[ -n "$ipv6" ] && echo " * ssh root@${ipv6%%/*}"
echo -n " Mot de passe : "
[ -n "$sshkey" ] && echo "aucun (authentification par clé)" || echo "$DEFAULT_ROOT_PASSWORD"
echo " Empreintes :"
ssh-keygen -l -f "$tmp_vps_keyfile"
fi
echo -e "\n\nVNC :"
echo -n " Nom d'hôte : $name-vnc.arn-fai.net:"; gnt-instance list --no-headers -o network_port "$name"
echo " Mot de passe : $vncpass"
fi
[ -n "$iso" ] && rm "$tmp_vps_keyfile"
exit 0
#!/bin/bash
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Dirty hack. Zebra (kernel module of Quagga) is unable to delete VM's routes
# from its internal routing table when we use (link-local) next-hop.
# This script does the job instead of Zebra. :-
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
# Include ARN variables
. /etc/ganeti/common-arn-vars
VMNETCONF=$CONFDIR/$GANETI_INSTANCE_NAME/net.conf
[ -r $VMNETCONF ] || exit 1
. $VMNETCONF
# We have something to do only if the VM has a (link-local) next-hop.
if [ -n "$VIA" ]; then
# Dirty hack again but Ganeti doesn't give us the VM's ifname...
# Even "GANETI_INSTANCE_NIC0_MAC" contains wrong value...
IFNAME=$(/sbin/ip link | grep -B2 $GANETI_INSTANCE_NAME | head -n1 | cut -d ":" -f 2)
# If this script is executed by the hypervisor on which the virtual machine is started,
# we delete all the VM's routes.
if [ -n "$IFNAME" ]; then
/sbin/ip r flush dev $IFNAME
fi
fi
exit 0
#! /bin/bash
# Copyright (C) 2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Remove VM-specific configuration (network configuration, SSH key,
# VNC password) on the hypervisors when destroying the VM.
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
# Include ARN variables
. /etc/ganeti/common-arn-vars
# Make sure the variables are properly set to avoid unexpected 'rm /'
[ -n "$CONFDIR" ] || exit 1
[ -n "$GANETI_INSTANCE_NAME" ] || exit 1
rm -r "$CONFDIR/$GANETI_INSTANCE_NAME"
exit 0
#!/bin/sh
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Copy an Apt sources.list in the VM's rootfs
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
# Include ARN variables
. /etc/ganeti/common-arn-vars
if [ ! -d "$TARGET" ]; then
echo "Missing target directory"
exit 1
fi
if [ ! -r "$APTSOURCES_DIR/sources.${SUITE}.tpl" ]; then
echo "Missing source sources.list for this suite: $SUITE"
exit 1
fi
cp "$APTSOURCES_DIR/sources.${SUITE}.tpl" "$TARGET/etc/apt/sources.list"
chown root:root "$TARGET/etc/apt/sources.list"
chmod 644 "$TARGET/etc/apt/sources.list"
exit 0
#!/bin/bash
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# Heavily based on ganeti-instance-debootstrap examples hooks
# See https://github.com/ouvrages/ganeti-instance-debootstrap/blob/master/examples/hooks/grub
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# setup the VM to autoinstall grub on first boot (need to boot one time with kernel from outside the VM)
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
. common.sh
# we do not clean anything
CLEANUP=( )
trap cleanup EXIT
if [ ! -d "$TARGET" ]; then
echo "Missing target directory"
exit 1
fi
# install a command in rc.local of the VM to install grub on first boot
INSTALL_COMMAND='[ -f /var/lib/dpkg/info/grub-pc.list ] || (DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends grub-pc; halt -p)'
sed -i '$i'"$INSTALL_COMMAND" ${TARGET}/etc/rc.local
# pre-configure grub's installation questions
chroot "$TARGET" debconf-set-selections <<< "debconf grub2/linux_cmdline_default string console=ttyS0,38400 console=tty1 quiet"
chroot "$TARGET" debconf-set-selections <<< "debconf grub-pc/install_devices string /dev/vda"
# download packages now to avoid network dep on setup boot
chroot "$TARGET" apt-get update
chroot "$TARGET" apt-get install -d -y --no-install-recommends grub-pc
# copy kernel/initrd in temporary directory to use them on first boot
cp ${TARGET}/boot/vmlinuz* /tmp/ganeti-install-vmlinuz-"$INSTANCE_NAME"
cp ${TARGET}/boot/initrd.img* /tmp/ganeti-install-initrd-"$INSTANCE_NAME"
exit 0
#!/bin/bash
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Replace /etc/hosts file in the VM's rootfs. Without this hook, Debootstrap
# uses the hypervisor's hosts file.
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
if [ ! -d "$TARGET" ]; then
echo "Missing target directory"
exit 1
fi
cat > $TARGET/etc/hosts <<EOF
127.0.0.1 localhost localhost.localdomain
# The following lines are desirable for IPv6 capable hosts
::1 localhost localhost.localdomain ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
exit 0
#!/bin/sh
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Put SSH key (and disable root password) if any or set a default root password
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
# Include ARN variables
. /etc/ganeti/common-arn-vars
if [ ! -d "$TARGET" ]; then
echo "Missing target directory"
exit 1
fi
if [ -z "$DEFAULT_ROOT_PASSWORD" ]
echo "You must define a default root password in common-arn-vars script"
exit 1
fi
if [ -r "$CONFDIR/$INSTANCE_NAME/rootssh.pub" ]; then
mkdir -p "$TARGET/root/.ssh"
cp "$CONFDIR/$INSTANCE_NAME/rootssh.pub" "$TARGET/root/.ssh/authorized_keys"
chmod 700 "$TARGET/root/.ssh"
chmod 600 "$TARGET/root/.ssh/authorized_keys"
chroot $TARGET passwd -l root
else
echo "root:$DEFAULT_ROOT_PASSWORD" | chroot $TARGET chpasswd
fi
exit 0
#!/bin/bash
# Copyright (C) 2009 Google Inc.
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
# Create a valid /etc/network/interfaces file for the ARN network.
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
# Include ARN variables
. /etc/ganeti/common-arn-vars
VMNETCONF=$CONFDIR/$INSTANCE_NAME/net.conf
if [ ! -d "$TARGET" ]; then
echo "Missing target directory"
exit 1
fi
if [ ! -d "$TARGET/etc/network" ]; then
echo "Missing target network directory"
exit 1
fi
if [ -z "$NIC_COUNT" ]; then
echo "Missing NIC COUNT"
exit 1
fi
if [ ! -r "$VMNETCONF" ]; then
echo "Missing VM's network configuration: $CONFDIR/$INSTANCE_NAME/net.conf"
exit 1
fi
cat > $TARGET/etc/network/interfaces <<EOF
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
auto lo
iface lo inet loopback
EOF
if [ "$NIC_COUNT" -gt 0 ]; then
. $VMNETCONF
if [ -n "${IPV4_NET% *}" ]; then
cat >> $TARGET/etc/network/interfaces <<EOF
auto eth0
iface eth0 inet static
pre-up /sbin/ip link set \$IFACE up
pre-up /sbin/ip route add 169.254.42.1 dev \$IFACE
address ${IPV4_NET% *}
gateway 169.254.42.1
EOF
fi
if [ -n "${IPV6_NET% *}" ]; then
cat >> $TARGET/etc/network/interfaces <<EOF
auto eth0
iface eth0 inet6 static
address ${IPV6_NET% *}
gateway fe80::42:1
accept_ra 0
autoconf 0
dad-attempts 0
EOF
fi
fi
exit 0
#!/bin/bash
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Replace /etc/resolv.conf file in VM's rootfs. Without this hook,
# Debootstrap uses the hypervisor's resolv.conf.
#
# exit on error so ganeti is aware and outputs the message to the user
set -e
if [ ! -d "$TARGET" ]; then
echo "Missing target directory"
exit 1
fi
cat > $TARGET/etc/resolv.conf <<EOF
# ARN
nameserver 2a00:5881:8100:1000::3
# Grifon
nameserver 2a00:5884:8218::1
# ARN failback v4
nameserver 89.234.141.66
domain arn-fai.net
search arn-fai.net
EOF
exit 0
#!/bin/sh
#
# This is an example script that sets the timezone to a given default,
# or to the one of the host if none is configured.
# exit on error so ganeti is aware and outputs the message to the user
set -e
if [ ! -d "$TARGET" ]; then
echo "Missing target directory"
exit 1
fi
if [ -r confdata/timezone ]; then
cp confdata/timezone $TARGET/etc/
else
cp /etc/timezone $TARGET/etc/
fi
chroot $TARGET dpkg-reconfigure --frontend noninteractive tzdata
exit 0
#!/bin/bash
# Copyright (C) 2015-2016 Alsace Réseau Neutre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Include ARN variables
. /etc/ganeti/common-arn-vars
VMNETCONF=$CONFDIR/$INSTANCE/net.conf
[ -r $VMNETCONF ] || exit 1