#!/usr/bin/python3
#
# Copyright (C) 2015
# Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
# Authors: Brian C. Lane
#
import os
import subprocess
import argparse
import logging
LVM_POOL_NAME="lvm_virt_pool"
#OVMF_DIR="/usr/share/edk2.git/ovmf-x64/"
OVMF_DIR="/usr/share/OVMF/"
UEFI_FIRMWARE="loader=%(OMVF)s/OVMF_CODE.fd,loader_ro=yes,loader_type=pflash,nvram_template=%(OMVF)s/OVMF_VARS.fd" % {"OMVF": OVMF_DIR}
def main(args):
# Shut down any previous virt
try:
subprocess.check_call(["virsh", "destroy", args.name])
except subprocess.CalledProcessError:
pass
try:
subprocess.check_call(["virsh", "undefine", args.name])
except subprocess.CalledProcessError:
pass
disks = []
for n in range(0,args.disks):
if n:
name = args.name + "-%d" % n
else:
name = args.name
if args.blank:
cmd = ["virsh", "vol-delete", "--pool", LVM_POOL_NAME, name]
logging.debug(cmd)
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError:
pass
disks += ["--disk", "pool=%s,size=%s,bus=virtio" % (LVM_POOL_NAME, args.size)]
else:
disks += ["--disk", "vol=%s/%s,bus=virtio" % (LVM_POOL_NAME, name)]
# Assemble a virt-install commandline
cmd = ["virt-install", "-n", args.name, "-r", args.ram, "--vcpus", args.cpu]
cmd += disks
if args.uefi:
cmd += ["--boot", UEFI_FIRMWARE]
if args.pxe:
cmd += ["--pxe"]
elif args.iso:
cmd += ["--disk=path=%s,device=cdrom,shareable=on,readonly=on" % args.iso]
# Try setting --os-variant
if "fedora" in args.iso.lower():
cmd += ["--os-variant=fedora21"]
elif "rhel6" in args.iso.lower():
cmd += ["--os-variant=rhel6.2"]
elif "rhel7" in args.iso.lower():
cmd += ["--os-variant=rhel7.0"]
# Inject the kickstart into the initrd
if args.kickstart:
cmd += ["--initrd-inject", args.kickstart]
cmd += ["--extra-args", "inst.ks=file:/%s inst.stage2=cdrom:/dev/sr0" % os.path.basename(args.kickstart)]
cmd += ["--location", args.iso]
cmd += ["--network", "bridge=br0", "--rng", "/dev/random"]
cmd += ["--graphics", "vnc", "--video", "vga", "--noautoconsole"]
# Add more nics
for i in range(0, args.nics):
cmd += ["--network", "network=default,model=e1000"]
logging.debug(cmd)
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError as e:
logging.error("%s: %s" % (e, e.output))
def setup_args():
""" Return argparse.Parser object of cmdline."""
parser = argparse.ArgumentParser(description="Run a virt")
parser.add_argument("-b", "--blank", action="store_true", default=False, help="Start with blank disks")
parser.add_argument("-n", "--disks", default=2, type=int, help="Number of disks to start with")
parser.add_argument("-s", "--size", default="10", help="Default size of disks in GiB")
parser.add_argument("-p", "--pxe", action="store_true", default=False, help="pxe boot")
parser.add_argument("-i", "--iso", help="iso to boot")
parser.add_argument("-k", "--kickstart", help="kickstart to inject into initrd, requires an iso")
parser.add_argument("-r", "--ram", default="2048", help="Amount of RAM in Megabytes")
parser.add_argument("-c", "--cpu", default="2", help="Number of CPUs")
parser.add_argument("-u", "--uefi", action="store_true", default=False, help="Boot with UEFI OVMF firmware")
parser.add_argument("--ovmf-dir", help="Directory with OVMF firmware")
parser.add_argument("--nics", type=int, default=0, help="Number of extra nics to add")
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose debugging output")
parser.add_argument("name", help="Name of virt")
args = parser.parse_args()
# Sanity check the args
if args.iso and args.pxe:
args.error("Cannot use --iso and --pxe at the same time.")
elif not args.iso and not args.pxe:
args.error("Need to pass one of --iso or --pxe")
elif args.kickstart and not args.iso:
args.error("--kickstart needs an --iso so it can inject into the initrd")
return args
def setup_logging():
if args.verbose:
level=logging.DEBUG
else:
level=logging.INFO
logging.basicConfig(format='%(levelname)s:%(message)s', level=level)
if __name__=='__main__':
args = setup_args()
setup_logging()
main(args)