#!/bin/bash -e #### NOTE TO SELF SO I DON'T FORGET LATER: you can pass the name of an environment JSON file to this script # (e.g., test-custom instead of Test-Laptop) to build using that one # bash imports source ./virtualbox_env.sh if [[ -f ./vbox_override.sh ]] { source ./vbox_override.sh } if [[ "$OSTYPE" == msys || "$OSTYPE" == cygwin ]] { setglobal WIN = 'TRUE' } set -x if [[ -f ./proxy_setup.sh ]] { source ./proxy_setup.sh } if [[ -z "$CURL" ]] { echo "CURL is not defined" exit } # Bootstrap VM Defaults (these need to be exported for Vagrant's Vagrantfile) # DO NOT EDIT THESE HERE, INSTEAD EDIT THEM IN vbox_override.sh export BOOTSTRAP_APT_MIRROR=$(BOOTSTRAP_APT_MIRROR:-) export BOOTSTRAP_VM_MEM=$(BOOTSTRAP_VM_MEM:-2048) export BOOTSTRAP_VM_CPUS=$(BOOTSTRAP_VM_CPUS:-1) export BOOTSTRAP_VM_DRIVE_SIZE=$(BOOTSTRAP_VM_DRIVE_SIZE:-20480) export CLUSTER_VM_MEM=$(CLUSTER_VM_MEM:-2560) export CLUSTER_VM_CPUS=$(CLUSTER_VM_CPUS:-2) export CLUSTER_VM_DRIVE_SIZE=$(CLUSTER_VM_DRIVE_SIZE:-20480) setglobal BASE_DIR = $[dirname $(BASH_SOURCE[0])] setglobal VBOX_DIR = ""$BASE_DIR/vbox"" setglobal P = $[cd $VBOX_DIR ; /bin/pwd] || exit # from EVW packer branch proc vbm_import { local -r image_name="$1" local -r vm_name="$2" shift 2 # this currently assumes that only one virtual system is imported $VBM import $image_name --vsys 0 --vmname $vm_name @Argv } ###################################################### # Function to download files necessary for VM stand-up # proc download_VM_files { pushd $P setglobal ROM = 'gpxe-1.0.1-80861004.rom' setglobal CACHEDIR = "~/bcpc-cache" if [[ ! -f $ROM ]] { if [[ -f $CACHEDIR/$ROM ]] { cp $CACHEDIR/$ROM . } else { $CURL -o gpxe-1.0.1-80861004.rom "http://rom-o-matic.net/gpxe/gpxe-1.0.1/contrib/rom-o-matic/build.php" -H "Origin: http://rom-o-matic.net" -H "Host: rom-o-matic.net" -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" -H "Referer: http://rom-o-matic.net/gpxe/gpxe-1.0.1/contrib/rom-o-matic/build.php" -H "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3" --data "version=1.0.1&use_flags=1&ofmt=ROM+binary+%28flashable%29+image+%28.rom%29&nic=all-drivers&pci_vendor_code=8086&pci_device_code=1004&PRODUCT_NAME=&PRODUCT_SHORT_NAME=gPXE&CONSOLE_PCBIOS=on&BANNER_TIMEOUT=20&NET_PROTO_IPV4=on&COMCONSOLE=0x3F8&COMSPEED=115200&COMDATA=8&COMPARITY=0&COMSTOP=1&DOWNLOAD_PROTO_TFTP=on&DNS_RESOLVER=on&NMB_RESOLVER=off&IMAGE_ELF=on&IMAGE_NBI=on&IMAGE_MULTIBOOT=on&IMAGE_PXE=on&IMAGE_SCRIPT=on&IMAGE_BZIMAGE=on&IMAGE_COMBOOT=on&AUTOBOOT_CMD=on&NVO_CMD=on&CONFIG_CMD=on&IFMGMT_CMD=on&IWMGMT_CMD=on&ROUTE_CMD=on&IMAGE_CMD=on&DHCP_CMD=on&SANBOOT_CMD=on&LOGIN_CMD=on&embedded_script=&A=Get+Image" } if [[ -d $CACHEDIR && ! -f $CACHEDIR/$ROM ]] { cp $ROM $CACHEDIR/$ROM } } setglobal ISO = 'ubuntu-14.04-mini.iso' # Grab the Ubuntu installer image if [[ ! -f $ISO ]] { if [[ -f $CACHEDIR/$ISO ]] { cp $CACHEDIR/$ISO . } else { #$CURL -o $ISO http://archive.ubuntu.com/ubuntu/dists/trusty/main/installer-amd64/current/images/netboot/mini.iso $CURL -o $ISO http://archive.ubuntu.com/ubuntu/dists/trusty-updates/main/installer-amd64/current/images/netboot/mini.iso } if [[ -d $CACHEDIR && ! -f $CACHEDIR/$ISO ]] { cp $ISO $CACHEDIR } } setglobal BOX = ''trusty-server-cloudimg-amd64-vagrant-disk1.box'' # Can we create the bootstrap VM via Vagrant if hash vagrant !2 > /dev/null { echo "Vagrant detected - downloading Vagrant box for bcpc-bootstrap VM" if [[ ! -f $BOX ]] { if [[ -f $CACHEDIR/$BOX ]] { cp $CACHEDIR/$BOX . } else { $CURL -o $BOX http://cloud-images.ubuntu.com/vagrant/trusty/current/$BOX } if [[ -d $CACHEDIR && ! -f $CACHEDIR/$BOX ]] { cp $BOX $CACHEDIR } } } popd } ################################################################################ # Function to remove VirtualBox DHCP servers # By default, checks for any DHCP server on networks without VM's & removes them # (expecting if a remove fails the function should bail) # If a network is provided, removes that network's DHCP server # (or passes the vboxmanage error and return code up to the caller) # proc remove_DHCPservers { local network_name=$(1-) if [[ -z "$network_name" ]] { # make a list of VM UUID's local vms=$[$VBM list vms|sed 's/^.*{\([0-9a-f-]*\)}/\1/] # make a list of networks (e.g. "vobxnet0 vboxnet1") local vm_networks=$[for vm in [$vms] { \ $VBM showvminfo --details --machinereadable $vm | \ grep -i '^hostonlyadapter[2-9]=' | \ sed -e 's/^.*=//' -e 's/"//g'; \ } | sort -u] # will produce a regular expression string of networks which are in use by VMs # (e.g. ^vboxnet0$|^vboxnet1$) local existing_nets_reg_ex=$[sed -e 's/^/^/' -e '/$/$/' -e 's/ /$|^/g' <<< $vm_networks] $VBM list dhcpservers | grep -E "^NetworkName:\s+HostInterfaceNetworking" | awk '{print $2}' | while read -r network_name { [[ -n $existing_nets_reg_ex ]] && ! egrep -q $existing_nets_reg_ex <<< $network_name && continue remove_DHCPservers $network_name } } else { $VBM dhcpserver remove --netname $network_name && local return=0 || local return=$Status return $return } } ################################################################### # Function to create the bootstrap VM # uses Vagrant or stands-up the VM in VirtualBox for manual install # proc create_bootstrap_VM { pushd $P remove_DHCPservers if hash vagrant !2 > /dev/null { echo "Vagrant detected - using Vagrant to initialize bcpc-bootstrap VM" cp ../Vagrantfile . vagrant up setglobal keyfile = $[vagrant ssh-config bootstrap | awk '/Host bootstrap/,/^$/{ if ($0 ~ /^ +IdentityFile/) print $2}] if [[ -f "$keyfile" ]] { cp $keyfile insecure_private_key } } else { echo "Vagrant not detected - using raw VirtualBox for bcpc-bootstrap" if [[ -z "$WIN" ]] { # Make the three BCPC networks we'll need, but clear all nets and dhcpservers first for i in [0 1 2 3 4 5 6 7 8 9] { if [[ ! -z `$VBM list hostonlyifs | grep vboxnet$i | cut -f2 -d" "` ]] { $VBM hostonlyif remove vboxnet$i || true } } } else { # On Windows the first interface has no number # The second interface is #2 # Remove in reverse to avoid substring matching issue for i in [10 9 8 7 6 5 4 3 2 1] { if [[ i -gt 1 ]] { setglobal IF = ""VirtualBox Host-Only Ethernet Adapter #$i""; } else { setglobal IF = '"VirtualBox Host-Only Ethernet Adapter'"; } if [[ ! -z `$VBM list hostonlyifs | grep "$IF"` ]] { $VBM hostonlyif remove $IF } } } $VBM hostonlyif create $VBM hostonlyif create $VBM hostonlyif create if [[ -z "$WIN" ]] { remove_DHCPservers vboxnet0 || true remove_DHCPservers vboxnet1 || true remove_DHCPservers vboxnet2 || true # use variable names to refer to our three interfaces to disturb # the remaining code that refers to these as little as possible - # the names are compact on Unix : setglobal VBN0 = 'vboxnet0' setglobal VBN1 = 'vboxnet1' setglobal VBN2 = 'vboxnet2' } else { # However, the names are verbose on Windows : setglobal VBN0 = '"VirtualBox Host-Only Ethernet Adapter'" setglobal VBN1 = '"VirtualBox Host-Only Ethernet Adapter #2'" setglobal VBN2 = '"VirtualBox Host-Only Ethernet Adapter #3'" } $VBM hostonlyif ipconfig $VBN0 --ip 10.0.100.2 --netmask 255.255.255.0 $VBM hostonlyif ipconfig $VBN1 --ip 172.16.100.2 --netmask 255.255.255.0 $VBM hostonlyif ipconfig $VBN2 --ip 192.168.100.2 --netmask 255.255.255.0 # Create bootstrap VM for vm in [bcpc-bootstrap] { # Only if VM doesn't exist if ! $VBM list vms | grep "^\"$(vm)\"" { # define this if you have a pre-built OVA image # (virtualbox exported machine image), for example as # built by # https://github.com/ericvw/chef-bcpc/tree/packer/bootstrap setglobal ARCHIVED_BOOTSTRAP = '../images/build/virtualbox/bcpc-bootstrap/packer-bcpc-bootstrap_ubuntu-14.04.2-amd64.ova' if [[ -n "$ARCHIVED_BOOTSTRAP" && -f "$ARCHIVED_BOOTSTRAP" ]] { vbm_import $ARCHIVED_BOOTSTRAP bcpc-bootstrap } else { exit $VBM createvm --name $vm --ostype Ubuntu_64 --basefolder $P --register $VBM modifyvm $vm --memory $BOOTSTRAP_VM_MEM $VBM modifyvm $vm --cpus $BOOTSTRAP_VM_CPUS $VBM modifyvm $vm --vram 16 $VBM storagectl $vm --name "SATA Controller" --add sata $VBM storagectl $vm --name "IDE Controller" --add ide # Create a number of hard disks setglobal port = '0' for disk in [a] { $VBM createhd --filename $P/$vm/$vm-$disk.vdi --size $BOOTSTRAP_VM_DRIVE_SIZE $VBM storageattach $vm --storagectl "SATA Controller" --device 0 --port $port --type hdd --medium $P/$vm/$vm-$disk.vdi setglobal port = $shExpr('port+1') } # Add the bootable mini ISO for installing Ubuntu ISO $VBM storageattach $vm --storagectl "IDE Controller" --device 0 --port 0 --type dvddrive --medium $ISO $VBM modifyvm $vm --boot1 disk } # Add the network interfaces $VBM modifyvm $vm --nic1 nat $VBM modifyvm $vm --nic2 hostonly --hostonlyadapter2 $VBN0 $VBM modifyvm $vm --nic3 hostonly --hostonlyadapter3 $VBN1 $VBM modifyvm $vm --nic4 hostonly --hostonlyadapter4 $VBN2 } } } popd } ################################################################### # Function to create the BCPC cluster VMs # proc create_cluster_VMs { # Gather VirtualBox networks in use by bootstrap VM (Vagrant simply uses the first not in-use so have to see what was picked) setglobal oifs = $IFS setglobal IFS = '$'\n'' setglobal bootstrap_interfaces = ''($($VBM showvminfo bcpc-bootstrap --machinereadable|egrep '^hostonlyadapter[0-9]=' |sort|sed -e 's/.*=//' -e 's/"//g')) setglobal IFS = $oifs setglobal VBN0 = $(bootstrap_interfaces[0]) setglobal VBN1 = $(bootstrap_interfaces[1]) setglobal VBN2 = $(bootstrap_interfaces[2]) # Create each VM for vm in [bcpc-vm1 bcpc-vm2 bcpc-vm3] { # Only if VM doesn't exist if ! $VBM list vms | grep "^\"$(vm)\"" { $VBM createvm --name $vm --ostype Ubuntu_64 --basefolder $P --register $VBM modifyvm $vm --memory $CLUSTER_VM_MEM $VBM modifyvm $vm --cpus $CLUSTER_VM_CPUS $VBM modifyvm $vm --vram 16 $VBM storagectl $vm --name "SATA Controller" --add sata # Create a number of hard disks setglobal port = '0' for disk in [a b c d e] { $VBM createhd --filename $P/$vm/$vm-$disk.vdi --size $CLUSTER_VM_DRIVE_SIZE $VBM storageattach $vm --storagectl "SATA Controller" --device 0 --port $port --type hdd --medium $P/$vm/$vm-$disk.vdi setglobal port = $shExpr('port+1') } # Add the network interfaces $VBM modifyvm $vm --nic1 hostonly --hostonlyadapter1 $VBN0 --nictype1 82543GC $VBM setextradata $vm VBoxInternal/Devices/pcbios/0/Config/LanBootRom $P/gpxe-1.0.1-80861004.rom $VBM modifyvm $vm --nic2 hostonly --hostonlyadapter2 $VBN1 $VBM modifyvm $vm --nic3 hostonly --hostonlyadapter3 $VBN2 # Set hardware acceleration options $VBM modifyvm $vm --largepages on --vtxvpid on --hwvirtex on --nestedpaging on --ioapic off } } } proc install_cluster { setglobal environment = $(1-Test-Laptop) setglobal ip = $(2-10.0.100.3) # VMs are now created - if we are using Vagrant, finish the install process. if hash vagrant !2 > /dev/null { # N.B. As of Aug 2013, grub-pc gets confused and wants to prompt re: 3-way # merge. Sigh. #vagrant ssh -c "sudo ucf -p /etc/default/grub" #vagrant ssh -c "sudo ucfr -p grub-pc /etc/default/grub" vagrant ssh -c "test -f /etc/default/grub.ucf-dist && sudo mv /etc/default/grub.ucf-dist /etc/default/grub" || true # Duplicate what d-i's apt-setup generators/50mirror does when set in preseed if test -n $http_proxy { if ! vagrant ssh -c "grep -z '^Acquire::http::Proxy ' /etc/apt/apt.conf" { vagrant ssh -c "echo 'Acquire::http::Proxy \"$http_proxy\";' | sudo tee -a /etc/apt/apt.conf" } # write the proxy to a known absolute location on the filesystem so that it can be sourced by build_bins.sh (and maybe other things) setglobal PROXY_INFO_SH = '"/home/vagrant/proxy_info.sh'" if ! vagrant ssh -c "test -f $PROXY_INFO_SH" { vagrant ssh -c "echo -e 'export http_proxy=$http_proxy\nexport https_proxy=$https_proxy' | sudo tee -a $PROXY_INFO_SH" } setglobal CURLRC = '"/home/vagrant/.curlrc'" if ! vagrant ssh -c "test -f $CURLRC" { vagrant ssh -c "echo -e 'proxy = $http_proxy' | sudo tee -a $CURLRC" } setglobal GITCONFIG = '"/home/vagrant/.gitconfig'" if ! vagrant ssh -c "test -f $GITCONFIG" { vagrant ssh -c "echo -e '[http]\nproxy = $http_proxy' | sudo tee -a $GITCONFIG" } # copy any additional provided CA root certificates to the system store # note that these certificates must follow the restrictions of update-ca-certificates (i.e., end in .crt and be PEM) setglobal CUSTOM_BASE = '"custom'" setglobal CUSTOM_CA_DIR = ""/usr/share/ca-certificates/$CUSTOM_BASE"" for CERT in [$[ls -1 $BASE_DIR/cacerts]] { vagrant ssh -c "sudo mkdir -p $CUSTOM_CA_DIR" vagrant ssh -c "if [[ ! -f $CUSTOM_CA_DIR/$CERT ]]; then sudo cp /chef-bcpc-host/cacerts/$CERT $CUSTOM_CA_DIR/$CERT; fi" vagrant ssh -c "echo $CUSTOM_BASE/$CERT | sudo tee -a /etc/ca-certificates.conf" } vagrant ssh -c "sudo /usr/sbin/update-ca-certificates" } echo "Bootstrap complete - setting up Chef server" echo "N.B. This may take approximately 30-45 minutes to complete." ./bootstrap_chef.sh --vagrant-remote $ip $environment ./enroll_cobbler.sh } else { ./non_vagrant_boot.sh } } # only execute functions if being run and not sourced if [[ "${BASH_SOURCE[0]}" == "${0}" ]] { download_VM_files create_bootstrap_VM create_cluster_VMs install_cluster $ifsjoin(Argv) }