Skip to content

Instantly share code, notes, and snippets.

@offlinehacker
Created March 10, 2018 09:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save offlinehacker/a7368e33b1e082693e7083811900a89e to your computer and use it in GitHub Desktop.
Save offlinehacker/a7368e33b1e082693e7083811900a89e to your computer and use it in GitHub Desktop.
Libvirt deploy
#!/bin/bash
set -e
VIRSH=virsh
LIBVIRT_HOST=root@192.168.122.1
LIBVIRT_URI=qemu+ssh://$LIBVIRT_HOST/system
POOL=images
PROJECT=$1
SHARE_DIR=/storage/share
ROOT_DEV=/dev/vda1
function getIp() {
sleepSeconds=10
while ! $VIRSH -c $LIBVIRT_URI domifaddr $1 | grep vnet > /dev/null; do
sleep $sleepSeconds
done
$VIRSH -c $LIBVIRT_URI domifaddr $1 | grep vnet | awk '{print $4}' | cut -d '/' -f1
}
function listVolumes() {
$VIRSH -c $LIBVIRT_URI vol-list $1 | tail -n +3 | xargs -I{} echo {} | awk '{print $1}'
}
function listDomains() {
$VIRSH -c $LIBVIRT_URI list $1 | xargs -I{} echo {} | awk '{print $2}'
}
function createBackedVolume() {
$VIRSH -c $LIBVIRT_URI vol-create $POOL <(cat <<EOF
<volume type='file'>
<name>$2</name>
<capacity unit='GB'>$3</capacity>
<target>
<format type='qcow2'/>
<features>
<lazy_refcounts/>
</features>
</target>
<backingStore>
<path>$1</path>
<format type='qcow2'/>
</backingStore>
</volume>
EOF
)
}
function volumePath() {
$VIRSH -c $LIBVIRT_URI vol-path --pool=$POOL $1
}
function waitForSSH() {
echo "# waiting for connection to $1"
maxConnectionAttempts=10
sleepSeconds=10
index=1
while (( $index <= $maxConnectionAttempts ))
do
ssh root@$1 "exit 0"
case $? in
(0) echo "${index}> Success"; break ;;
(*) echo "${index} of ${maxConnectionAttempts}> Bastion SSH server not ready yet, waiting ${sleepSeconds} seconds..." ;;
esac
sleep $sleepSeconds
((index+=1))
done
}
function createDomain() {
$VIRSH -c $LIBVIRT_URI define <(cat <<EOF
<domain type='kvm'>
<name>$1</name>
<memory unit='GB'>$2</memory>
<vcpu placement='static'>4</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-i440fx-2.8'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<vmport state='off'/>
</features>
<cpu mode='custom' match='exact'>
<model fallback='forbid'>Broadwell-noTSX</model>
<vendor>Intel</vendor>
</cpu>
<clock offset='utc'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='$(volumePath "$1.qcow2")'/>
<backingStore type='file' index='1'>
<format type='raw'/>
<source file='$(volumePath "nixos-17.03.qcow2")'/>
<backingStore/>
</backingStore>
<target dev='vda' bus='virtio'/>
<alias name='virtio-disk0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
</disk>
<controller type='usb' index='0' model='ich9-ehci1'>
<alias name='usb'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x7'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci1'>
<alias name='usb'/>
<master startport='0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci2'>
<alias name='usb'/>
<master startport='2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x1'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci3'>
<alias name='usb'/>
<master startport='4'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x2'/>
</controller>
<controller type='virtio-serial' index='0'>
<alias name='virtio-serial0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
</controller>
<controller type='pci' index='0' model='pci-root'>
<alias name='pci.0'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<filesystem type='mount' accessmode='mapped'>
<source dir='$SHARE_DIR'/>
<target dir='share'/>
<alias name='fs0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/>
</filesystem>
<interface type='network'>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='virtio'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/3'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/3'>
<source path='/dev/pts/3'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<channel type='spicevmc'>
<target type='virtio' name='com.redhat.spice.0' state='connected'/>
<alias name='channel0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
<channel type='unix'>
<source mode='bind'/>
<target type='virtio' name='org.qemu.guest_agent.0' state='disconnected'/>
<alias name='channel1'/>
<address type='virtio-serial' controller='0' bus='0' port='2'/>
</channel>
<input type='mouse' bus='ps2'>
<alias name='input0'/>
</input>
<input type='keyboard' bus='ps2'>
<alias name='input1'/>
</input>
<graphics type='spice' port='5900' autoport='yes' listen='127.0.0.1'>
<listen type='address' address='127.0.0.1'/>
<image compression='off'/>
</graphics>
<sound model='ich6'>
<alias name='sound0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</sound>
<video>
<model type='virtio' heads='1' primary='yes'>
<acceleration accel3d='no'/>
</model>
<alias name='video0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<redirdev bus='usb' type='spicevmc'>
<alias name='redir0'/>
<address type='usb' bus='0' port='1'/>
</redirdev>
<redirdev bus='usb' type='spicevmc'>
<alias name='redir1'/>
<address type='usb' bus='0' port='2'/>
</redirdev>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/>
</memballoon>
</devices>
<seclabel type='none' model='none'/>
<seclabel type='dynamic' model='dac' relabel='yes'>
<label>+0:+0</label>
<imagelabel>+0:+0</imagelabel>
</seclabel>
</domain>
EOF
)
}
function startDomain() {
$VIRSH -c $LIBVIRT_URI start $1
}
if ! listDomains "--all" | grep $PROJECT >/dev/null; then
if ! listVolumes $POOL | grep "nixos-17.03.qcow2" >/dev/null; then
echo "--> uploading base volume: nixos-17.03.qcow2"
image=$(nix-build --no-out-link -E "import <nixpkgs/nixos> { configuration = <xtruder/nix-profiles/images/qemu-img.nix>; }" -A config.system.build.qemu -j 4)
size=$(stat -Lc%s nixos)
$VIRSH -c $LIBVIRT_URI vol-create-as $POOL nixos-17.03.qcow2 --format qcow2
$VIRSH vol-upload --pool $POOL nixos-17.03.qcow2 nixos-17.03.qcow2
echo "# volume uploaded"
fi
echo "--> Creating root volume"
createBackedVolume nixos-17.03.qcow2 $PROJECT.qcow2 42
echo "--> Creating domain"
createDomain "$PROJECT" 4
fi
if ! listDomains | grep $PROJECT; then
echo "--> Starting domain"
startDomain "$PROJECT"
fi
echo "--> Getting IP"
ip=$(getIp "$PROJECT")
echo "#Ip: ${ip}"
echo "--> Waiting for ssh"
waitForSSH ${ip}
echo "--> Resizing root filesystem"
ssh -o ProxyJump="$LIBVIRT_HOST" root@${ip} resize2fs $ROOT_DEV
echo "--> Building system"
export NIXOS_CONFIG=$PWD/environments/$PROJECT.nix
system=$(nix-build -E 'import <nixpkgs/nixos> {}' -A system -j 4)
echo "# system: ${system}"
echo "--> Copy closure"
NIX_SSHOPTS="-o ProxyJump='$LIBVIRT_HOST'" nix-copy-closure --to root@${ip} $system
echo "--> Switching config"
ssh -o ProxyJump="$LIBVIRT_HOST" root@${ip} ${system}/bin/switch-to-configuration switch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment