#! /bin/bash
#: Title : vm-create
#: Date Created: Sat Jan 29 01:54:07 PST 2011
#: Last Edit : Wed Feb 9 13:24:14 PST 2011
#: Author : please_try_again
#: Version : 1.0
#: Description : install OS from the Internet or local iso in a kvm vm
# ~~~~
prg=$(basename $0)
which virt-install &> /dev/null || Error "virt-install not installed"
"x$(ps ax | grep libvirtd | awk '!/grep/ { print $1 }')" == "x" ] && Error "libvirtd is not running"
VIRTINST_VER=$(virt-install --version | sed 's|^0||;s|\.||g')
LIVIRT_VER=$(libvirtd --version | sed 's|^0-9]*\([0-9]\)|\1|;s|\.||g;s|^0||')
# ~~~~
# DEFINE THE VARIABLES IN THIS SECTIONS TO MATCH YOUR SYSTEM
IMGPATH=/misc/vm # where to put the vm images.
ISOPATH=/misc/iso # where to save iso images
IMPPATH=/import # where to mount storage pools
POOLNAME=install # pollname for remote install
POOLPATH=/var/lib/libvirt/images/install
# your gateway (unless set in the environment variable GATEWAY)
GW=192.168.101.1
# YOU MIGHT EDIT THE DEFAULTS BELOW
DEF_HYPERVISOR=qemu # qemu or xen
#DEF_HOST= # default to localhost
DEF_CONNECT=${VIRSH_DEFAULT_CONNECT_URI:-${DEF_HYPERVISOR}://$DEF_HOST/system}
DEF_RAM=512
DEF_CPUS=1
DEF_ARCH=i386
DEF_KERN=generic26
DEF_VIDEO=vga # cirrus, vga or vmvga
DEF_AUDIO=default # AC97 if the hypervisor supports it, otherwise it will be ES1370.
DEF_VMSIZE=10 # default size of virtual machines (10GB)
DISPLAYOPTS=" --vnc --vnclisten=0.0.0.0"
$VIRTINST_VER -gt 5003 ] && BOOTOPTS=" --boot=cdrom,hd,network"
# network defaults
DEF_BRIDGE=br0
DEF_NIC=eth0
DEF_NAT=virbr0
DEF_NETWORK=nat # nat or bridge
DEF_NETMASK=0xffffff00 # should be fine for a class C network
CREATEBRIDGE=1 # create bridge if needed
STARTVIRBR=1 # start virtual network (NAT) if needed
# You might change distros default versions
fedora_ver=14
opensuse_ver=11.3
opensuseM6_ver=11.4 ; opensuseM6_rel=1034
ubuntu_ver=maverick ; ubuntu_rel=10.10
debian_ver=lenny ; debian_rel=508
mandriva_ver=2010.2
archlinux_ver=2010.05
centos_ver=5.5
freebsd_ver="8.2" ; freebsd_rel="-RC3"
openbsd_ver="4.8"
netbsd_ver="5.1"
dflybsd_ver="2.8.2" ; dflybsd_rel=REL
# You might add/change ditros urls.
debian_url="ftp://ftp.osuosl.org/debian/dists/VER/main/installer-ARCH/"
fedora_url="ftp://ftp.osuosl.org/pub/fedora/linux/releases/VER/Fedora/ARCH/os/"
mandriva_url="ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/VER/i586/"
ubuntu_url="ftp://ftp.osuosl.org/pub/ubuntu/dists/VER/main/installer-ARCH/"
archlinux_iso="ftp://ftp.osuosl.org/pub/archlinux/iso/VER/archlinux-VER-netinstall-ARCH.iso"
centos_iso="http://centos.arcticnetwork.ca/VER/isos/ARCH/CentOS-VER-ARCH-netinstall.iso"
debian_iso="ftp://debian.osuosl.org/debian-cd/current/ARCH/iso-cd/debian-REL-ARCH-netinst.iso"
fedora_iso="ftp://ftp.osuosl.org/pub/fedora/linux/releases/VER/Fedora/ARCH/iso/Fedora-VER-ARCH-netinst.iso"
mandriva_iso="ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/VER/ARCH/install/images/boot.iso"
opensuse_iso="http://download.opensuse.org/distribution/VER/iso/openSUSE-VER-NET-ARCH.iso"
ubuntu_iso="ftp://ftp.osuosl.org/pub/ubuntu/dists/VER/main/installer-ARCH/current/images/netboot/mini.iso"
freebsd_iso="ftp://ftp.freebsd.org/pub/FreeBSD/releases/ARCH/ISO-IMAGES/VER/FreeBSD-VERREL-ARCH-bootonly.iso"
openbsd_iso="ftp://ftp.openbsd.org/pub/OpenBSD/VER/ARCH/install${openbsd_ver/./}.iso"
netbsd_iso="ftp://ftp.netbsd.org/pub/NetBSD/iso/VER/ARCHcd-VER.iso"
dflybsd_iso="ftp://ftp.dragonflybsd.org/iso-images/dfly-ARCH-2.8.2_REL.iso.bz2"
opensuseM6_iso="http://download.opensuse.org/distribution/11.4-Milestone6/iso/openSUSE-NET-BuildREL-ARCH.iso"
#netbsd_iso="ftp://ftp.netbsd.org/pub/NetBSD/NetBSD-VER/ARCH/installation/cdrom/boot.iso"
# ~~~
# You should not modify the script blelow this point.
# recognized OS types to this day.
OSTYPES="debianetch debianlenny debiansqueeze \
fedora5 fedora6 fedora7 fedora8 fedora9 fedora10 fedora11 fedora12 fedora13 \
generic24 generic26 \
virtio26 \
mandriva2009 mandriva2010 \
mes5 mes5.1 \
rhel2.1 rhel3 rhel4 rhel5 rhel5.4 rhel6 \
sles10 sles11 \
ubuntuhardy ubuntuintrepid ubuntujaunty ubuntukarmic \
generic \
msdos \
netware4 netware5 netware6 \
opensolaris solaris10 solaris9 \
freebsd6 freebsd7 \
openbsd4 \
vista win2k win2k3 win2k8 win7 winxp winxp64"
$VIRTINST_VER -lt 5003 ] && Error "virt-install 0.500.3 or newer required"
$VIRTINST_VER -ge 5004 ] && OSTYPES="$OSTYPES fedora14 ubuntulucid freebsd8"
$VIRTINST_VER -ge 5005 ] && OSTYPES="$OSTYPES ubuntumaverick"
$LIVIRT_VER -ge 87 ] && Y="-- "
# valid xen and qemu MAC addresses
qemu_mac="52:54:00:"
xen_mac="00:16:3e:"
# ~~~
# use the popup library if found
which popup &>/dev/null && source $(which popup)
# use popup functions if available
function Error { declare -F | grep -q error || exec echo "Error: $*" ; error "$*" ;}
function Warn { declare -F | grep -q warn && warn "$*" || echo "Warning: $*" ;}
# ~~~
function chkarg { "${1:0:1}" == "-" ] && Error "invalid argument: $1" ;}
function chkopt { "x$1" == "x" ] && Error "you should provide a vm name" ;}
function syntax {
if "$1" == "-d" ] ; then
# show defaults
grep '^DEF_' $0 | sed '/\[/d;/^[ ]/d;s/#.*//;/=\$.*/d;s/"//g' | awk -F "=" '{ sub(/^ /,"", $2) ; printf "%-20s %s
", $1, $2}'
else
cat << EOFSYNTAX
usage:
$prg vm name
options:
-c --connect <host> : remote host where to create the vm
-r --ram <ram in MB> : amount of ram (default 512MB)
-a --arch <i386|amd64> : architecture (i386 or amd64)
-o --os <os variant> : os variant (example: fedora14, mandriva2010)
-u --url <os> : os (fedora, debian, ubuntu, opensuse, mandriva)
-i --iso <img.iso> : iso image
-p --path <directory> : where to store vm images
-s --size <size> : size of virtual machine in GB
-V --virtio : same as -o virtio26
-v --video : video device: cirrus, vga* or vmvga (for kvm)
-R --release : OS version to install (other than default)
-S --sound : enable sound device (ac97)
-l --sdl : use sdl display rather than vnc
-L --live : boot live CD
-b --bridge <bridge> : use network bridge (otherwise use DEF_NETWORK if defined or 'nat')
-e --eth <nic> : network interface to use for bridge (otherwise use DEF_NIC if defined or eth0)
-x --xen : use Xen hypervisor rather than kvm
-t --try : just print but not execute the command
-h --help : show this help
-d --defaults : show defaults
recognized OS variants :
`echo $OSTYPES | fmt`
available guest systems :
$(awk -F "=" '/^[a-zA-Z0-9]*_url=|^[a-zA-Z0-9]*_iso=/ { sub(/_.*/,"",$1); print $1 }' $0 | sort -u | tr "
" " ")
EOFSYNTAX
fi
exit
}
function createBridge {
"x$gw" == "x" ] && Error "no gateway defined"
ping -q -c 1 -W 2 $gw > /dev/null || Error "gateway $gw is unreachable"
echo " - creating bridge $1"
brctl addbr $1
ifconfig $2 0.0.0.0 promisc
brctl addif $1 $2
ifconfig $1 inet $3 netmask $DEF_NETMASK
brctl stp $br on
route del default 2>/dev/null
route add default gw $gw 2>/dev/null
}
function importPool {
virsh -c $hyp pool-dumpxml $1 2>/dev/null | grep -q $2 && {
virsh -c $hyp pool-info $1 | grep -q running || virsh -c $hyp pool-start $1
virsh -c $hyp pool-refresh $1
return
}
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-destroy $1 2>/dev/null
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-undefine $1 2>/dev/null
$SSH mkdir -m 600 $POOLPATH 2>/dev/null
virsh -c $hyp pool-create-as $1 netfs $2 $ISOPATH -- -- $Y$POOLPATH
}
function getarch {
case $arch in
amd64)
case $os in
fedora|mandriva|archlinux) arch=x86_64 ;;
esac
;;
i386)
case $os in
mandriva|opensuse*) arch=i586 ;;
archlinux) arch=i686 ;;
esac
;;
esac
}
# find out if we need to download a netinstall iso image
function geturl {
getarch
"$rflag" ] && url=${1}_iso || url=${1}_url ; url=${!url}
"$url" ] || { url=${1}_iso ; url=${!url} ; iflag=1 ; }
url=$(echo $url | sed "s|VER|$VER|g;s|ARCH|$arch|g;s|REL|$REL|g")
"$url" ] || Error "No url defined for $1"
if "$iflag" ] ; then
-d $ISOPATH ] && cd $ISOPATH || Error "$ISOPATH doesn't exist"
isoimg=$(basename $url .bz2)
$tflag -eq 0 ] && ( -f ./$isoimg ] || wget -v $url )
-f ./$isoimg.bz2 ] && bunzip2 -v $isoimg.bz2
if "$rflag" ] ; then
$tflag -eq 0 ] && importPool $POOLNAME $HOSTNAME
url=" --disk vol=$POOLNAME/$isoimg,device=cdrom"
else
url=" --cdrom=$ISOPATH/$isoimg"
fi
cd - >/dev/null
else
url=" --location=$url"
fi
}
function chkMAC {
Mac=$(echo ${1:0:9} | tr ":upper:]" ":lower:]")
"$Mac" == "$MAC" ] || Error "invalid $HV MAC address: $1"
"$(echo ${1:9} | sed 's|^:]*||g')" == "::" ] || Error "invalid $HV MAC address: $1"
a=$(echo ${1:9} | sed 's|:||g;s|^0-9a-fA-F]*||g')
${#a} -eq 6 ] || Error "invalid $HV MAC address: $1"
}
# ~~~
uflag=0 ; vflag=0 ; bflag=0 ; sflag=0 ; dflag=0 ; tflag=0 ; lflag=0 ; aflag=0
url=""
# evaluate arguments
args=`getopt -q -u -o c:r:a:o:u:i:p:s:b:e:m:R:v:xSVlLhdt -l connect:,ram:,arch:,os:,url:,iso:,path:,size:,bridge:,eth:,mac:,release:,video:,xen,virtio,sdl,sound,live,help,defaults,try -- "$@"`
set -- $args
for i; do
case "$i" in
-c|--connect) shift; chkarg $1 ; host="$1" ; HYP="+ssh://$host/system" ; shift ;;
-r|--ram) shift; chkarg $1 ; ram="$1" ; shift ;;
-a|--arch) shift; chkarg $1 ; arch="$1" ; shift ;;
-o|--os) shift; chkarg $1 ; ostype="$1" ; shift ;;
-i|--iso) shift; chkarg $1 ; iso="$1" ; uflag=$(($uflag | 1)) ; shift ;;
-u|--url) shift; chkarg $1 ; os="$1" ; uflag=$(($uflag | 2)) ; shift ;;
-p|--path) shift; chkarg $1 ; imgpath="$1" ; shift ;;
-s|--size) shift; chkarg $1 ; vmsize="$1" ; shift ;;
-b|--bridge) shift; chkarg $1 ; br="$1" ; bflag=1 ; shift ;;
-e|--eth) shift; chkarg $1 ; nic="$1" ; shift ;;
-m|--mac) shift; chkarg $1 ; mac="$1" ; shift ;;
-R|--release) shift; chkarg $1 ; VER="$1" ; shift ;;
-v|--video) shift; chkarg $1 ; video="$1" ; shift ;;
-x|--xen) XEN=xen ; shift ;;
-V|--virtio) vflag=1 ; shift ;;
-S|--sound) aflag=1 ; shift ;;
-l|--sdl) sflag=1 ; shift ;;
-L|--live) lflag=1 ; shift ;;
-t|--try) tflag=1 ; shift ;;
-d|--defaults) syntax -d ;;
-h|--help) syntax ;;
--) shift ; chkopt $1 ; vm=$1 ; shift ;;
esac
done
HV=${XEN:-${DEF_HYPERVISOR}}
"$XEN" ] && hyp=${HV}///system
"$HYP" ] && hyp=${HV}${HYP}
hyp=${hyp:-$DEF_CONNECT}
host=${host:-$HOSTNAME}
ram=${ram:-$DEF_RAM}
arch=${arch/i[456]/i3} ; arch=${arch/x86_/amd}
arch=${arch:-$DEF_ARCH}
ver=${os}_ver ; ver=${!ver}
VER=${VER:-$ver}
REL=${os}_rel ; REL=${!REL}
MAC=${HV}_mac ; MAC=${!MAC}
"$host" == "$HOSTNAME" ] || { rflag=1 ; iflag=1 ; SSH="ssh root@$host" ; }
if $uflag -ge 3 ] ; then
Error "options --url and --iso are mutually exclusive."
elif $uflag -ge 2 ] ; then
geturl $os
elif $uflag -ge 1 ] ; then
"$rflag" ] && Error "remote install from a local iso is unsupported."
-f "$iso" ] && iso=" --cdrom=$iso" || Error "iso image $os not found."
elif $uflag -ge 0 ] ; then
Error "No OS or iso image specified."
fi
# ~~~
# OS and version
"$os" ] && OSDESC=" ($os $VER)"
desc="$vm$OSDESC - vm guest on host $host"
# determine os variant from os name if option --os not given
"$ostype" ] || ostype=$os$VER
"${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$os$VER
"${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$(echo $os${OSTYPES##*$os} | sed 's| .*||')
"${OSTYPES%$ostype*}" == "$OSTYPES" -a $vflag -gt 0 ] && ostype=virtio26
"${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$DEF_KERN
"ostype" ] || ostype=generic
arch=${arch/i3/i6} ; arch=${arch/amd/x86_}
# ~~~
# get size of vm
vmsize=${vmsize:-$DEF_VMSIZE}
# get destination path,
IMGPATH=${IMGPATH:-/var/lib/libvirt/images}
imgpath=${imgpath:-$IMGPATH}
if "$rflag" ] ; then
DISKOPTS=" --disk pool=default,size=$vmsize"
else
# check if there is enough space to store image locally.
hyp=$DEF_CONNECT
-d $imgpath ] || Error "Destination directory $imgpath doesn't exist."
$(($vmsize + 1)) -gt $(df -Phl $imgpath | awk '/G/ { sub(/G/,"", $4) ; print $4 }') ] && Error "Not enough space available on $imgpath"
imgname=${imgpath}/${vm}.img
if $lflag -ge 1 ] ; then
DISKOPTS=" --nodisk"
$VIRTINST_VER -gt 5003 ] && BOOTOPTS=" --boot=cdrom"
else
DISKOPTS=" --disk path=${imgname},size=$vmsize"
fi
fi
# ~~~
# networking
gw=${GATEWAY:-$GW}
# which networking method to use
if $bflag -eq 1 -o "$DEF_NETWORK" == "bridge" ] ; then
br=${br:-$DEF_BRIDGE}
nic=${nic:-$DEF_NIC}
# create bridge on localhost if needed
if "$rflag" ] ; then
if $tflag -eq 0 ] ; then
$SSH brctl show | grep -q "^$br ]" || Error "bridge $br not present on host $host"
fi
else
if "x$CREATEBRIDGE" == "x1" -a $tflag -eq 0 ] ; then
net=$(ifconfig $nic | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
brctl show | grep -q "^$br ]" && echo "bridge $br already set" || createBridge $br $nic $net
fi
fi
NETOPTS=" --network bridge=$br"
else
# start virtual network (NAT) if needed
if "x$STARTVIRBR" == "x1" ] ; then
virsh -c $hyp net-list | grep -q 'active' || virsh -c $hyp net-start default
NETOPTS=" --network network=default"
fi
fi
case $os in
openbsd) NETOPTS="$NETOPTS,model=e1000" ;;
netbsd) NETOPTS="$NETOPTS,model=ne2k_pci" ; ACPI=" --noacpi" ; ostype=openbsd4 ;;
dflybsd) NETOPTS="$NETOPTS,model=e1000" ; ostype=freebsd7 ;;
opensuse) ostype=sles11 ;;
esac
"$ostype" ] && ostype=" --os-variant=$ostype"
# get MAC address from option -m or /etc/ethers.
"$mac" ] || mac=`$SSH grep $vm /etc/ethers 2>/dev/null | awk '{print $1}'`
"$mac" ] && chkMAC $mac
"$mac" ] && NETOPTS="$NETOPTS,mac=$mac"
# ~~~
# display and graphic adapter
$sflag -eq 1 ] && DISPLAYOPTS=" --sdl"
"$video" ] || video=$DEF_VIDEO
$aflag -ge 1 ] && audio=" --soundhw=$DEF_AUDIO"
# ~~~
if $tflag -ge 1 ] ; then
printf "
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description=\"$desc\"${ostype}${url}${iso}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
" | sed 's|--|
--|g'
else
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description="$desc"${ostype}${url}${iso}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
fi
What is vm-create
vm-create is a script which enables the installation of operating systems (directly from the Internet or from iso images saved locally) in kvm or xen virtual machines - although it’s totally untested with xen since I’m using kvm. Installation can be done on a local or remote hypervisor.
Requirements
The script uses virt-install and requires the packages virt-manager, virt-viewer and kvm (which provides qemu-kvm) to be installed. It has been originally written for virt-manager version 0.8.5.49-1 from openSUSE:Virtualization repo: [noparse]http://download.opensuse.org/repositories/Virtualization/openSUSE_11.3[/noparse], which provides virt-install 0.500.4, although I tried to make it compatible with version 0.500.3 shipped with Ubuntu and version 0.500.5 included in virt-manager 0.8.6-3 as on ArchLinux. Under openSUSE, virt-install is included in virt-manager, while in other distros such as Ubuntu, it is a separate package. To connect to the hypervisor from a machine running ArchLinux and perform remote installations from there you need to install netcat-openbsd on the openSUSE server and create the following symlink:
# ln -s nc /usr/bin/nc.openbsd
Installing OS in local vms from the Internet
There are many options but you should be able to create a vm and install an OS using a pretty short command with the default options. So the following command will install a 32bit version of the latest stable debian (lenny) directly from a debian mirror in a 10 GB virtual machine stored in /misc/vm/desiree.img on your local computer - desiree beeing the name of the guest.
# vm-create -u debian desiree
Mainstream Linux distros, as well as FreeBSD, NetBSD and openBSD urls, are already included in the script. You can add others by defining new variables in the form os_url or os_iso (and post the urls in that thread afterwards). The installation of Windows guests is not covered in this tutorial (and will never be).
The following commands will install the specified OS in virtual machines (whose names are of course just examples) with default options:
# vm-create -u archlinux archimede
# vm-create -u fedora felicita
# vm-create -u centos cecilia
# vm-create -u mandriva marcel
# vm-create -u opensuse othello
# vm-create -u opensuseM6 oscar
# vm-create -u ubuntu ubu
# vm-create -u freebsd fredo
# vm-create -u netbsd nestor
# vm-create -u openbsd oprah
# vm-create -u dflybsd daffy
Installing OS guest on a remote host
The installation of a virtual machine on a remote host is accomplished by connecting to the remote hypervisor through ssh. You need a ssh root account on that computer. It is advisable to use ssh keys to avoid being prompted to enter your password for each command - the installation might even fail if you aren’t given the opportunity to input your password.
While installing a guest OS on a remote host, a mini or net iso will be downloaded first to a directory on the local machine, and a pool containing that directory wil be created on the host. Thus in some cases where a direct network install is possible (when an os_url variable is defined in the script), remote install (which uses the os_iso variable) might be different from local install.
The following example installs openSUSE 11.4 Millestone 6 in a guest called *oscar *on a remote host:
# vm-create -c -u opensuseM6 oscar
Installing from iso image
If guest and host are on the same machine, you can install from a locally stored iso image with the option -i (–iso) followed by the path of the iso file. Of course this could also be an nfs mounted filesystem. It is not possible in virt-install to install a guest on host B from an iso image located on host A. It would be do-able in the script but wouldn’t it be simpler to upload the iso on the remote host and install from there?
The following command boots openSUSE 11.4 Millestone 6 live CD from an iso image in the example path into a local vm guest called oprah:
# vm-create -i /data/Linux/openSUSE/11.4/iso/openSUSE-GNOME-LiveCD-Build1034-i686.iso oprah
Booting live CD only
To boot a live CD into a vm without actually creating a virtual disk, add option -L to the example above, giving:
# vm-create -i /data/Linux/openSUSE/11.4/iso/openSUSE-GNOME-LiveCD-Build1034-i686.iso -L oprah
This will create a diskless virtual machine which doesn’t use any disk space on the host.
Display: VNC or SDL
The default display is VNC, which allows remote usage of the virtual machine. If the virtual machine is to be seen on the local computer only, you can install SDL rather than VNC display with the option -l (or --sdl) , as shown in the following example:
# vm-create -u opensuseM6 --sdl oscar
Network: NAT or bridge
The default is to use NAT for network connection. The virtual network (default) will be started if needed on the local or even on a remote hypervisor. You can install directly using bridge with the option -b (or --bridge) followed by the bridge name (usually br0). If the bridge doesn’t exist, the script will attempt to create one on the network interface specified in DEF_NIC (default eth0). You can specify another network interface if needed with the option -e (or --eth).
The following example creates a vm called archimede with a 8GB disk and network bridge br1 on eth1, and installs archlinux:
# vm-create -s 8 -u archlinux -b br1 -e eth1 archimede
A bridge can only be created on the local hypervisor. If if you want to install a virtual machine on a remote host using bridge, you have to create the bridge first on the remote machine -for example by calling the vm-bridge](http://forums.opensuse.org/english/other-forums/development/programming-scripting/453961-vm-bridge-convert-virtual-machines-nat-bridge-bridge-nat.html#post2288556) script under the name nat2bridge or by creating the bridge permanently. If the bridge doesn’t exist, the script will issue an error message and exit.
MAC address
You can specify the MAC address you want to assign to the virtual network interface with the optin -m (–mac). It can be useful for various reasons, such as reinstalling a guest which obtains a fixed IP from a DHCP server. If an entry for this guest already exists in /etc/ethers on the hosts, the MAC address defined in this file will be used. MAC addresses should be in Xen (starting with 00:16:3e) or Qemu (starting with 52:54:00) valid ranges. Otherwise vm-create will display an error message an abort.
OS variant
The os-variant is determined by the OS name and version or sles11 for opensuse, otherwise the value of DEF_KERN, or, if not defined, generic. For Linux, you can enforce the use of the virtio driver with the option -v (–virtio). This only makes sense for distros whose variant is not already supported in virt-install, such as archlinux. If you wish to install archlinux with the virtio driver, you should rebuild the ramdisk with (some of) the virtio modules (virtio itself is built in the i686 kernel). Read this page for more info about how to install archlinux in kvm with the virtio driver: https://wiki.archlinux.org/index.php/KVM#Preparing_an_.28arch.29linux_guest.
Printing the command before executing
You can see how the complete command looks without running it with the -t (or --try) option. For example, without further options, the following command
# vm-create -t -u fedora felicita
produces the following output:
virt-install
--connect=qemu:///system
--ram=512
--arch=i686
--vcpus=1
--video=vga
--description="felicita (fedora 14) - vm guest on host bareil"
--os-variant=fedora14
--location=ftp://ftp.osuosl.org/pub/fedora/linux/releases/14/Fedora/i386/os/
--boot=cdrom,hd,network
--disk path=/misc/vm/felicita.img,size=10
--network network=default
--vnc
--vnclisten=0.0.0.0
--name=felicita
It’s a good idea to print the command with the option -t before executing it.
As an another example, the command below proposes to install openSUSE 11.4 M6 with default settings + sound support from an iso image stored locally in the current directory into a vitual machine called oprah:
# vm-create -t -S -i /data/Linux/openSUSE/11.4/iso/openSUSE-GNOME-LiveCD-Build1034-i686.iso oprah
The option -t shows the command to be executed:
virt-install
--connect=qemu:///system
--ram=512
--arch=i686
--vcpus=1
--video=vga
--soundhw=default
--description="oprah - vm guest on host bareil"
--os-variant=generic26
--cdrom=/data/Linux/openSUSE/11.4/iso/openSUSE-GNOME-LiveCD-Build1034-i686.iso
--boot=cdrom,hd,network
--disk path=/misc/vm/oprah.img,size=10
--network network=default
--vnc
--vnclisten=0.0.0.0
--name=oprah
Since libvirt doesn’t recognize openSUSE 11.4 as a valid os variant at this time, vm-create selected “generic26” kernel instead. However we know that openSUSE’s kernel supports the virtio driver, an I/O an network driver (libvirt: Wiki: Virtio) optimized for kvm guests. So we can add the option -V (–virtio) to our command and take a look at it first:
**# vm-create -t -S -V -i /data/Linux/openSUSE/11.4/iso/openSUSE-GNOME-LiveCD-Build1034-i686.iso oprah **
virt-install
--connect=qemu:///system
--ram=512
--arch=i686
--vcpus=1
--video=vga
--soundhw=default
--description="oprah - vm guest on host bareil"
--os-variant=virtio26
--cdrom=/data/Linux/openSUSE/11.4/iso/openSUSE-GNOME-LiveCD-Build1034-i686.iso
--boot=cdrom,hd,network
--disk path=/misc/vm/oprah.img,size=10
--network network=default
--vnc
--vnclisten=0.0.0.0
--name=oprah
When we’re happy with that command, we can execute it after removing the option -t.
Checking the default settings
To see the current defaults, use the option -d (–defaults)
vm-create -d will print:
DEF_HYPERVISOR qemu
DEF_RAM 512
DEF_CPUS 1
DEF_ARCH i386
DEF_KERN generic26
DEF_VIDEO vga
DEF_AUDIO default
DEF_VMSIZE 10
DEF_BRIDGE br0
DEF_NIC eth0
DEF_NAT virbr0
DEF_NETWORK nat
DEF_NETMASK 0xffffff00
Viewing available options
To see the available options, use the option -h (–help)
I strongly encourage you to read the virt-install and virsh manpages before using this script.
bugs
to create a network pool livirtd 0.8.7 expects the following syntax:
pool-create-as <name> netfs <source host> <source path> -- --** --** <target>
while libvirtd 0.8.0 and 0.8.3 requires:
pool-create-as <name> netfs <source host> <source path> -- -- <target>
I don’t know what the third optional argument (–) is supposed to be. This is not documented and doesn’t show up with --print-xml. I suspect a bug in libvirt 0.8.7 (?). vm-create handles the situation by checking libvirt version. However you might encounter a syntax error if using versions other than 0.8.0, 0.8.3 and 0.8.7, because other versions may have changed this behavior.
remote install tested so far with kvm
Remote install was conducted on openSUSE server running libvirtd 0.8.7 (from Virtualization repo) from different client machines:
- openSUSE (virt-install 0.500.4, libvirtd 0.8.7)
- Ubuntu (virt-install 0.500.3, libvirtd 0.8.3)
- Fedora (virt-install 0.500.4, libvirtd 0.8.3)
- ArchLinux (virt-install 0.500.5, libvirt 0.8.7)
- Mandriva (virt-install 0.500.3, libvirt 0.8.0)
boot install reboot
_____________________________________________________________________________________________
Debian netinstall (debian-508-i386-netinst.iso) : OK OK OK
Fedora netinstall (Fedora-14-i386-netinst.iso) : OK OK Failed
Centos netinstall (Centos-5.5-i386-netinstall.iso) : OK OK OK
Archlinux netinstall (archlinux-2010.05-netinstall-i686.iso) : OK OK OK**1**
openSUSE netinstall (openSUSE-NET-Build1034-i586.iso) : OK OK OK
Mandriva netinstall (2010.2 boot.iso) : OK OK OK
Ubuntu netinstall (mini.iso) : OK OK OK/Failed**2**
FreeBSD netinstall (FreeBSD-8.2-RC3-i386-bootonly.iso) : OK OK OK
NetBSD cd install (i386cd-5.1.iso) : OK Failed**3** Failed
OpenBSD netinstall (cd48.iso) : OK OK OK**5**
DragonFly cd install (dfly-i386-2.8.2_REL.iso) : OK OK OK
_____________________________________________________________________________________________
local install tested so far with kvm
boot install reboot
_____________________________________________________________________________________________
openSUSE 11.3: (openSUSE-11.3-DVD-i586.iso) : OK OK OK
openSUSE 11.4 M6: (openSUSE-GNOME-LiveCD-Build1034-i686.iso) : OK OK OK
Fedora 14: (Fedora-14-i686-Live-Desktop.iso) : OK OK OK
Ubuntu 10.10 (ubuntu-10.10-desktop-i386.iso) : OK OK Failed**2**
NetBSD 5.1 (i386cd-5.1.iso) : OK OK**4** OK
OpenBSD 4.8 (install48.iso) : OK OK OK**5**
_____________________________________________________________________________________________
Install “OK” & reboot “Failed” means that the setup appears to complete successfully, however the system failed to boot afterwards.
- If using the virtio driver, you should reinstall Grub as described here https://wiki.archlinux.org/index.php/KVM#Preparing_an_.28arch.29linux_guest or it won’t reboot.
- Fail to boot on Fedora 14 host with an “out of range pointer” message (with Grub2 in MBR or in partition bootsector)
- Failed to extract all the binary sets
- Finally OK but took very long to extract big archives. Remote install would probably have worked if I had waited long enough.
- Disable mpbios at first reboot:
boot> bsd -c
...
UKC> disable mpbios
352 mpbios disabled
UKC> quit
...
and later permanently:
# config -ef /bsd:
UKC> disable mpbios
352 mpbios disabled
UKC> quit
Saving modified kernel
vms created on system with different **virt-install **versions might need some changes before you can import them. For example to use vms created on openSUSE or Fedora in Ubuntu or Mandriva, you have to replace
<type arch='i686' machine='pc-0.**13**'>hvm</type>
with
<type arch='i686' machine='pc-0.**12**'>hvm</type>
in the xml definition files.
Oh ! Oh ! I am eager to test it out.
Thanks please_try_again and I really hope it’ll work well for me.
I’ll test it on xen and give you feedback later.
To make it even simpler (well … in some way), you can create the following function in your environment:
function newvm {
unset C N guest host size ram bridge eth arch os
if "x$1" == "x-n" ] ; then
N=" -t"
shift
fi
guest=$1 ; shift
host=$1 ; shift
size=${VM_SIZE:-10}
ram=${VM_RAM:-512}
bridge=${VM_BRIDGE:-br0}
eth=${VM_ETH:-eth0}
arch=${VM_ARCH:-i386}
OS=$(lsb_release -s -i | tr ":upper:]" ":lower:]" | sed 's| *linux||;s|suse|open&|;s|n/a|archlinux|')
os=${VM_OS:-$OS}
"$os" == "archlinux" ] && virtio=" -V"
"$host" == "" ] || C=" -c $host"
su -p -c "vm-create$N$C -a $arch -r $ram -s $size -b $bridge -e $eth$virtio -u $os $guest"
}
The function calls the script with some default values that can be changed in the environment variables VM_SIZE, VM_RAM, VM_BRIDGE, VM_ETH, VM_ARCH and VM_OS. And such a function can be executed by users since it calls the script with “su”, while the script has to be executed by root (only root can create bridges and connect to qemu:///system or xen:///system - at least under openSUSE AFAIK.)
Thus with this function in your environment (write it in a ~/.functions file that you’ll source from your ~/.profile or ~/.bash_profile, just like aliases), if for example you set the following environment variables:
export VM_SIZE=20
export VM_RAM=1024
export VM_OS=opensuse
you’ll just have to run:
newvm spock
To create a vm (called spock) on a 20GB virtual disk with 1GB RAM and start an opensuse 11.3 net install in it.
- Use the -n option before the machine name to display the command rather than execute it :
newvm -n spock
virt-install
--connect=qemu:///system
--ram=1024
--arch=i586
--vcpus=1
--video=vga
--description="spock (opensuse 11.3) - vm guest on host uhura"
--os-variant=sles11
--cdrom=/misc/iso/openSUSE-11.3-NET-i586.iso
--boot=cdrom,hd,network
--disk path=/misc/vm/spock.img,size=20
--network bridge=br0
--vnc
--vnclisten=0.0.0.0
--name=spock
- add a hostname after the vm name to install it on a remote host rather than localhost:
newvm spock risa
The function uses bridge as default (unlike the script and virt-install).
Such a function only makes sense if you create a lot of virtual machines.
- Maybe I should use virtio26 rather than sles11 as default for openSUSE. I don’t know.
Similarly, to install from an openSUSE client to a Fedora server, you have to symlink nc to netcat on the Fedora machine. So netcat seems to be the issue while connecting two different Linux distros through VNC. The program needs to have the same name on the server and on the client trying to connect.
vm-create version 2.0
(Please see release notes in the next post)
#! /bin/bash
#: Title : vm-create
#: Date Created: Sat Jan 29 01:54:07 PST 2011
#: Last Edit : Wed Feb 23 06:08:08 PST 2011
#: Author : please_try_again
#: Version : 2.0
#: Description : install OS from the Internet or local iso in a kvm vm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prg=$(basename $0)
# use the popup library if found
which popup &>/dev/null && source $(which popup)
# use popup functions if available
function Error { declare -F | grep -q error || exec echo "Error: $*" ; error "$*" ;}
function Warn { declare -F | grep -q warn && warn "$*" || echo "Warning: $*" ;}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which virt-install &> /dev/null || Error "virt-install not installed"
[ -r /etc/vm-create.cfg ] && source /etc/vm-create.cfg || Error "/etc/vm-create.cfg not found"
[ -r ~/.vm-create.cfg ] && source ~/.vm-create.cfg
[ "x$(ps ax | grep libvirtd | awk '!/grep/ { print $1 }')" == "x" ] && Error "libvirtd is not running"
VIRTINST_VER=$(virt-install --version | sed 's|^0||;s|\.||g')
LIVIRT_VER=$(libvirtd --version | sed 's|[^0-9]*\([0-9]\)|\1|;s|\.||g;s|^0||')
# recognized OS types to this day.
OSTYPES="debianetch debianlenny debiansqueeze \
fedora5 fedora6 fedora7 fedora8 fedora9 fedora10 fedora11 fedora12 fedora13 \
generic24 generic26 \
virtio26 \
mandriva2009 mandriva2010 \
mes5 mes5.1 \
rhel2.1 rhel3 rhel4 rhel5 rhel5.4 rhel6 \
sles10 sles11 \
ubuntuhardy ubuntuintrepid ubuntujaunty ubuntukarmic \
generic \
msdos \
netware4 netware5 netware6 \
opensolaris solaris10 solaris9 \
freebsd6 freebsd7 \
openbsd4 \
vista win2k win2k3 win2k8 win7 winxp winxp64"
[ $VIRTINST_VER -lt 5003 ] && Error "virt-install 0.500.3 or newer required"
[ $VIRTINST_VER -ge 5004 ] && { OSTYPES="$OSTYPES fedora14 ubuntulucid freebsd8" ; BOOTOPTS=" --boot=cdrom,hd,network";}
[ $VIRTINST_VER -ge 5005 ] && OSTYPES="$OSTYPES ubuntumaverick"
[ $LIVIRT_VER -ge 87 ] && Y="-- "
DEF_CONNECT=${VIRSH_DEFAULT_CONNECT_URI:-${DEF_HYPERVISOR}://$DEF_HOST/system}
DISPLAYOPTS=" --vnc --vnclisten=0.0.0.0"
# valid xen and qemu MAC addresses
qemu_mac="52:54:00:"
xen_mac="00:16:3e:"
# valid video adapters
video_models=":vga:vmvga:cirrus:xen:"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function chknum {
N=$(echo $1 | tr -d "[:alpha:]")
[ "x$N" == "x$1" ] || Error "invalid numeric argument: $1"
}
function chkMAC {
Mac=$(echo ${1:0:9} | tr "[:upper:]" "[:lower:]")
MAC=${HV}_mac ; MAC=${!MAC}
[ "$Mac" == "$MAC" ] || Error "invalid $HV MAC address: $1"
[ "$(echo ${1:9} | sed 's|[^:]*||g')" == "::" ] || Error "invalid $HV MAC address: $1"
a=$(echo ${1:9} | sed 's|:||g;s|[^0-9a-fA-F]*||g')
[ ${#1} -eq 17 -a ${#a} -eq 6 ] || Error "invalid $HV MAC address: $1"
}
function chkarg { [ "${1:0:1}" == "-" ] && Error "invalid argument: $1" ;}
function chkopt { [ "x$1" == "x" ] && Error "you should provide a vm name" ;}
function syntax {
cat << EOFSYNTAX
usage:
$prg vm name
options:
-c --connect <host> : remote host where to create the vm
-r --ram <ram in MB> : amount of ram (default 512MB)
-a --arch <i386|amd64> : architecture (i386 or amd64)
-o --os <os variant> : os variant (example: fedora14, mandriva2010)
-u --url <os> : os (fedora, debian, ubuntu, opensuse, mandriva)
-i --iso <img.iso> : iso image
-p --path <directory> : where to store vm images
-s --size <size> : size of virtual machine in GB
-V --virtio : same as -o virtio26
-v --video : video device: cirrus, vga* or vmvga (for kvm)
-R --release : OS version to install (other than default)
-S --sound : enable sound device (ac97)
-l --sdl : use sdl display rather than vnc
-L --live : boot live CD
-b --bridge <bridge> : use network bridge (otherwise use DEF_NETWORK if defined or 'nat')
-e --eth <nic> : network interface to use for bridge (otherwise use DEF_NIC if defined or eth0)
-x --xen : use Xen hypervisor rather than kvm
-t --try : just print but not execute the command
-h --help : show this help
-d --disks : number of virtual hard disks
recognized OS variants :
`echo $OSTYPES | fmt`
available guest systems :
$(awk -F "=" '/^[a-zA-Z0-9]*_url=|^[a-zA-Z0-9]*_iso=/ { sub(/_.*/,"",$1); print $1 }' /etc/vm-create.cfg | sort -u | tr "
" " ")
EOFSYNTAX
exit
}
function createBridge {
[ "x$gw" == "x" ] && Error "no gateway defined"
ping -q -c 1 -W 2 $gw > /dev/null || Error "gateway $gw is unreachable"
echo " - creating bridge $1"
brctl addbr $1
ifconfig $2 0.0.0.0 promisc
brctl addif $1 $2
ifconfig $1 inet $3 netmask $DEF_NETMASK
brctl stp $br on
route del default 2>/dev/null
route add default gw $gw 2>/dev/null
}
function importPool {
virsh -c $hyp pool-dumpxml $1 2>/dev/null | grep -q $2 && {
virsh -c $hyp pool-info $1 | grep -q running || virsh -c $hyp pool-start $1
virsh -c $hyp pool-refresh $1
return
}
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-destroy $1 2>/dev/null
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-undefine $1 2>/dev/null
$SSH mkdir -m 600 $POOLPATH 2>/dev/null
virsh -c $hyp pool-create-as $1 netfs $2 $ISOPATH -- -- $Y$POOLPATH
}
function getarch {
case $1 in
amd64)
case $os in
fedora|mandriva|archlinux|opensuse) echo x86_64 ;;
*) echo $1 ;;
esac
;;
i386)
case $os in
mandriva|opensuse*) echo i586 ;;
archlinux) echo i686 ;;
gentoo) echo x86 ;;
*) echo $1 ;;
esac
;;
esac
}
function getiso {
[ -d $ISOPATH ] && cd $ISOPATH || Error "$ISOPATH doesn't exist"
IMG=$1 ; shift ; URL=$1
ISO=$(basename $IMG .bz2) ; ISO=$(basename $ISO .tgz)
if [ $tflag -eq 0 ] ; then
if [ "$URL" ] ; then
[ -f ./$ISO ] || [ -f ./$IMG ] || wget -v $URL/$IMG
[ -f ./$ISO ] || bunzip2 -v $IMG
else
[ -f $IMG ] || Error "File not found: $IMG"
file $IMG | grep -q bootable || Error "$IMG is not a bootable iso image"
fi
fi
DIR=$(dirname $IMG)
[ "$DIR" == "." ] && DIR=$(pwd)
if [ "$rflag" ] ; then
[ "$DIR" == "$ISOPATH" ] || Error "iso img $ISO not in shared pool $ISOPATH"
[ $tflag -eq 0 ] && importPool $POOLNAME $HOSTNAME
url=" --disk vol=$POOLNAME/$ISO,device=cdrom"
else
url=" --cdrom=$DIR/$ISO"
fi
cd - >/dev/null
}
# find out if we need to download a netinstall iso image
function geturl {
ARCH=$(getarch $arch)
URL=${1//ARCH/$ARCH} ; shift
URL=${URL//VER/$1}
if [ "$iflag" ] ; then
img=$(links -dump $URL | awk '/dfly|netinst|mini|NET|boot|cd[-0-9]/&&/iso$|iso.bz2$/&&/'$ARCH'/ { sub(/.*[/\] ]/,"", $0) ; print $0 }' | sort -u | tail -1)
getiso $(basename $img) $URL
else
url=" --location=$URL"
fi
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uflag=0 ; vflag=0 ; bflag=0 ; sflag=0 ; dflag=0 ; tflag=0 ; lflag=0 ; aflag=0
url=""
HV=$DEF_HYPERVISOR
hds=1
# evaluate arguments
args=`getopt -q -u -o c:r:a:m:o:u:i:p:s:b:e:R:v:d:xSVlLht -l connect:,ram:,arch:,mac:,os:,url:,iso:,path:,size:,bridge:,eth:,release:,video:,disks:,xen,virtio,sdl,sound,live,help,try -- "$@"`
set -- $args
for i; do
case "$i" in
-c|--connect) shift; chkarg $1 ; rhost="$1" ; shift ;;
-r|--ram) shift; chkarg $1 ; ram="$1" ; shift ;;
-a|--arch) shift; chkarg $1 ; arch="$1" ; shift ;;
-m|--mac) shift; chkarg $1 ; mac="$1" ; shift ;;
-o|--os) shift; chkarg $1 ; ostype="$1" ; shift ;;
-i|--iso) shift; chkarg $1 ; iso="$1" ; uflag=$(($uflag | 1)) ; shift ;;
-u|--url) shift; chkarg $1 ; os="$1" ; uflag=$(($uflag | 2)) ; shift ;;
-p|--path) shift; chkarg $1 ; imgpath="$1" ; shift ;;
-s|--size) shift; chkarg $1 ; vmsize="$1" ; shift ;;
-b|--bridge) shift; chkarg $1 ; br="$1" ; bflag=1 ; shift ;;
-e|--eth) shift; chkarg $1 ; nic="$1" ; shift ;;
-R|--release) shift; chkarg $1 ; ver="$1" ; shift ;;
-v|--video) shift; chkarg $1 ; video="$1" ; shift ;;
-d|--disks) shift; chkarg $1 ; hds="$1" ; shift ;;
-x|--xen) XEN=xen ; shift ;;
-V|--virtio) vflag=1 ; shift ;;
-S|--sound) aflag=1 ; shift ;;
-l|--sdl) sflag=1 ; shift ;;
-L|--live) lflag=1 ; shift ;;
-t|--try) tflag=1 ; shift ;;
-h|--help) syntax ;;
--) shift ; chkopt $1 ; vm=$1 ; shift ;;
esac
done
if [ $uflag -ge 3 ] ; then
Error "options --url and --iso are mutually exclusive."
elif [ $uflag -le 0 ] ; then
Error "No OS or iso image specified."
fi
# check remote host
[ "$rhost" ] && hyp=$HV+ssh://$rhost/system || { [ "$HV" == "xen" ] && hyp=$HV:///system || hyp=${DEF_CONNECT:-$HV:///system} ; }
DEF_RHOST=$(echo ${DEF_CONNECT##*://} | sed 's|/system||')
host=${rhost:-$DEF_RHOST} ; host=${host:-$HOSTNAME}
[ "$host" == "$HOSTNAME" ] || {
ping -q -c 1 -W 2 $host &> /dev/null || Error "host $host is unreachable"
rflag=1 ; iflag=1 ; SSH="ssh root@$host"
}
# check virtual machine
virsh -c $hyp dominfo $vm &> /dev/null && Error "Virtual machine $vm already exists."
# check ram
ram=${ram:-$DEF_RAM}
chknum $ram ; [ $ram -ge $MIN_RAM ] || Error "not enough RAM allocated: $ram MB"
# check architecture
arch=${arch:-$DEF_ARCH}
arch=$(echo $arch | sed 's|i[456]|i3|;s|x86_|amd|')
[ "$arch" == "i386" -o "$arch" == "amd64" ] || Error "unsupported architecture: $arch"
# check OS version
if [ $uflag -ge 2 ] ; then
url=${os}_url ; url=${!url}
[ "$url" ] || { url=${os}_iso ; url=${!url} ; iflag=1 ;}
[ "$rflag" ] && { url=${os}_iso ; url=${!url} ; iflag=1 ;}
VER=${os}_ver ; VER=${!VER} ; ver=${ver:-$VER}
which links &>/dev/null || Error "links not found. Please install the links package first."
[ "$url" ] && geturl $url $ver || Error "invalid OS: $os"
# check iso image
elif [ $uflag -ge 1 ] ; then
getiso $iso
fi
# check size of vm
vmsize=${vmsize:-$DEF_VMSIZE}
chknum $vmsize && VMSIZE=$vmsize
# check video
[ "$video" ] || video=$DEF_VIDEO
[ "${video_models%%:$video:*}" == "$video_models" ] && Error "Invalid video device: $video"
# check destination path,
IMGPATH=${IMGPATH:-/var/lib/libvirt/images}
imgpath=${imgpath:-$IMGPATH}
[ -d $imgpath ] || Error "Destination directory $imgpath doesn't exist."
# check mac address
[ "$mac" ] || mac=`$SSH grep $vm /etc/ethers 2>/dev/null | awk '{print $1}'`
[ "$mac" ] && chkMAC $mac
# OS and version
[ "$ver" ] && osver=" $ver"
[ "$os" ] && OSDESC=" ($os$osver)"
desc="$vm$OSDESC - vm guest on host $host"
# check os variant
Ver=${ver%%.*}
[ "$ostype" ] || ostype=$os$Ver
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$os$VER
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$(echo $os${OSTYPES##*$os} | sed 's| .*||')
[ "${OSTYPES%$ostype*}" == "$OSTYPES" -a $vflag -gt 0 ] && ostype=virtio26
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$DEF_KERN
[ "ostype" ] || ostype=generic
# check number of disk
[ "$hds" == "1" ] || chknum $hds
[ $hds -gt 1 ] && VMSIZE=$(($vmsize * $hds))
i=0
while [ $i -lt $hds ] ; do
hd[$i]=${vm}_hd$i.img
let i++
done
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ "$rflag" ] ; then
virsh -c $hyp pool-info default | grep -q running || virsh -c $hyp pool-start default
poolAvailableSize=$(virsh -c $hyp pool-info default | awk '/Available:/&&/GB/ { s=int($2 * 1024) ; print s }')
[ $(( ($VMSIZE + 1) * 1024)) -gt $poolAvailableSize ] && Error "Not enough space available on default pool"
if [ $hds -gt 1 ] ; then
if [ $tflag -eq 0 ] ; then
for hd in ${hd[li]} ; do
[/li] echo " - creating raw volume $hd, please wait..."
virsh -c $hyp vol-create-as default $hd ${vmsize}G
done
fi
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk '{ printf " --disk vol=default/%s", $1}')
else
DISKOPTS=" --disk pool=default,size=$vmsize"
fi
else
# check if there is enough space to store image locally.
hyp=$DEF_CONNECT
[ $(( ($VMSIZE + 1) * 1024)) -gt $(df -Pl -B $((1024*1024)) $imgpath | awk 'END { print $4 }') ] && Error "Not enough space available on $imgpath"
if [ $lflag -ge 1 ] ; then
DISKOPTS=" --nodisk"
[ $VIRTINST_VER -gt 5003 ] && BOOTOPTS=" --boot=cdrom"
else
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk 'BEGIN {S='$vmsize' ; P="'"$imgpath"'"} ; {printf " --disk path=%s/%s,size=%s", P, $1, S}')
fi
fi
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# networking
gw=${GATEWAY:-$GW}
# which networking method to use
if [ $bflag -eq 1 -o "$DEF_NETWORK" == "bridge" ] ; then
br=${br:-$DEF_BRIDGE}
nic=${nic:-$DEF_NIC}
ifconfig $nic &> /dev/null || Error "invalid network device: $nic"
# create bridge on localhost if needed
if [ "$rflag" ] ; then
if [ $tflag -eq 0 ] ; then
$SSH brctl show | grep -q "^$br[ ]" || Error "bridge $br not present on host $host"
fi
else
if [ "x$CREATEBRIDGE" == "x1" -a $tflag -eq 0 ] ; then
net=$(ifconfig $nic | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
brctl show | grep -q "^$br[ ]" && echo "bridge $br already set" || createBridge $br $nic $net
fi
fi
NETOPTS=" --network bridge=$br"
else
# start virtual network (NAT) if needed
if [ "x$STARTVIRBR" == "x1" ] ; then
virsh -c $hyp net-list | grep -q 'active' || virsh -c $hyp net-start default
NETOPTS=" --network network=default"
fi
fi
[ "$mac" ] && NETOPTS="$NETOPTS,mac=$mac"
case $os in
openbsd) NETOPTS="$NETOPTS,model=e1000" ;;
netbsd) NETOPTS="$NETOPTS,model=ne2k_pci" ; ACPI=" --noacpi" ; ostype=openbsd4 ;;
dflybsd) NETOPTS="$NETOPTS,model=e1000" ; ostype=freebsd7 ;;
opensuse) ostype=virtio26 ;;
esac
[ "$ostype" ] && ostype=" --os-variant=$ostype"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# display
[ $sflag -eq 1 ] && DISPLAYOPTS=" --sdl"
[ $aflag -ge 1 ] && audio=" --soundhw=$DEF_AUDIO"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ $tflag -ge 1 ] ; then
printf "
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description=\"$desc\"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
" | sed 's|--|
--|g'
else
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description="$desc"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
fi
vm-create 2.0 includes several major changes:
- The script now uses a systemwide config file /etc/vm-create.cfg
(required) and optional user config file ~/.vm-create.cfg to save user preferences and urls for network installations. The urls are also better organized, as the iso filenames are not written in the script anymore but read whenever possible from the distro ftp or http mirrors. The filename is read from the text browser “links”. Therefore the links package has to be installed. This make the installation of newer versions easier.
To install another version as the default version, you can specify the release with the -R option. The following command installs openSUSE 11.4 RC1 in a virtual machine called ‘oprah’:
# vm-create -R 11.4-RC1 -u opensuse oprah
Withouth the -R option followed by the release, it would install openSUSE 11.3. Same goes for Ubuntu ‘natty’ alpha releases installed with the command:
# vm-create -R natty -u ubuntu
Since those alpha and beta releases are not defined in /etc/vm-create.cfg but parsed from FTP listing outputs, chances are that future versions will be installed in the same way withouth the need of changing the script or its config file. Let’s hope so!
- As a consequence the option -d
(–default) which displayed the preferences previously defined in the script has been removed. - the letter ‘d’ is now used for another option -d
(–disks) serving a new feature: the possibility of assigning several virtual disks to a virtual machine. The number of disks to use is given as argument of the option. This works for local and remote installs although in a different way. For local installation, several --disk path options are passed to virt-install, as in the example below:
# vm-create -t -s 8 -d 2 -b br0 -R 11.4-RC1 -u opensuse oprah
virt-install
--connect=qemu:///system
--ram=512
--arch=i386
--vcpus=1
--video=vga
--description="oprah (opensuse 11.4-RC1) - vm guest on host jadzia"
--os-variant=virtio26
--cdrom=/misc/iso/openSUSE-NET-Build1056-i586.iso
--boot=cdrom,hd,network
--disk path=/misc/vm/oprah_hd0.img,size=8
--disk path=/misc/vm/oprah_hd1.img,size=8
--network bridge=br0
--vnc
--vnclisten=0.0.0.0
--name=oprah
When installing remotely, the disk are first created in the default pool through a virsh connection to the remote hosts and passed to virt-install as --disk vol options. vm-create is not limited in the number of virtual disks you can add (although libvirt, kvm or xen might … I don’t know). In both local and remote installs, vm-create will add the sizes of all disks to create (more precisely multiply the desired size by the number of disks) and first check if there is enough space available on the local filesystem or remote pool. As you can only specify the size (in the -s or --size option) and the number of disks to crate (with -d or --disks), all the disks must have the same size. Using virtual disks of different size while creating a virtual machine is rarely needed if ever.
# vm-create -c bareil -t -s 8 -d 2 -b br0 -R 11.4-RC1 -u opensuse oprah
virt-install
--connect=qemu+ssh://bareil/system
--ram=512
--arch=i386
--vcpus=1
--video=vga
--description="oprah2 (opensuse 11.4-RC1) - vm guest on host bareil"
--os-variant=virtio26
--disk vol=install/openSUSE-NET-Build1056-i586.iso,device=cdrom
--boot=cdrom,hd,network
--disk vol=default/oprah2_hd0.img
--disk vol=default/oprah2_hd1.img
--network bridge=br0
--vnc
--vnclisten=0.0.0.0
--name=oprah
Notice in red the differences in the syntax between local and remote installs.
- Other changes in this version include a better error handling which tries to better catch syntax errors and invalid options entered by the user.
I used this version to install a raid1/LVM on 2 virtual hard disks for testing purpose and posted a quick howto here: http://forums.opensuse.org/english/get-technical-help-here/how-faq-forums/unreviewed-how-faq/454559-opensuse-11-4-raid1-lvm.html#post2294166
vm-create systemwide configuration file: /etc/vm-create.cfg
# system wide /etc/vm-create.cfg.
# variables in this file can be ovrewritten in ~/.vm-create.cfg
# DEFINE THE VARIABLES IN THIS SECTIONS TO MATCH YOUR SYSTEM
IMGPATH=/misc/vm # where to put the vm images.
ISOPATH=/misc/iso # where to save iso images
POOLNAME=install # pollname for remote install
POOLPATH=/var/lib/libvirt/images/install
# your gateway (unless set in the environment variable GATEWAY)
GW=192.168.101.1
# YOU MIGHT EDIT THE DEFAULTS BELOW
DEF_HYPERVISOR=qemu # qemu or xen
#DEF_HOST= # default to localhost
DEF_RAM=512
DEF_CPUS=1
DEF_ARCH=i386
DEF_KERN=generic26
DEF_VIDEO=vga # cirrus, vga or vmvga
DEF_AUDIO=default # AC97 if the hypervisor supports it, otherwise it will be ES1370.
DEF_VMSIZE=10 # default size of virtual machines (10GB)
# network defaults
DEF_BRIDGE=br0
DEF_NIC=eth0
DEF_NAT=virbr0
DEF_NETWORK=nat # nat or bridge
DEF_NETMASK=0xffffff00 # should be fine for a class C network
CREATEBRIDGE=1 # create bridge if needed
STARTVIRBR=1 # start virtual network (NAT) if needed
MIN_RAM=64 # minimal amount of RAM for a vm
# You might change distros default versions
opensuse_ver=11.3
centos_ver=5
fedora_ver=14
ubuntu_ver=maverick
mandriva_ver=2010.2
debian_ver=squeeze
freebsd_ver=8.2
openbsd_ver=4.8
netbsd_ver=5.1
dflybsd_ver=2.8.2
# You might add/change ditros urls.
MIRROR="ftp://ftp.osuosl.org"
# mirrors
debian_mirror=$MIRROR
debiancd_mirror=$MIRROR
archlinux_mirror="$MIRROR/pub/archlinux"
centos_mirror="$MIRROR/pub/centos"
fedora_mirror="$MIRROR/pub/fedora"
gentoo_mirror="$MIRROR/pub/gentoo"
ubuntu_mirror="$MIRROR/pub/ubuntu"
#opensuse_mirror="$MIRROR/pub/opensuse"
# official sites
freebsd_mirror="ftp://ftp.freebsd.org/pub/FreeBSD"
openbsd_mirror="ftp://ftp.openbsd.org/pub/OpenBSD"
netbsd_mirror="ftp://ftp.netbsd.org/pub/NetBSD"
dflybsd_mirror="ftp://ftp.dragonflybsd.org"
opensuse_mirror="http://download.opensuse.org"
mandriva_mirror="ftp://ftp.uwsg.indiana.edu"
#debian_mirror="ftp://ftp.debian.org"
#debiancd_mirror="htpp://cdimage.debian.org"
#archlinux_mirror="ftp://ftp.archlinux.org"
#fedora_mirror="http://download.fedoraproject.org/pub/fedora"
#gentoo_iso="http://distfiles.gentoo.org"
#ubuntu_mirror="http://ca.archive.ubuntu,com/ubuntu"
debian_url="$debian_mirror/debian/dists/VER/main/installer-ARCH/"
fedora_url="$fedora_mirror/linux/releases/VER/Fedora/ARCH/os/"
mandriva_url="$mandriva_mirror/linux/mandrake/official/VER/ARCH/"
ubuntu_url="$ubuntu_mirror/dists/VER/main/installer-ARCH/"
archlinux_iso="$archlinux_mirror/iso/latest"
centos_iso="$centos_mirror/VER/isos/ARCH"
debian_iso="$debiancd_mirror/debian-cd/current/ARCH/iso-cd"
fedora_iso="$fedora_mirror/linux/releases/VER/Fedora/ARCH/iso"
gentoo_iso="$gentoo_mirror/releases/ARCH/current-iso"
mandriva_iso="$mandriva_mirror/linux/mandrake/official/VER/ARCH/install/images"
opensuse_iso="$opensuse_mirror/distribution/VER/iso"
ubuntu_iso="$ubuntu_mirror/dists/VER/main/installer-ARCH/current/images/netboot"
freebsd_iso="$freebsd_mirror/releases/ARCH/ISO-IMAGES/VER"
openbsd_iso="$openbsd_mirror/VER/ARCH"
netbsd_iso="$netbsd_mirror/iso/VER"
dflybsd_iso="$dflybsd_mirror/iso-images"
vm-create version 2.1
There was a bug in the creation of 64bit virtual machines because some distros use amd64 and others x86_64 in the name of their install iso images. “amd64” was passed to virt-install instead of “x86_74”. This bug is fixed in this version. As before, you can give either amd64 or x86_64 as argument to the -a option in vm-create to create 64bit virtual machines.
#! /bin/bash
#: Title : vm-create
#: Date Created: Sat Jan 29 01:54:07 PST 2011
#: Last Edit : Tue Mar 1 20:01:38 PST 2011
#: Author : please_try_again
#: Version : 2.1
#: Description : install OS from the Internet or local iso in a kvm vm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prg=$(basename $0)
# use the popup library if found
which popup &>/dev/null && source $(which popup)
# use popup functions if available
function Error { declare -F | grep -q error || exec echo "Error: $*" ; error "$*" ;}
function Warn { declare -F | grep -q warn && warn "$*" || echo "Warning: $*" ;}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which virt-install &> /dev/null || Error "virt-install not installed"
[ -r /etc/vm-create.cfg ] && source /etc/vm-create.cfg || Error "/etc/vm-create.cfg not found"
[ -r ~/.vm-create.cfg ] && source ~/.vm-create.cfg
[ "x$(ps ax | grep libvirtd | awk '!/grep/ { print $1 }')" == "x" ] && Error "libvirtd is not running"
VIRTINST_VER=$(virt-install --version | sed 's|^0||;s|\.||g')
LIVIRT_VER=$(libvirtd --version | sed 's|[^0-9]*\([0-9]\)|\1|;s|\.||g;s|^0||')
# recognized OS types to this day.
OSTYPES="debianetch debianlenny debiansqueeze \
fedora5 fedora6 fedora7 fedora8 fedora9 fedora10 fedora11 fedora12 fedora13 \
generic24 generic26 \
virtio26 \
mandriva2009 mandriva2010 \
mes5 mes5.1 \
rhel2.1 rhel3 rhel4 rhel5 rhel5.4 rhel6 \
sles10 sles11 \
ubuntuhardy ubuntuintrepid ubuntujaunty ubuntukarmic \
generic \
msdos \
netware4 netware5 netware6 \
opensolaris solaris10 solaris9 \
freebsd6 freebsd7 \
openbsd4 \
vista win2k win2k3 win2k8 win7 winxp winxp64"
[ $VIRTINST_VER -lt 5003 ] && Error "virt-install 0.500.3 or newer required"
[ $VIRTINST_VER -ge 5004 ] && { OSTYPES="$OSTYPES fedora14 ubuntulucid freebsd8" ; BOOTOPTS=" --boot=cdrom,hd,network";}
[ $VIRTINST_VER -ge 5005 ] && OSTYPES="$OSTYPES ubuntumaverick"
[ $LIVIRT_VER -ge 87 ] && Y="-- "
DEF_CONNECT=${VIRSH_DEFAULT_CONNECT_URI:-${DEF_HYPERVISOR}://$DEF_HOST/system}
DISPLAYOPTS=" --vnc --vnclisten=0.0.0.0"
# valid xen and qemu MAC addresses
qemu_mac="52:54:00:"
xen_mac="00:16:3e:"
# valid video adapters
video_models=":vga:vmvga:cirrus:xen:"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function chknum {
N=$(echo $1 | tr -d "[:alpha:]")
[ "x$N" == "x$1" ] || Error "invalid numeric argument: $1"
}
function chkMAC {
Mac=$(echo ${1:0:9} | tr "[:upper:]" "[:lower:]")
MAC=${HV}_mac ; MAC=${!MAC}
[ "$Mac" == "$MAC" ] || Error "invalid $HV MAC address: $1"
[ "$(echo ${1:9} | sed 's|[^:]*||g')" == "::" ] || Error "invalid $HV MAC address: $1"
a=$(echo ${1:9} | sed 's|:||g;s|[^0-9a-fA-F]*||g')
[ ${#1} -eq 17 -a ${#a} -eq 6 ] || Error "invalid $HV MAC address: $1"
}
function chkarg { [ "${1:0:1}" == "-" ] && Error "invalid argument: $1" ;}
function chkopt { [ "x$1" == "x" ] && Error "you should provide a vm name" ;}
function syntax {
cat << EOFSYNTAX
usage:
$prg vm name
options:
-c --connect <host> : remote host where to create the vm
-r --ram <ram in MB> : amount of ram (default 512MB)
-a --arch <i386|amd64> : architecture (i386 or amd64)
-o --os <os variant> : os variant (example: fedora14, mandriva2010)
-u --url <os> : os (fedora, debian, ubuntu, opensuse, mandriva)
-i --iso <img.iso> : iso image
-p --path <directory> : where to store vm images
-s --size <size> : size of virtual machine in GB
-V --virtio : same as -o virtio26
-v --video : video device: cirrus, vga* or vmvga (for kvm)
-R --release : OS version to install (other than default)
-S --sound : enable sound device (ac97)
-l --sdl : use sdl display rather than vnc
-L --live : boot live CD
-b --bridge <bridge> : use network bridge (otherwise use DEF_NETWORK if defined or 'nat')
-e --eth <nic> : network interface to use for bridge (otherwise use DEF_NIC if defined or eth0)
-x --xen : use Xen hypervisor rather than kvm
-t --try : just print but not execute the command
-h --help : show this help
-d --disks : number of virtual hard disks
recognized OS variants :
`echo $OSTYPES | fmt`
available guest systems :
$(awk -F "=" '/^[a-zA-Z0-9]*_url=|^[a-zA-Z0-9]*_iso=/ { sub(/_.*/,"",$1); print $1 }' /etc/vm-create.cfg | sort -u | tr "
" " ")
EOFSYNTAX
exit
}
function createBridge {
[ "x$gw" == "x" ] && Error "no gateway defined"
ping -q -c 1 -W 2 $gw > /dev/null || Error "gateway $gw is unreachable"
echo " - creating bridge $1"
brctl addbr $1
ifconfig $2 0.0.0.0 promisc
brctl addif $1 $2
ifconfig $1 inet $3 netmask $DEF_NETMASK
brctl stp $br on
route del default 2>/dev/null
route add default gw $gw 2>/dev/null
}
function importPool {
virsh -c $hyp pool-dumpxml $1 2>/dev/null | grep -q $2 && {
virsh -c $hyp pool-info $1 | grep -q running || virsh -c $hyp pool-start $1
virsh -c $hyp pool-refresh $1
return
}
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-destroy $1 2>/dev/null
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-undefine $1 2>/dev/null
$SSH mkdir -m 600 $POOLPATH 2>/dev/null
virsh -c $hyp pool-create-as $1 netfs $2 $ISOPATH -- -- $Y$POOLPATH
}
function getarch {
case $1 in
x86_64)
case $os in
centos|debian|dflybsd|freebsd|gentoo|netbsd|openbsd|ubuntu) echo amd64 ;;
*) echo $1 ;;
esac
;;
i386)
case $os in
mandriva|opensuse*) echo i586 ;;
archlinux) echo i686 ;;
gentoo) echo x86 ;;
*) echo $1 ;;
esac
;;
esac
}
function getiso {
[ -d $ISOPATH ] && cd $ISOPATH || Error "$ISOPATH doesn't exist"
IMG=$1 ; shift ; URL=$1
ISO=$(basename $IMG .bz2) ; ISO=$(basename $ISO .tgz)
if [ $tflag -eq 0 ] ; then
if [ "$URL" ] ; then
[ -f ./$ISO ] || [ -f ./$IMG ] || wget -v $URL/$IMG
[ -f ./$ISO ] || bunzip2 -v $IMG
else
[ -f $IMG ] || Error "File not found: $IMG"
file $IMG | grep -q bootable || Error "$IMG is not a bootable iso image"
fi
fi
DIR=$(dirname $IMG)
[ "$DIR" == "." ] && DIR=$(pwd)
if [ "$rflag" ] ; then
[ "$DIR" == "$ISOPATH" ] || Error "iso img $ISO not in shared pool $ISOPATH"
[ $tflag -eq 0 ] && importPool $POOLNAME $HOSTNAME
url=" --disk vol=$POOLNAME/$ISO,device=cdrom"
else
url=" --cdrom=$DIR/$ISO"
fi
cd - >/dev/null
}
# find out if we need to download a netinstall iso image
function geturl {
ARCH=$(getarch $arch)
URL=${1//ARCH/$ARCH} ; shift
URL=${URL//VER/$1}
if [ "$iflag" ] ; then
img=$(links -dump $URL | awk '/dfly|netinst|mini|NET|boot|cd[-0-9]/&&/iso$|iso.bz2$/&&/'$ARCH'/ { sub(/.*[/\] ]/,"", $0) ; print $0 }' | sort -u | tail -1)
getiso $(basename $img) $URL
else
url=" --location=$URL"
fi
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uflag=0 ; vflag=0 ; bflag=0 ; sflag=0 ; dflag=0 ; tflag=0 ; lflag=0 ; aflag=0
url=""
HV=$DEF_HYPERVISOR
hds=1
# evaluate arguments
args=`getopt -q -u -o c:r:a:m:o:u:i:p:s:b:e:R:v:d:xSVlLht -l connect:,ram:,arch:,mac:,os:,url:,iso:,path:,size:,bridge:,eth:,release:,video:,disks:,xen,virtio,sdl,sound,live,help,try -- "$@"`
set -- $args
for i; do
case "$i" in
-c|--connect) shift; chkarg $1 ; rhost="$1" ; shift ;;
-r|--ram) shift; chkarg $1 ; ram="$1" ; shift ;;
-a|--arch) shift; chkarg $1 ; arch="$1" ; shift ;;
-m|--mac) shift; chkarg $1 ; mac="$1" ; shift ;;
-o|--os) shift; chkarg $1 ; ostype="$1" ; shift ;;
-i|--iso) shift; chkarg $1 ; iso="$1" ; uflag=$(($uflag | 1)) ; shift ;;
-u|--url) shift; chkarg $1 ; os="$1" ; uflag=$(($uflag | 2)) ; shift ;;
-p|--path) shift; chkarg $1 ; imgpath="$1" ; shift ;;
-s|--size) shift; chkarg $1 ; vmsize="$1" ; shift ;;
-b|--bridge) shift; chkarg $1 ; br="$1" ; bflag=1 ; shift ;;
-e|--eth) shift; chkarg $1 ; nic="$1" ; shift ;;
-R|--release) shift; chkarg $1 ; ver="$1" ; shift ;;
-v|--video) shift; chkarg $1 ; video="$1" ; shift ;;
-d|--disks) shift; chkarg $1 ; hds="$1" ; shift ;;
-x|--xen) XEN=xen ; shift ;;
-V|--virtio) vflag=1 ; shift ;;
-S|--sound) aflag=1 ; shift ;;
-l|--sdl) sflag=1 ; shift ;;
-L|--live) lflag=1 ; shift ;;
-t|--try) tflag=1 ; shift ;;
-h|--help) syntax ;;
--) shift ; chkopt $1 ; vm=$1 ; shift ;;
esac
done
if [ $uflag -ge 3 ] ; then
Error "options --url and --iso are mutually exclusive."
elif [ $uflag -le 0 ] ; then
Error "No OS or iso image specified."
fi
# check remote host
[ "$rhost" ] && hyp=$HV+ssh://$rhost/system || { [ "$HV" == "xen" ] && hyp=$HV:///system || hyp=${DEF_CONNECT:-$HV:///system} ; }
DEF_RHOST=$(echo ${DEF_CONNECT##*://} | sed 's|/system||')
host=${rhost:-$DEF_RHOST} ; host=${host:-$HOSTNAME}
[ "$host" == "$HOSTNAME" ] || {
ping -q -c 1 -W 2 $host &> /dev/null || Error "host $host is unreachable"
rflag=1 ; iflag=1 ; SSH="ssh root@$host"
}
# check virtual machine
virsh -c $hyp dominfo $vm &> /dev/null && Error "Virtual machine $vm already exists."
# check ram
ram=${ram:-$DEF_RAM}
chknum $ram ; [ $ram -ge $MIN_RAM ] || Error "not enough RAM allocated: $ram MB"
# check architecture
arch=${arch:-$DEF_ARCH}
arch=$(echo $arch | sed 's|i[456]|i3|;s|amd|x86_|')
[ "$arch" == "i386" -o "$arch" == "x86_64" ] || Error "unsupported architecture: $arch"
# check OS version
if [ $uflag -ge 2 ] ; then
url=${os}_url ; url=${!url}
[ "$url" ] || { url=${os}_iso ; url=${!url} ; iflag=1 ;}
[ "$rflag" ] && { url=${os}_iso ; url=${!url} ; iflag=1 ;}
VER=${os}_ver ; VER=${!VER} ; ver=${ver:-$VER}
which links &>/dev/null || Error "links not found. Please install the links package first."
[ "$url" ] && geturl $url $ver || Error "invalid OS: $os"
# check iso image
elif [ $uflag -ge 1 ] ; then
getiso $iso
fi
# check size of vm
vmsize=${vmsize:-$DEF_VMSIZE}
chknum $vmsize && VMSIZE=$vmsize
# check video
[ "$video" ] || video=$DEF_VIDEO
[ "${video_models%%:$video:*}" == "$video_models" ] && Error "Invalid video device: $video"
# check destination path,
IMGPATH=${IMGPATH:-/var/lib/libvirt/images}
imgpath=${imgpath:-$IMGPATH}
[ -d $imgpath ] || Error "Destination directory $imgpath doesn't exist."
# check mac address
[ "$mac" ] || mac=`$SSH grep $vm /etc/ethers 2>/dev/null | awk '{print $1}'`
[ "$mac" ] && chkMAC $mac
# OS and version
[ "$ver" ] && osver=" $ver"
[ "$os" ] && OSDESC=" ($os$osver)"
desc="$vm$OSDESC - vm guest on host $host"
# check os variant
Ver=${ver%%.*}
[ "$ostype" ] || ostype=$os$Ver
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$os$VER
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$(echo $os${OSTYPES##*$os} | sed 's| .*||')
[ "${OSTYPES%$ostype*}" == "$OSTYPES" -a $vflag -gt 0 ] && ostype=virtio26
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$DEF_KERN
[ "ostype" ] || ostype=generic
# check number of disk
[ "$hds" == "1" ] || chknum $hds
[ $hds -gt 1 ] && VMSIZE=$(($vmsize * $hds))
i=0
while [ $i -lt $hds ] ; do
hd[$i]=${vm}_hd$i.img
let i++
done
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ "$rflag" ] ; then
virsh -c $hyp pool-info default | grep -q running || virsh -c $hyp pool-start default
poolAvailableSize=$(virsh -c $hyp pool-info default | awk '/Available:/&&/GB/ { s=int($2 * 1024) ; print s }')
[ $(( ($VMSIZE + 1) * 1024)) -gt $poolAvailableSize ] && Error "Not enough space available on default pool"
if [ $hds -gt 1 ] ; then
if [ $tflag -eq 0 ] ; then
for hd in ${hd[li]} ; do
[/li] echo " - creating raw volume $hd, please wait..."
virsh -c $hyp vol-create-as default $hd ${vmsize}G
done
fi
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk '{ printf " --disk vol=default/%s", $1}')
else
DISKOPTS=" --disk pool=default,size=$vmsize"
fi
else
# check if there is enough space to store image locally.
hyp=$DEF_CONNECT
[ $(( ($VMSIZE + 1) * 1024)) -gt $(df -Pl -B $((1024*1024)) $imgpath | awk 'END { print $4 }') ] && Error "Not enough space available on $imgpath"
if [ $lflag -ge 1 ] ; then
DISKOPTS=" --nodisk"
[ $VIRTINST_VER -gt 5003 ] && BOOTOPTS=" --boot=cdrom"
else
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk 'BEGIN {S='$vmsize' ; P="'"$imgpath"'"} ; {printf " --disk path=%s/%s,size=%s", P, $1, S}')
fi
fi
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# networking
gw=${GATEWAY:-$GW}
# which networking method to use
if [ $bflag -eq 1 -o "$DEF_NETWORK" == "bridge" ] ; then
br=${br:-$DEF_BRIDGE}
nic=${nic:-$DEF_NIC}
ifconfig $nic &> /dev/null || Error "invalid network device: $nic"
# create bridge on localhost if needed
if [ "$rflag" ] ; then
if [ $tflag -eq 0 ] ; then
$SSH brctl show | grep -q "^$br[ ]" || Error "bridge $br not present on host $host"
fi
else
if [ "x$CREATEBRIDGE" == "x1" -a $tflag -eq 0 ] ; then
net=$(ifconfig $nic | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
brctl show | grep -q "^$br[ ]" && echo "bridge $br already set" || createBridge $br $nic $net
fi
fi
NETOPTS=" --network bridge=$br"
else
# start virtual network (NAT) if needed
if [ "x$STARTVIRBR" == "x1" ] ; then
virsh -c $hyp net-list | grep -q 'active' || virsh -c $hyp net-start default
NETOPTS=" --network network=default"
fi
fi
[ "$mac" ] && NETOPTS="$NETOPTS,mac=$mac"
case $os in
openbsd) NETOPTS="$NETOPTS,model=e1000" ;;
netbsd) NETOPTS="$NETOPTS,model=ne2k_pci" ; ACPI=" --noacpi" ; ostype=openbsd4 ;;
dflybsd) NETOPTS="$NETOPTS,model=e1000" ; ostype=freebsd7 ;;
opensuse) ostype=virtio26 ;;
esac
[ "$ostype" ] && ostype=" --os-variant=$ostype"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# display
[ $sflag -eq 1 ] && DISPLAYOPTS=" --sdl"
[ $aflag -ge 1 ] && audio=" --soundhw=$DEF_AUDIO"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ $tflag -ge 1 ] ; then
printf "
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description=\"$desc\"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
" | sed 's|--|
--|g'
else
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description="$desc"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
fi
Thanks. Got another problem with some URLs, including openSUSE. It seems that something changed on the download page, since I already installed openSUSE 11.3 and RC1. Anyway, I rewrote the geturl function an now it’s working for openSUSE (11.3 and 11.4), ubuntu (maverick and natty) as well as the other distros that the script handles. I also added the URL for the iso image in the output of **vm-create -t **… (which doesn’t do anything but printing the whole command). If you do a remote install (which means if you install a vm guest from the Internet onto a remote machine), you should see the iso URL displayed. If you don’t see it, the geturl function could not parse the download page (means something has changed again). And in that case, it won’t work. While installing from the Internet onto the local machine, the URL won’t appear in some cases not using the geturl and getiso functions, because the os_url (which refers to a directory and installs from that directory) has precedence over the os_iso (which first downloads a mini iso image from that directory to a directory on the local machine, exports that directory as a pool to the remote host and boots the iso image from there.
Installing from an Internet directory only works on a locale machine and only for the OS which have an os_url variable define in /etc/vm-create.cfg. These are debian, fedora, mandriva and ubuntu. It was supposed to work with openSUSE but it does not … and further it could not since it wouldn’t let you choose the architecture (32 or 64 bit) but select the architecture depending on the host … and having 32bit guests on 64bit hosts is quite common, in particular when you cannot afford 2 GB of RAM for each guest.
Be careful with distros which use a unique name for the net install iso image of different releases, like Ubuntu. If the iso image (in this case mini.iso) already exists in the volume pool, the script won’t download it again and you might end up installing the wrong version. It doesn’t affect openSUSE which use more specific filenames.
Here’s version 2.2 with rewritten geturl function:
#! /bin/bash
#: Title : vm-create
#: Date Created: Sat Jan 29 01:54:07 PST 2011
#: Last Edit : Wed Mar 2 08:04:48 PST 2011
#: Author : please_try_again
#: Version : 2.2
#: Description : install OS from the Internet or local iso in a kvm vm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prg=$(basename $0)
# use the popup library if found
which popup &>/dev/null && source $(which popup)
# use popup functions if available
function Error { declare -F | grep -q error || exec echo "Error: $*" ; error "$*" ;}
function Warn { declare -F | grep -q warn && warn "$*" || echo "Warning: $*" ;}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which virt-install &> /dev/null || Error "virt-install not installed"
[ -r /etc/vm-create.cfg ] && source /etc/vm-create.cfg || Error "/etc/vm-create.cfg not found"
[ -r ~/.vm-create.cfg ] && source ~/.vm-create.cfg
[ "x$(ps ax | grep libvirtd | awk '!/grep/ { print $1 }')" == "x" ] && Error "libvirtd is not running"
VIRTINST_VER=$(virt-install --version | sed 's|^0||;s|\.||g')
LIVIRT_VER=$(libvirtd --version | sed 's|[^0-9]*\([0-9]\)|\1|;s|\.||g;s|^0||')
# recognized OS types to this day.
OSTYPES="debianetch debianlenny debiansqueeze \
fedora5 fedora6 fedora7 fedora8 fedora9 fedora10 fedora11 fedora12 fedora13 \
generic24 generic26 \
virtio26 \
mandriva2009 mandriva2010 \
mes5 mes5.1 \
rhel2.1 rhel3 rhel4 rhel5 rhel5.4 rhel6 \
sles10 sles11 \
ubuntuhardy ubuntuintrepid ubuntujaunty ubuntukarmic \
generic \
msdos \
netware4 netware5 netware6 \
opensolaris solaris10 solaris9 \
freebsd6 freebsd7 \
openbsd4 \
vista win2k win2k3 win2k8 win7 winxp winxp64"
[ $VIRTINST_VER -lt 5003 ] && Error "virt-install 0.500.3 or newer required"
[ $VIRTINST_VER -ge 5004 ] && { OSTYPES="$OSTYPES fedora14 ubuntulucid freebsd8" ; BOOTOPTS=" --boot=cdrom,hd,network";}
[ $VIRTINST_VER -ge 5005 ] && OSTYPES="$OSTYPES ubuntumaverick"
[ $LIVIRT_VER -ge 87 ] && Y="-- "
DEF_CONNECT=${VIRSH_DEFAULT_CONNECT_URI:-${DEF_HYPERVISOR}://$DEF_HOST/system}
DISPLAYOPTS=" --vnc --vnclisten=0.0.0.0"
# valid xen and qemu MAC addresses
qemu_mac="52:54:00:"
xen_mac="00:16:3e:"
# valid video adapters
video_models=":vga:vmvga:cirrus:xen:"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function chknum {
N=$(echo $1 | tr -d "[:alpha:]")
[ "x$N" == "x$1" ] || Error "invalid numeric argument: $1"
}
function chkMAC {
Mac=$(echo ${1:0:9} | tr "[:upper:]" "[:lower:]")
MAC=${HV}_mac ; MAC=${!MAC}
[ "$Mac" == "$MAC" ] || Error "invalid $HV MAC address: $1"
[ "$(echo ${1:9} | sed 's|[^:]*||g')" == "::" ] || Error "invalid $HV MAC address: $1"
a=$(echo ${1:9} | sed 's|:||g;s|[^0-9a-fA-F]*||g')
[ ${#1} -eq 17 -a ${#a} -eq 6 ] || Error "invalid $HV MAC address: $1"
}
function chkarg { [ "${1:0:1}" == "-" ] && Error "invalid argument: $1" ;}
function chkopt { [ "x$1" == "x" ] && Error "you should provide a vm name" ;}
function syntax {
cat << EOFSYNTAX
usage:
$prg vm name
options:
-c --connect <host> : remote host where to create the vm
-r --ram <ram in MB> : amount of ram (default 512MB)
-a --arch <i386|amd64> : architecture (i386 or amd64)
-o --os <os variant> : os variant (example: fedora14, mandriva2010)
-u --url <os> : os (fedora, debian, ubuntu, opensuse, mandriva)
-i --iso <img.iso> : iso image
-p --path <directory> : where to store vm images
-s --size <size> : size of virtual machine in GB
-V --virtio : same as -o virtio26
-v --video : video device: cirrus, vga* or vmvga (for kvm)
-R --release : OS version to install (other than default)
-S --sound : enable sound device (ac97)
-l --sdl : use sdl display rather than vnc
-L --live : boot live CD
-b --bridge <bridge> : use network bridge (otherwise use DEF_NETWORK if defined or 'nat')
-e --eth <nic> : network interface to use for bridge (otherwise use DEF_NIC if defined or eth0)
-x --xen : use Xen hypervisor rather than kvm
-t --try : just print but not execute the command
-h --help : show this help
-d --disks : number of virtual hard disks
recognized OS variants :
`echo $OSTYPES | fmt`
available guest systems :
$(awk -F "=" '/^[a-zA-Z0-9]*_url=|^[a-zA-Z0-9]*_iso=/ { sub(/_.*/,"",$1); print $1 }' /etc/vm-create.cfg | sort -u | tr "
" " ")
EOFSYNTAX
exit
}
function createBridge {
[ "x$gw" == "x" ] && Error "no gateway defined"
ping -q -c 1 -W 2 $gw > /dev/null || Error "gateway $gw is unreachable"
echo " - creating bridge $1"
brctl addbr $1
ifconfig $2 0.0.0.0 promisc
brctl addif $1 $2
ifconfig $1 inet $3 netmask $DEF_NETMASK
brctl stp $br on
route del default 2>/dev/null
route add default gw $gw 2>/dev/null
}
function importPool {
virsh -c $hyp pool-dumpxml $1 2>/dev/null | grep -q $2 && {
virsh -c $hyp pool-info $1 | grep -q running || virsh -c $hyp pool-start $1
virsh -c $hyp pool-refresh $1
return
}
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-destroy $1 2>/dev/null
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-undefine $1 2>/dev/null
$SSH mkdir -m 600 $POOLPATH 2>/dev/null
virsh -c $hyp pool-create-as $1 netfs $2 $ISOPATH -- -- $Y$POOLPATH
}
function getarch {
case $1 in
x86_64)
case $os in
centos|debian|dflybsd|freebsd|gentoo|netbsd|openbsd|ubuntu) echo amd64 ;;
*) echo $1 ;;
esac
;;
i386)
case $os in
mandriva|opensuse*) echo i586 ;;
archlinux) echo i686 ;;
gentoo) echo x86 ;;
*) echo $1 ;;
esac
;;
esac
}
function getiso {
[ -d $ISOPATH ] && cd $ISOPATH || Error "$ISOPATH doesn't exist"
IMG=$1 ; shift ; URL=$1
ISO=$(basename $IMG .bz2) ; ISO=$(basename $ISO .tgz)
if [ $tflag -eq 0 ] ; then
if [ "$URL" ] ; then
[ -f ./$ISO ] || [ -f ./$IMG ] || wget -v $URL/$IMG
[ -f ./$ISO ] || bunzip2 -v $IMG
else
[ -f $IMG ] || Error "File not found: $IMG"
file $IMG | grep -q bootable || Error "$IMG is not a bootable iso image"
fi
fi
DIR=$(dirname $IMG)
[ "$DIR" == "." ] && DIR=$(pwd)
if [ "$rflag" ] ; then
[ "$DIR" == "$ISOPATH" ] || Error "iso img $ISO not in shared pool $ISOPATH"
[ $tflag -eq 0 ] && importPool $POOLNAME $HOSTNAME
url=" --disk vol=$POOLNAME/$ISO,device=cdrom"
else
url=" --cdrom=$DIR/$ISO"
fi
cd - >/dev/null
}
# find out if we need to download a netinstall iso image
function geturl {
ARCH=$(getarch $arch)
URL=${1//ARCH/$ARCH} ; shift
URL=${URL//VER/$1}
if [ "$iflag" ] ; then
imgs=($(links -dump $URL | awk '/dfly|netinst|mini|NET|boot|cd[-0-9]/&&/iso|iso.bz2/ { print $0}' | sed 's|.* \([^ ]*.iso[.bz2]*\).*|\1|;s|\.$||' | sort -u))
[ ${#imgs[li]} -eq 1 ] && img=${imgs[0]} || img=$(echo ${imgs[*]} | tr " " "[/li]" | grep $ARCH | tail -1)
getiso $(basename $img) $URL
DISTURL="$URL/$img"
else
url=" --location=$URL"
fi
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uflag=0 ; vflag=0 ; bflag=0 ; sflag=0 ; dflag=0 ; tflag=0 ; lflag=0 ; aflag=0
url=""
HV=$DEF_HYPERVISOR
hds=1
# evaluate arguments
args=`getopt -q -u -o c:r:a:m:o:u:i:p:s:b:e:R:v:d:xSVlLht -l connect:,ram:,arch:,mac:,os:,url:,iso:,path:,size:,bridge:,eth:,release:,video:,disks:,xen,virtio,sdl,sound,live,help,try -- "$@"`
set -- $args
for i; do
case "$i" in
-c|--connect) shift; chkarg $1 ; rhost="$1" ; shift ;;
-r|--ram) shift; chkarg $1 ; ram="$1" ; shift ;;
-a|--arch) shift; chkarg $1 ; arch="$1" ; shift ;;
-m|--mac) shift; chkarg $1 ; mac="$1" ; shift ;;
-o|--os) shift; chkarg $1 ; ostype="$1" ; shift ;;
-i|--iso) shift; chkarg $1 ; iso="$1" ; uflag=$(($uflag | 1)) ; shift ;;
-u|--url) shift; chkarg $1 ; os="$1" ; uflag=$(($uflag | 2)) ; shift ;;
-p|--path) shift; chkarg $1 ; imgpath="$1" ; shift ;;
-s|--size) shift; chkarg $1 ; vmsize="$1" ; shift ;;
-b|--bridge) shift; chkarg $1 ; br="$1" ; bflag=1 ; shift ;;
-e|--eth) shift; chkarg $1 ; nic="$1" ; shift ;;
-R|--release) shift; chkarg $1 ; ver="$1" ; shift ;;
-v|--video) shift; chkarg $1 ; video="$1" ; shift ;;
-d|--disks) shift; chkarg $1 ; hds="$1" ; shift ;;
-x|--xen) XEN=xen ; shift ;;
-V|--virtio) vflag=1 ; shift ;;
-S|--sound) aflag=1 ; shift ;;
-l|--sdl) sflag=1 ; shift ;;
-L|--live) lflag=1 ; shift ;;
-t|--try) tflag=1 ; shift ;;
-h|--help) syntax ;;
--) shift ; chkopt $1 ; vm=$1 ; shift ;;
esac
done
if [ $uflag -ge 3 ] ; then
Error "options --url and --iso are mutually exclusive."
elif [ $uflag -le 0 ] ; then
Error "No OS or iso image specified."
fi
# check remote host
[ "$rhost" ] && hyp=$HV+ssh://$rhost/system || { [ "$HV" == "xen" ] && hyp=$HV:///system || hyp=${DEF_CONNECT:-$HV:///system} ; }
DEF_RHOST=$(echo ${DEF_CONNECT##*://} | sed 's|/system||')
host=${rhost:-$DEF_RHOST} ; host=${host:-$HOSTNAME}
[ "$host" == "$HOSTNAME" ] || {
ping -q -c 1 -W 2 $host &> /dev/null || Error "host $host is unreachable"
rflag=1 ; iflag=1 ; SSH="ssh root@$host"
}
# check virtual machine
virsh -c $hyp dominfo $vm &> /dev/null && Error "Virtual machine $vm already exists."
# check ram
ram=${ram:-$DEF_RAM}
chknum $ram ; [ $ram -ge $MIN_RAM ] || Error "not enough RAM allocated: $ram MB"
# check architecture
arch=${arch:-$DEF_ARCH}
arch=$(echo $arch | sed 's|i[456]|i3|;s|amd|x86_|')
[ "$arch" == "i386" -o "$arch" == "x86_64" ] || Error "unsupported architecture: $arch"
# check OS version
if [ $uflag -ge 2 ] ; then
url=${os}_url ; url=${!url}
[ "$url" ] || { url=${os}_iso ; url=${!url} ; iflag=1 ;}
[ "$rflag" ] && { url=${os}_iso ; url=${!url} ; iflag=1 ;}
VER=${os}_ver ; VER=${!VER} ; ver=${ver:-$VER}
which links &>/dev/null || Error "links not found. Please install the links package first."
[ "$url" ] && geturl $url $ver || Error "invalid OS: $os"
# check iso image
elif [ $uflag -ge 1 ] ; then
getiso $iso
fi
# check size of vm
vmsize=${vmsize:-$DEF_VMSIZE}
chknum $vmsize && VMSIZE=$vmsize
# check video
[ "$video" ] || video=$DEF_VIDEO
[ "${video_models%%:$video:*}" == "$video_models" ] && Error "Invalid video device: $video"
# check destination path,
IMGPATH=${IMGPATH:-/var/lib/libvirt/images}
imgpath=${imgpath:-$IMGPATH}
[ -d $imgpath ] || Error "Destination directory $imgpath doesn't exist."
# check mac address
[ "$mac" ] || mac=`$SSH grep $vm /etc/ethers 2>/dev/null | awk '{print $1}'`
[ "$mac" ] && chkMAC $mac
# OS and version
[ "$ver" ] && osver=" $ver"
[ "$os" ] && OSDESC=" ($os$osver)"
desc="$vm$OSDESC - vm guest on host $host"
# check os variant
Ver=${ver%%.*}
[ "$ostype" ] || ostype=$os$Ver
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$os$VER
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$(echo $os${OSTYPES##*$os} | sed 's| .*||')
[ "${OSTYPES%$ostype*}" == "$OSTYPES" -a $vflag -gt 0 ] && ostype=virtio26
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$DEF_KERN
[ "ostype" ] || ostype=generic
# check number of disk
[ "$hds" == "1" ] || chknum $hds
[ $hds -gt 1 ] && VMSIZE=$(($vmsize * $hds))
i=0
while [ $i -lt $hds ] ; do
hd[$i]=${vm}_hd$i.img
let i++
done
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ "$rflag" ] ; then
virsh -c $hyp pool-info default | grep -q running || virsh -c $hyp pool-start default
poolAvailableSize=$(virsh -c $hyp pool-info default | awk '/Available:/&&/GB/ { s=int($2 * 1024) ; print s }')
[ $(( ($VMSIZE + 1) * 1024)) -gt $poolAvailableSize ] && Error "Not enough space available on default pool"
if [ $hds -gt 1 ] ; then
if [ $tflag -eq 0 ] ; then
for hd in ${hd[li]} ; do
[/li] echo " - creating raw volume $hd, please wait..."
virsh -c $hyp vol-create-as default $hd ${vmsize}G
done
fi
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk '{ printf " --disk vol=default/%s", $1}')
else
DISKOPTS=" --disk pool=default,size=$vmsize"
fi
else
# check if there is enough space to store image locally.
hyp=$DEF_CONNECT
[ $(( ($VMSIZE + 1) * 1024)) -gt $(df -Pl -B $((1024*1024)) $imgpath | awk 'END { print $4 }') ] && Error "Not enough space available on $imgpath"
if [ $lflag -ge 1 ] ; then
DISKOPTS=" --nodisk"
[ $VIRTINST_VER -gt 5003 ] && BOOTOPTS=" --boot=cdrom"
else
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk 'BEGIN {S='$vmsize' ; P="'"$imgpath"'"} ; {printf " --disk path=%s/%s,size=%s", P, $1, S}')
fi
fi
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# networking
gw=${GATEWAY:-$GW}
# which networking method to use
if [ $bflag -eq 1 -o "$DEF_NETWORK" == "bridge" ] ; then
br=${br:-$DEF_BRIDGE}
nic=${nic:-$DEF_NIC}
ifconfig $nic &> /dev/null || Error "invalid network device: $nic"
# create bridge on localhost if needed
if [ "$rflag" ] ; then
if [ $tflag -eq 0 ] ; then
$SSH brctl show | grep -q "^$br[ ]" || Error "bridge $br not present on host $host"
fi
else
if [ "x$CREATEBRIDGE" == "x1" -a $tflag -eq 0 ] ; then
net=$(ifconfig $nic | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
brctl show | grep -q "^$br[ ]" && echo "bridge $br already set" || createBridge $br $nic $net
fi
fi
NETOPTS=" --network bridge=$br"
else
# start virtual network (NAT) if needed
if [ "x$STARTVIRBR" == "x1" ] ; then
virsh -c $hyp net-list | grep -q 'active' || virsh -c $hyp net-start default
NETOPTS=" --network network=default"
fi
fi
[ "$mac" ] && NETOPTS="$NETOPTS,mac=$mac"
case $os in
openbsd) NETOPTS="$NETOPTS,model=e1000" ;;
netbsd) NETOPTS="$NETOPTS,model=ne2k_pci" ; ACPI=" --noacpi" ; ostype=openbsd4 ;;
dflybsd) NETOPTS="$NETOPTS,model=e1000" ; ostype=freebsd7 ;;
opensuse) ostype=virtio26 ;;
esac
[ "$ostype" ] && ostype=" --os-variant=$ostype"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# display
[ $sflag -eq 1 ] && DISPLAYOPTS=" --sdl"
[ $aflag -ge 1 ] && audio=" --soundhw=$DEF_AUDIO"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ $tflag -ge 1 ] ; then
printf "
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description=\"$desc\"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
" | sed 's|--|
--|g'
[ "$DISTURL" ] && printf "iso URL: %s
" $DISTURL
else
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description="$desc"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
fi
Version 2.3. Some minor bug fixes (like checking some more invalid input from user).
#! /bin/bash
#: Title : vm-create
#: Date Created: Sat Jan 29 01:54:07 PST 2011
#: Last Edit : Sat Mar 12 09:21:59 PST 2011
#: Author : please_try_again
#: Version : 2.3
#: Description : install OS from the Internet or local iso in a kvm vm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prg=$(basename $0)
# use the popup library if found
which popup &>/dev/null && source $(which popup)
# use popup functions if available
function Error { declare -F | grep -q error || exec echo "Error: $*" ; error "$*" ;}
function Warn { declare -F | grep -q warn && warn "$*" || echo "Warning: $*" ;}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
which virt-install &> /dev/null || Error "virt-install not installed"
[ -r /etc/vm-create.cfg ] && source /etc/vm-create.cfg || Error "/etc/vm-create.cfg not found"
[ -r ~/.vm-create.cfg ] && source ~/.vm-create.cfg
[ "x$(ps ax | grep libvirtd | awk '!/grep/ { print $1 }')" == "x" ] && Error "libvirtd is not running"
VIRTINST_VER=$(virt-install --version | sed 's|^0||;s|\.||g')
LIVIRT_VER=$(libvirtd --version | sed 's|[^0-9]*\([0-9]\)|\1|;s|\.||g;s|^0||')
# recognized OS types to this day.
OSTYPES="debianetch debianlenny debiansqueeze \
fedora5 fedora6 fedora7 fedora8 fedora9 fedora10 fedora11 fedora12 fedora13 \
generic24 generic26 \
virtio26 \
mandriva2009 mandriva2010 \
mes5 mes5.1 \
rhel2.1 rhel3 rhel4 rhel5 rhel5.4 rhel6 \
sles10 sles11 \
ubuntuhardy ubuntuintrepid ubuntujaunty ubuntukarmic \
generic \
msdos \
netware4 netware5 netware6 \
opensolaris solaris10 solaris9 \
freebsd6 freebsd7 \
openbsd4 \
vista win2k win2k3 win2k8 win7 winxp winxp64"
[ $VIRTINST_VER -lt 5003 ] && Error "virt-install 0.500.3 or newer required"
[ $VIRTINST_VER -ge 5004 ] && { OSTYPES="$OSTYPES fedora14 ubuntulucid freebsd8" ; BOOTOPTS=" --boot=cdrom,hd,network";}
[ $VIRTINST_VER -ge 5005 ] && OSTYPES="$OSTYPES ubuntumaverick"
[ $LIVIRT_VER -ge 87 ] && Y="-- "
DEF_CONNECT=${VIRSH_DEFAULT_CONNECT_URI:-${DEF_HYPERVISOR}://$DEF_HOST/system}
DISPLAYOPTS=" --vnc --vnclisten=0.0.0.0"
# valid xen and qemu MAC addresses
qemu_mac="52:54:00:"
xen_mac="00:16:3e:"
# valid video adapters
video_models=":vga:vmvga:cirrus:xen:"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function chknum {
N=$(echo $1 | tr -d "[:alpha:]")
[ "x$N" == "x$1" ] || Error "invalid numeric argument: $1"
}
function chkMAC {
Mac=$(echo ${1:0:9} | tr "[:upper:]" "[:lower:]")
MAC=${HV}_mac ; MAC=${!MAC}
[ "$Mac" == "$MAC" ] || Error "invalid $HV MAC address: $1"
[ "$(echo ${1:9} | sed 's|[^:]*||g')" == "::" ] || Error "invalid $HV MAC address: $1"
a=$(echo ${1:9} | sed 's|:||g;s|[^0-9a-fA-F]*||g')
[ ${#1} -eq 17 -a ${#a} -eq 6 ] || Error "invalid $HV MAC address: $1"
}
function chkarg { [ "${1:0:1}" == "-" ] && Error "invalid argument: $1" ;}
function chkopt { [ "x$1" == "x" ] && Error "you should provide a vm name" ;}
function syntax {
cat << EOFSYNTAX
usage:
$prg vm name
options:
-c --connect <host> : remote host where to create the vm
-r --ram <ram in MB> : amount of ram (default 512MB)
-a --arch <i386|amd64> : architecture (i386 or amd64)
-o --os <os variant> : os variant (example: fedora14, mandriva2010)
-u --url <os> : os (fedora, debian, ubuntu, opensuse, mandriva)
-i --iso <img.iso> : iso image
-p --path <directory> : where to store vm images
-s --size <size> : size of virtual machine in GB
-V --virtio : same as -o virtio26
-v --video : video device: cirrus, vga* or vmvga (for kvm)
-R --release : OS version to install (other than default)
-S --sound : enable sound device (ac97)
-l --sdl : use sdl display rather than vnc
-L --live : boot live CD
-b --bridge <bridge> : use network bridge (otherwise use DEF_NETWORK if defined or 'nat')
-e --eth <nic> : network interface to use for bridge (otherwise use DEF_NIC if defined or eth0)
-x --xen : use Xen hypervisor rather than kvm
-t --try : just print but not execute the command
-h --help : show this help
-d --disks : number of virtual hard disks
recognized OS variants :
`echo $OSTYPES | fmt`
available guest systems :
$(awk -F "=" '/^[a-zA-Z0-9]*_url=|^[a-zA-Z0-9]*_iso=/ { sub(/_.*/,"",$1); print $1 }' /etc/vm-create.cfg | sort -u | tr "
" " ")
EOFSYNTAX
exit
}
function createBridge {
[ "x$gw" == "x" ] && Error "no gateway defined"
ping -q -c 1 -W 2 $gw > /dev/null || Error "gateway $gw is unreachable"
echo " - creating bridge $1"
brctl addbr $1
ifconfig $2 0.0.0.0 promisc
brctl addif $1 $2
ifconfig $1 inet $3 netmask $DEF_NETMASK
brctl stp $br on
route del default 2>/dev/null
route add default gw $gw 2>/dev/null
}
function importPool {
virsh -c $hyp pool-dumpxml $1 2>/dev/null | grep -q $2 && {
virsh -c $hyp pool-info $1 | grep -q running || virsh -c $hyp pool-start $1
virsh -c $hyp pool-refresh $1
return
}
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-destroy $1 2>/dev/null
virsh -c $hyp pool-list --all | grep -q "\b$1\b" && virsh -c $hyp pool-undefine $1 2>/dev/null
$SSH mkdir -m 600 $POOLPATH 2>/dev/null
virsh -c $hyp pool-create-as $1 netfs $2 $ISOPATH -- -- $Y$POOLPATH
}
function getarch {
case $1 in
x86_64)
case $os in
centos|debian|dflybsd|freebsd|gentoo|netbsd|openbsd|ubuntu) echo amd64 ;;
*) echo $1 ;;
esac
;;
i386)
case $os in
mandriva|opensuse*) echo i586 ;;
archlinux) echo i686 ;;
gentoo) echo x86 ;;
*) echo $1 ;;
esac
;;
esac
}
function getiso {
[ -d $ISOPATH ] && cd $ISOPATH || Error "$ISOPATH doesn't exist"
IMG=$1 ; shift ; URL=$1
ISO=$(basename $IMG .bz2) ; ISO=$(basename $ISO .tgz)
if [ $tflag -eq 0 ] ; then
if [ "$URL" ] ; then
[ -f ./$ISO ] || [ -f ./$IMG ] || wget -v $URL/$IMG
[ -f ./$ISO ] || bunzip2 -v $IMG
else
[ -f $IMG ] || Error "File not found: $IMG"
file $IMG | grep -q bootable || Error "$IMG is not a bootable iso image"
fi
fi
DIR=$(dirname $IMG)
[ "$DIR" == "." ] && DIR=$(pwd)
if [ "$rflag" ] ; then
[ "$DIR" == "$ISOPATH" ] || Error "iso img $ISO not in shared pool $ISOPATH"
[ $tflag -eq 0 ] && importPool $POOLNAME $HOSTNAME
url=" --disk vol=$POOLNAME/$ISO,device=cdrom"
else
url=" --cdrom=$DIR/$ISO"
fi
cd - >/dev/null
}
# find out if we need to download a netinstall iso image
function geturl {
ARCH=$(getarch $arch)
URL=${1//ARCH/$ARCH} ; shift
URL=${URL//VER/$1}
if [ "$iflag" ] ; then
imgs=($(links -dump $URL | awk '/dfly|netinst|mini|NET|boot|cd[-0-9]/&&/iso|iso.bz2/ { print $0}' | sed 's|.* \([^ ]*.iso[.bz2]*\).*|\1|;s|\.$||;s|^.*[]/]||' | sort -u))
[ ${#imgs[li]} -eq 1 ] && img=${imgs[0]} || img=$(echo ${imgs[*]} | tr " " "[/li]" | grep $ARCH | tail -1)
getiso $(basename $img) $URL
DISTURL="$URL/$img"
else
url=" --location=$URL"
fi
}
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uflag=0 ; vflag=0 ; bflag=0 ; sflag=0 ; dflag=0 ; tflag=0 ; lflag=0 ; aflag=0
url=""
HV=$DEF_HYPERVISOR
hds=1
# evaluate arguments
args=`getopt -q -u -o c:r:a:m:o:u:i:p:s:b:e:R:v:d:xSVlLht -l connect:,ram:,arch:,mac:,os:,url:,iso:,path:,size:,bridge:,eth:,release:,video:,disks:,xen,virtio,sdl,sound,live,help,try -- "$@"`
set -- $args
for i; do
case "$i" in
-c|--connect) shift; chkarg $1 ; rhost="$1" ; shift ;;
-r|--ram) shift; chkarg $1 ; ram="$1" ; shift ;;
-a|--arch) shift; chkarg $1 ; arch="$1" ; shift ;;
-m|--mac) shift; chkarg $1 ; mac="$1" ; shift ;;
-o|--os) shift; chkarg $1 ; ostype="$1" ; shift ;;
-i|--iso) shift; chkarg $1 ; iso="$1" ; uflag=$(($uflag | 1)) ; shift ;;
-u|--url) shift; chkarg $1 ; os="$1" ; uflag=$(($uflag | 2)) ; shift ;;
-p|--path) shift; chkarg $1 ; imgpath="$1" ; shift ;;
-s|--size) shift; chkarg $1 ; vmsize="$1" ; shift ;;
-b|--bridge) shift; chkarg $1 ; br="$1" ; bflag=1 ; shift ;;
-e|--eth) shift; chkarg $1 ; nic="$1" ; shift ;;
-R|--release) shift; chkarg $1 ; ver="$1" ; shift ;;
-v|--video) shift; chkarg $1 ; video="$1" ; shift ;;
-d|--disks) shift; chkarg $1 ; hds="$1" ; shift ;;
-x|--xen) XEN=xen ; shift ;;
-V|--virtio) vflag=1 ; shift ;;
-S|--sound) aflag=1 ; shift ;;
-l|--sdl) sflag=1 ; shift ;;
-L|--live) lflag=1 ; shift ;;
-t|--try) tflag=1 ; shift ;;
-h|--help) syntax ;;
--) shift ; chkopt $1 ; vm=$1 ; shift ;;
esac
done
if [ $uflag -ge 3 ] ; then
Error "options --url and --iso are mutually exclusive."
elif [ $uflag -le 0 ] ; then
Error "No OS or iso image specified."
fi
# check remote host
[ "$rhost" ] && hyp=$HV+ssh://$rhost/system || { [ "$HV" == "xen" ] && hyp=$HV:///system || hyp=${DEF_CONNECT:-$HV:///system} ; }
DEF_RHOST=$(echo ${DEF_CONNECT##*://} | sed 's|/system||')
host=${rhost:-$DEF_RHOST} ; host=${host:-$HOSTNAME}
[ "$host" == "$HOSTNAME" ] || {
ping -q -c 1 -W 2 $host &> /dev/null || Error "host $host is unreachable"
rflag=1 ; iflag=1 ; SSH="ssh root@$host"
}
# check virtual machine
virsh -c $hyp dominfo $vm &> /dev/null && Error "Virtual machine $vm already exists."
# check ram
ram=${ram:-$DEF_RAM}
chknum $ram ; [ $ram -ge $MIN_RAM ] || Error "not enough RAM allocated: $ram MB"
# check architecture
arch=${arch:-$DEF_ARCH}
arch=$(echo $arch | sed 's|i[456]|i3|;s|amd|x86_|')
[ "$arch" == "i386" -o "$arch" == "x86_64" ] || Error "unsupported architecture: $arch"
# check OS version
if [ $uflag -ge 2 ] ; then
url=${os}_url ; url=${!url}
[ "$url" ] || { url=${os}_iso ; url=${!url} ; iflag=1 ;}
[ "$rflag" ] && { url=${os}_iso ; url=${!url} ; iflag=1 ;}
VER=${os}_ver ; VER=${!VER} ; ver=${ver:-$VER}
which links &>/dev/null || Error "links not found. Please install the links package first."
[ "$url" ] && geturl $url $ver || Error "invalid OS: $os"
# check iso image
elif [ $uflag -ge 1 ] ; then
getiso $iso
fi
# check size of vm
vmsize=${vmsize:-$DEF_VMSIZE}
chknum $vmsize && VMSIZE=$vmsize
# check video
[ "$video" ] || video=$DEF_VIDEO
[ "${video_models%%:$video:*}" == "$video_models" ] && Error "Invalid video device: $video"
# check destination path,
IMGPATH=${IMGPATH:-/var/lib/libvirt/images}
imgpath=${imgpath:-$IMGPATH}
[ -d $imgpath ] || Error "Destination directory $imgpath doesn't exist."
# check mac address
[ "$mac" ] || mac=`$SSH grep $vm /etc/ethers 2>/dev/null | awk '{print $1}'`
[ "$mac" ] && chkMAC $mac
# OS and version
[ "$ver" ] && osver=" $ver"
[ "$os" ] && OSDESC=" ($os$osver)"
desc="$vm$OSDESC - vm guest on host $host"
# check os variant
Ver=${ver%%.*}
[ "$ostype" ] || ostype=$os$Ver
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$os$VER
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$(echo $os${OSTYPES##*$os} | sed 's| .*||')
[ "${OSTYPES%$ostype*}" == "$OSTYPES" -a $vflag -gt 0 ] && ostype=virtio26
[ "${OSTYPES%$ostype*}" == "$OSTYPES" ] && ostype=$DEF_KERN
[ "ostype" ] || ostype=generic
# check number of disk
[ "$hds" == "1" ] || chknum $hds
[ $hds -gt 1 ] && VMSIZE=$(($vmsize * $hds))
i=0
while [ $i -lt $hds ] ; do
hd[$i]=${vm}_hd$i.img
let i++
done
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ "$rflag" ] ; then
virsh -c $hyp pool-info default | grep -q running || virsh -c $hyp pool-start default
poolAvailableSize=$(virsh -c $hyp pool-info default | awk '/Available:/&&/GB/ { s=int($2 * 1024) ; print s }')
[ $(( ($VMSIZE + 1) * 1024)) -gt $poolAvailableSize ] && Error "Not enough space available on default pool"
if [ $hds -gt 1 ] ; then
if [ $tflag -eq 0 ] ; then
for hd in ${hd[li]} ; do
[/li] echo " - creating raw volume $hd, please wait..."
virsh -c $hyp vol-create-as default $hd ${vmsize}G
done
fi
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk '{ printf " --disk vol=default/%s", $1}')
else
DISKOPTS=" --disk pool=default,size=$vmsize"
fi
else
# check if there is enough space to store image locally.
hyp=$DEF_CONNECT
[ $(( ($VMSIZE + 1) * 1024)) -gt $(df -Pl -B $((1024*1024)) $imgpath | awk 'END { print $4 }') ] && Error "Not enough space available on $imgpath"
if [ $lflag -ge 1 ] ; then
DISKOPTS=" --nodisk"
[ $VIRTINST_VER -gt 5003 ] && BOOTOPTS=" --boot=cdrom"
else
DISKOPTS=$(echo ${hd[li]} | tr " " "[/li]" | awk 'BEGIN {S='$vmsize' ; P="'"$imgpath"'"} ; {printf " --disk path=%s/%s,size=%s", P, $1, S}')
fi
fi
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# networking
gw=${GATEWAY:-$GW}
# which networking method to use
if [ $bflag -eq 1 -o "$DEF_NETWORK" == "bridge" ] ; then
br=${br:-$DEF_BRIDGE}
[ "${br#br*}" == "$br" ] && Error "invalid bridge device: $br"
nic=${nic:-$DEF_NIC}
ifconfig $nic &> /dev/null || Error "invalid network device: $nic"
# create bridge on localhost if needed
if [ "$rflag" ] ; then
if [ $tflag -eq 0 ] ; then
$SSH brctl show | grep -q "^$br[ ]" || Error "bridge $br not present on host $host"
fi
else
if [ "x$CREATEBRIDGE" == "x1" -a $tflag -eq 0 ] ; then
net=$(ifconfig $nic | awk '/inet addr/ { sub(/addr:/,"",$2) ; print $2 }')
brctl show | grep -q "^$br[ ]" && echo "bridge $br already set" || createBridge $br $nic $net
fi
fi
NETOPTS=" --network bridge=$br"
else
# start virtual network (NAT) if needed
if [ "x$STARTVIRBR" == "x1" ] ; then
virsh -c $hyp net-list | grep -q 'active' || virsh -c $hyp net-start default
NETOPTS=" --network network=default"
fi
fi
[ "$mac" ] && NETOPTS="$NETOPTS,mac=$mac"
case $os in
openbsd) NETOPTS="$NETOPTS,model=e1000" ;;
netbsd) NETOPTS="$NETOPTS,model=ne2k_pci" ; ACPI=" --noacpi" ; ostype=openbsd4 ;;
dflybsd) NETOPTS="$NETOPTS,model=e1000" ; ostype=freebsd7 ;;
opensuse) ostype=virtio26 ;;
esac
[ "$ostype" ] && ostype=" --os-variant=$ostype"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# display
[ $sflag -eq 1 ] && DISPLAYOPTS=" --sdl"
[ $aflag -ge 1 ] && audio=" --soundhw=$DEF_AUDIO"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if [ $tflag -ge 1 ] ; then
printf "
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description=\"$desc\"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
" | sed 's|--|
--|g'
[ "$DISTURL" ] && printf "iso URL: %s
" $DISTURL
else
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description="$desc"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
fi
new /etc/vm-create.cfg now defaults to openSUSE 11.4
(Don’t forget to edit the paths!)
# system wide /etc/vm-create.cfg.
# variables in this file can be ovrewritten in ~/.vm-create.cfg
# DEFINE THE VARIABLES IN THIS SECTIONS TO MATCH YOUR SYSTEM
IMGPATH=/misc/vm # where to put the vm images.
ISOPATH=/misc/iso # where to save iso images
POOLNAME=install # pollname for remote install
POOLPATH=/var/lib/libvirt/images/install
# your gateway (unless set in the environment variable GATEWAY)
GW=192.168.101.1
# YOU MIGHT EDIT THE DEFAULTS BELOW
DEF_HYPERVISOR=qemu # qemu or xen
#DEF_HOST= # default to localhost
DEF_RAM=512
DEF_CPUS=1
DEF_ARCH=i386
DEF_KERN=generic26
DEF_VIDEO=vga # cirrus, vga or vmvga
DEF_AUDIO=default # AC97 if the hypervisor supports it, otherwise it will be ES1370.
DEF_VMSIZE=10 # default size of virtual machines (10GB)
# network defaults
DEF_BRIDGE=br0
DEF_NIC=eth0
DEF_NAT=virbr0
DEF_NETWORK=nat # nat or bridge
DEF_NETMASK=0xffffff00 # should be fine for a class C network
CREATEBRIDGE=1 # create bridge if needed
STARTVIRBR=1 # start virtual network (NAT) if needed
MIN_RAM=64 # minimal amount of RAM for a vm
# You might change distros default versions
opensuse_ver=11.4
centos_ver=5
fedora_ver=14
ubuntu_ver=maverick
mandriva_ver=2010.2
debian_ver=squeeze
freebsd_ver=8.2
openbsd_ver=4.8
netbsd_ver=5.1
dflybsd_ver=2.8.2
# You might add/change ditros urls.
MIRROR="ftp://ftp.osuosl.org"
# mirrors
debian_mirror=$MIRROR
debiancd_mirror=$MIRROR
archlinux_mirror="$MIRROR/pub/archlinux"
centos_mirror="$MIRROR/pub/centos"
fedora_mirror="$MIRROR/pub/fedora"
gentoo_mirror="$MIRROR/pub/gentoo"
ubuntu_mirror="$MIRROR/pub/ubuntu"
#opensuse_mirror="$MIRROR/pub/opensuse"
# official sites
freebsd_mirror="ftp://ftp.freebsd.org/pub/FreeBSD"
openbsd_mirror="ftp://ftp.openbsd.org/pub/OpenBSD"
netbsd_mirror="ftp://ftp.netbsd.org/pub/NetBSD"
dflybsd_mirror="ftp://ftp.dragonflybsd.org"
opensuse_mirror="http://download.opensuse.org"
mandriva_mirror="ftp://ftp.uwsg.indiana.edu"
#debian_mirror="ftp://ftp.debian.org"
#debiancd_mirror="htpp://cdimage.debian.org"
#archlinux_mirror="ftp://ftp.archlinux.org"
#fedora_mirror="http://download.fedoraproject.org/pub/fedora"
#gentoo_iso="http://distfiles.gentoo.org"
ubuntu_mirror="http://ca.archive.ubuntu.com/ubuntu"
debian_url="$debian_mirror/debian/dists/VER/main/installer-ARCH/"
fedora_url="$fedora_mirror/linux/releases/VER/Fedora/ARCH/os/"
mandriva_url="$mandriva_mirror/linux/mandrake/official/VER/ARCH/"
ubuntu_url="$ubuntu_mirror/dists/VER/main/installer-ARCH/"
archlinux_iso="$archlinux_mirror/iso/latest"
centos_iso="$centos_mirror/VER/isos/ARCH"
debian_iso="$debiancd_mirror/debian-cd/6.0.0/ARCH/iso-cd"
fedora_iso="$fedora_mirror/linux/releases/VER/Fedora/ARCH/iso"
gentoo_iso="$gentoo_mirror/releases/ARCH/current-iso"
mandriva_iso="$mandriva_mirror/linux/mandrake/official/VER/ARCH/install/images"
opensuse_iso="$opensuse_mirror/distribution/VER/iso"
ubuntu_iso="$ubuntu_mirror/dists/VER/main/installer-ARCH/current/images/netboot"
freebsd_iso="$freebsd_mirror/releases/ARCH/ISO-IMAGES/VER"
openbsd_iso="$openbsd_mirror/VER/ARCH"
netbsd_iso="$netbsd_mirror/iso/VER"
dflybsd_iso="$dflybsd_mirror/iso-images"
Any update to use something like those options on the scripts
–extra-args=‘console=tty0 console=ttyS0,115200n8 serial’
–graphics spice port=5930,listen=0.0.0.0,password=‘hiworld’
That one would be tricky to implement as an option because it contains spaces and a various number of arguments. But we could set the extra args in /etc/vm-create.cfg or the user’s ~/.vm-create.cfg in a variable that could be overwritten (or deleted) on the command line - before executing the script.
I noticed that the options --vnc and --sdl are deprecated now. And spice was not supported as I first wrote the script. It needs update indeed. I don’t have time to modify the options now. But one could set SPICE in the config file with the desired options. If this variable exists, it will be used instead of vnc. It’s a temporary hack.
Try adding these lines to ~/.vm-create.cfg (or system wide in /etc/vm-create.cfg):
# Additional kernel command line arguments to pass to the installer
KERNELARGS_DEF="console=tty0 console=ttyS0,115200n8 serial"
# uncomment the followin line to use spice (temporary hack)
SPICE=" --graphics spice port=5930,listen=0.0.0.0,password='hiworld'"
Apply this patch in /usr/bin (or in the directory where you have the script vm-create):
--- vm-create.orig 2012-05-15 02:29:12.607679734 -0700
+++ vm-create 2012-05-15 03:32:24.888987633 -0700
@@ -1,9 +1,9 @@
#! /bin/bash
#: Title : vm-create
#: Date Created: Sat Jan 29 01:54:07 PST 2011
-#: Last Edit : Thu Apr 5 09:32:14 PDT 2012
+#: Last Edit : Tue May 15 02:20:03 PDT 2012
#: Author : please_try_again (Agnelo de la Crotche)
-#: Version : 2.5.1
+#: Version : 2.5.2
#: Description : install OS from the Internet or local iso in a kvm vm
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prg=$(basename $0)
@@ -398,13 +398,17 @@
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# display
- $sflag -eq 1 ] && DISPLAYOPTS=" --sdl"
+ "$SPICE" ] && DISPLAYOPTS="$SPICE"
+ $sflag -eq 1 ] && DISPLAYOPTS=" --sdl"
$aflag -ge 1 ] && audio=" --soundhw=$DEF_AUDIO"
+# kernel arguments
+ "${KERNELARGS+x}" == "x" ] && -z "$KERNELARG" ] || KERNELARGS=${KERNELARGS:-$KERNELARGS_DEF}
+ "$KERNELARGS" ] && EXTRAOPTS=" --extra_args='$KERNELARGS'"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if $tflag -ge 1 ] ; then
- printf "
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description=\"$desc\"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
" | sed 's|--|
--|g'
+ printf "
virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description=\"$desc\"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS}${EXTRAOPTS} --name=$vm
" | sed 's|--|
--|g'
"$DISTURL" ] && printf "iso URL: %s
" $DISTURL
else
- virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description="$desc"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS} --name=$vm
+ virt-install --connect=$hyp --ram=$ram --arch=$arch --vcpus=$DEF_CPUS --video=$video${audio} --description="$desc"${ostype}${url}${ACPI}${BOOTOPTS}${DISKOPTS}${NETOPTS}${DISPLAYOPTS}${EXTRAOPTS} --name=$vm
fi
This command should now print the following:
$ vm-create -t -s 8 -S -b br0 -u opensuse oscar
virt-install
--connect=qemu:///system
--ram=1024
--arch=i386
--vcpus=1
--video=vga
--soundhw=default
--description="oscar (opensuse 12.1) - vm guest on host neelix"
--os-variant=virtio26
--cdrom=/misc/iso/openSUSE-12.1-NET-i586.iso
--boot=cdrom,hd,network
--disk path=/misc/vm/oscar_hd0.img,size=8
--network bridge=br0
--graphics spice port=5930,listen=0.0.0.0,password='hiworld'
--extra_args='console=tty0 console=ttyS0,115200n8 serial'
--name=oscar
iso URL: http://download.opensuse.org/distribution/12.1/iso/openSUSE-12.1-NET-i586.iso
To execute virt-install with thes options, just remove the option -t.
To modify or delete the extra args, set KERNELARGS either to another value or to an empty string. Example:
$ env KERNELARGS="" vm-create -t -s 8 -S -b br0 -u opensuse oscar
virt-install
--connect=qemu:///system
--ram=1024
--arch=i386
--vcpus=1
--video=vga
--soundhw=default
--description="oscar (opensuse 12.1) - vm guest on host neelix"
--os-variant=virtio26
--cdrom=/misc/iso/openSUSE-12.1-NET-i586.iso
--boot=cdrom,hd,network
--disk path=/misc/vm/oscar_hd0.img,size=8
--network bridge=br0
--graphics spice port=5930,listen=0.0.0.0,password='hiworld'
--name=oscar
iso URL: http://download.opensuse.org/distribution/12.1/iso/openSUSE-12.1-NET-i586.iso
or
$ env KERNELARGS="some options" vm-create -t -s 8 -S -b br0 -u opensuse oscar
virt-install
--connect=qemu:///system
--ram=1024
--arch=i386
--vcpus=1
--video=vga
--soundhw=default
--description="oscar (opensuse 12.1) - vm guest on host neelix"
--os-variant=virtio26
--cdrom=/misc/iso/openSUSE-12.1-NET-i586.iso
--boot=cdrom,hd,network
--disk path=/misc/vm/oscar_hd0.img,size=8
--network bridge=br0
--graphics spice port=5930,listen=0.0.0.0,password='hiworld'
--extra_args='some options'
--name=oscar
iso URL: http://download.opensuse.org/distribution/12.1/iso/openSUSE-12.1-NET-i586.iso
…
Apply this patch in /usr/bin (or in the directory where you have the script vm-create):
…
the patch seems to indicate there is a version 2.5.x, but the last version available on the page is 2.3.
is the script now available somewhere else ?
P
on Opensuse 12.3 i get this :
vi bin/vm-create testvm -r 2048 -a i386 -o winxp -i /dev/null
VIM - Vi IMproved 7.3 (2010 Aug 15)
Unknown option argument: "-a"
More info with: "vim -h"
I can’t seem to work out where in the script vi/vim is called/used.
p