#!/usr/bin/python2
# 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 <http://www.gnu.org/licenses/>.

import argparse
import errno
import os
import subprocess
import sys
import re

from verify import parent
import testvm

NETWORK_SCRIPT="""
    set -ex
    /bin/virsh net-destroy cockpit1 || true
    /bin/virsh net-undefine cockpit1 || true
    /bin/virsh net-define /dev/stdin <<EOF

<network ipv6='yes'>
  <name>cockpit1</name>
  <uuid>f3605fa4-0763-41ea-8143-49da3bf73263</uuid>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <bridge name='cockpit1' stp='on' delay='0' />
  <domain name='cockpit.lan'/>
  <ip address='10.111.112.1' netmask='255.255.240.0'>
    <dhcp xmlns:cockpit="urn:cockpit-project.org:cockpit">
      <range start="10.111.112.2" end="10.111.127.254" />
    </dhcp>
  </ip>
  <ip family="ipv6" address="fd00:111:112::1" prefix="64"/>
</network>
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

    /bin/virsh net-autostart cockpit1
    /bin/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('-C', '--cpus', default=None, type=int, help='Number of cpus in the target machine')
parser.add_argument('--network', action='store_true', help='Setup a bridged network for running machines')

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

    network = testvm.VirtNetwork(0, bridge=bridge)

    machine = testvm.VirtMachine(verbose=args.verbose, image=args.image, maintain=args.maintain,
                                 networking=network.host(), memory_mb=memory, cpus=args.cpus)

    # 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(parent.BOTS_DIR, "images", "files", "openshift.kubeconfig"))
            if not os.path.exists(d):
                os.makedirs(d)
            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(parent.BOTS_DIR, "image-download"), args.image])
        except OSError as ex:
            if ex.errno != errno.ENOENT:
                raise
        else:
            if ret != 0:
                sys.exit(ret)

    machine.start()

    # for a bridged network, up its interface with DHCP and show it in the console message
    message = ""
    if args.network and bridge:
        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 "windows" in args.image:
        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)
