#!/usr/bin/python3
# This file is part of Cockpit.
#
# Copyright (C) 2013 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see .
import argparse
import errno
import os
import subprocess
import sys
import re
from machine import testvm
BOTS = os.path.abspath(os.path.dirname(__file__))
NETWORK_SCRIPT=b"""
set -ex
virsh net-destroy cockpit1 || true
virsh net-undefine cockpit1 || true
virsh net-define /dev/stdin <
cockpit1
f3605fa4-0763-41ea-8143-49da3bf73263
EOF
if [ ! -u /usr/libexec/qemu-bridge-helper ]; then
chmod -v u+s /usr/libexec/qemu-bridge-helper
fi
for qemu_config in /etc/qemu-kvm/bridge.conf /etc/qemu/bridge.conf; do
if [ -e "$qemu_config" ] && ! grep -qF cockpit1 "$qemu_config"; then
echo "allow cockpit1" >> "$qemu_config"
fi
done
virsh net-autostart cockpit1
virsh net-start cockpit1
"""
parser = argparse.ArgumentParser(description='Run a test machine')
parser.add_argument('-v', '--verbose', action='store_true', help='Display verbose details')
parser.add_argument('-m', '--maintain', action='store_true', help='Changes are permanent')
parser.add_argument('-M', '--memory', default=None, type=int, help='Memory (in MiB) of the target machine')
parser.add_argument('-G', '--graphics', action='store_true', help='Display a graphics console')
parser.add_argument('-C', '--cpus', default=None, type=int, help='Number of cpus in the target machine')
parser.add_argument('-S', '--storage', default=None, type=str, help='Add a second qcow2 disk at this path')
parser.add_argument('--network', action='store_true', help='Setup a bridged network for running machines')
parser.add_argument('--no-network', action='store_true', help='Do not connect the machine to the Internet')
parser.add_argument('image', help='The image to run')
args = parser.parse_args()
try:
if args.network:
proc = subprocess.Popen(["sudo", "/bin/sh"], stdin=subprocess.PIPE)
proc.communicate(NETWORK_SCRIPT)
if proc.returncode != 0:
sys.stderr.write("vm-run: failed to create cockpit1 network\n")
sys.exit(1)
bridge=None
with open(os.devnull, 'w') as fp:
if subprocess.call(["ip", "address", "show", "dev", "cockpit1"], stdout=fp, stderr=fp) == 0:
bridge = "cockpit1"
# Lets make sure Windows has enough memory to be productive
memory = args.memory
if "windows" in args.image and memory is None:
memory = 4096
graphics = args.graphics or 'windows' in args.image
network = testvm.VirtNetwork(0, bridge=bridge, image=args.image)
machine = testvm.VirtMachine(verbose=args.verbose, image=args.image, maintain=args.maintain,
networking=network.host(restrict=args.no_network),
memory_mb=memory, cpus=args.cpus, graphics=graphics)
# Hack to make things easier for users who don't know about kubeconfig
if 'openshift' in args.image:
kubeconfig = os.path.join(os.path.expanduser("~"), ".kube", "config")
if not os.path.lexists(kubeconfig):
d = os.path.dirname(kubeconfig)
src = os.path.abspath(os.path.join(BOTS, "images", "files", "openshift.kubeconfig"))
os.makedirs(d, exist_ok=True)
sys.stderr.write("image-run: linking kubeconfig into ~/.kube/config\n")
os.symlink(src, kubeconfig)
# Check that image is downloaded
if not os.path.exists(machine.image_file):
try:
ret = subprocess.call([ os.path.join(BOTS, "image-download"), args.image])
except OSError as ex:
if ex.errno != errno.ENOENT:
raise
else:
if ret != 0:
sys.exit(ret)
machine.start()
if args.storage:
machine.add_disk(path=args.storage, type='qcow2')
# for a bridged network, up its interface with DHCP and show it in the console message
message = ""
if args.network and bridge and 'windows' not in args.image:
machine.execute("nmcli connection modify 'System eth1' ipv4.method auto && nmcli connection up 'System eth1'")
output = machine.execute("ip -4 a show dev eth1")
ip = re.search("inet ([^/]+)", output).group(1)
message = "\nBRIDGE IP FROM HOST\n %s\n" % ip
# Graphics console necessary
if graphics:
machine.graphics_console()
# No graphics console necessary
else:
machine.qemu_console(message)
except testvm.Failure as ex:
sys.stderr.write("vm-run: %s\n" % ex)
sys.exit(1)