From bf1918204f650f18efe216a86118fa9f8d11b2d0 Mon Sep 17 00:00:00 2001 From: Peter Dahlberg Date: Fri, 5 Apr 2013 20:27:21 +0200 Subject: [PATCH] Ein Zwischenstand einfach mal so --- mc-vm-manager/VMHelper.py | 129 +++++++++++++++++++++++++++++++++----- mc-vm-manager/config.json | 52 +++++++++++++++ mc-vm-manager/manager.py | 68 ++++++++++++-------- 3 files changed, 208 insertions(+), 41 deletions(-) create mode 100644 mc-vm-manager/config.json diff --git a/mc-vm-manager/VMHelper.py b/mc-vm-manager/VMHelper.py index 3c86e6d..2c743b3 100644 --- a/mc-vm-manager/VMHelper.py +++ b/mc-vm-manager/VMHelper.py @@ -1,6 +1,64 @@ -class VMHelper: +import json +import subprocess +import os, errno + +class VMHelper: + def __init__(self): + self.config = json.load(open("/root/tmp/config.json")) + + def getPid(self,vmid): + result = None + try: + with open(self.config['kvm']['pidfile'].replace("$VMID", vmid)) as pidfd: + firstline = pidfd.readline().strip() + result = int(firstline) if firstline.isdigit() else None + except IOError: + pass + return result + + + def process_running(self,vmid): + + pid = self.getPid(vmid) + + if pid is None: + return False + + result = None + try: + os.kill(pid,0) + except OSError as e: + result = e.errno != errno.ESRCH + else: + result = True + + return result + + def startVM(self, vmid): + self.setupNetwork(vmid) + cmd = [] + cmd.append(self.config['kvm']['executable']) + cmd.append(vmid) + + cmd.append("-pidfile") + cmd.append(self.config['kvm']['pidfile'].replace("$VMID", vmid)) + + cmd.append("-qmp") + cmd.append("unix:" + self.config['kvm']['qmpsocket'].replace("$VMID", vmid) + ",server,nowait") + + default_args = self.config['kvm']['default_args'].replace("$VMID", vmid) + cmd += default_args.split() + cmd += self.createArguments(vmid).split() + #print(" ".join(cmd)) + subprocess.Popen(cmd, stdout=open("/dev/null"), stderr=open("/dev/null")) + #subprocess.call(cmd) + + def createArguments(self, vmid): + if ('VMs' in self.config) and (vmid in self.config['VMs']): + config = self.config['VMs'][vmid] + else: + raise Exception("No such VM configuration") - def createArguments(self, config): args = "" if ('cpu' in config): args += " -cpu " + config['cpu'] @@ -26,7 +84,7 @@ class VMHelper: args += " -net tap,vlan=1" if ('dev' in net): args += ",ifname=" + net['dev'] - args += ",script=no" + args += ",script=no,downscript=no" if ('vnc' in config): vnc = config['vnc'] if ('display' in vnc): @@ -39,23 +97,62 @@ class VMHelper: args += " -append \"" + config['append'] + "\"" return args - def setupNetwork(self, config): - foo = "" + def setupNetwork(self, vmid): + if ('VMs' in self.config) and (vmid in self.config['VMs']): + config = self.config['VMs'][vmid] + else: + raise Exception("No such VM configuration") + + commands = [] if ('network' in config): net = config['network'] if ('dev' in net): - foo += "tunctl -d " + net['dev'] + "\n" - foo += "ip link set dev " + net['dev'] +" up\n" - foo += "ip addr add dev " + net['dev'] +" 0.0.0.0\n" + commands.append(["tunctl", "-t", net['dev']]) + commands.append(["ip", "link", "set", "dev", net['dev'], "up"]) + commands.append(["ip", "addr", "add", "dev", net['dev'], "0.0.0.0"]) + + chain = "VMNET-FWD-" + vmid.upper() + + commands.append(["iptables", "--new-chain", chain]) if ('ip' in net): for ip in net['ip']: - foo += "ip route add " + ip + " dev " + net['dev'] + "\n" - # TODO create extra chain - foo += "iptables -A FORWARD -i " + net['dev'] + " -s " + ip + " -j ACCEPT\n" - foo += "iptables -A FORWARD -i " + net['dev'] + " -j REJECT --reject-with icmp-admin-prohibited\n" + commands.append(["ip", "route", "add", ip, "dev", net['dev']]) + commands.append(["iptables", "-A", chain, "-i", net['dev'], "-s", ip, "-j", "ACCEPT"]) + commands.append(["iptables", "-A", chain, "-i", net['dev'], "-j", "REJECT", "--reject-with", "icmp-admin-prohibited"]) + commands.append(["iptables", "-A", "FORWARD", "-j", chain]) + + commands.append(["ip6tables", "--new-chain", chain]) if ('ipv6' in net): for ipv6 in net['ipv6']: - foo += "ip -6 route add " + ipv6 + " dev " + net['dev'] + "\n" - foo += "ip6tables -A FORWARD -i " + net['dev'] + " -s " + ipv6 + " -j ACCEPT\n" - foo += "iptables -A FORWARD -i " + net['dev'] + " -j REJECT --reject-with icmp6-adm-prohibited\n" - return foo + commands.append( ["ip", "-6", "route", "add", ipv6, "dev", net['dev']]) + commands.append(["ip6tables", "-A", chain, "-i", net['dev'], "-s", ipv6, "-j", "ACCEPT"]) + commands.append(["ip6tables", "-A", chain, "-i", net['dev'], "-j", "REJECT", "--reject-with", "icmp6-adm-prohibited"]) + commands.append(["ip6tables", "-A", "FORWARD", "-j", chain]) + + for cmd in commands: + subprocess.call(cmd, stdout=open("/dev/null")) + + def teardownNetwork(self, vmid): + if ('VMs' in self.config) and (vmid in self.config['VMs']): + config = self.config['VMs'][vmid] + else: + raise Exception("No such VM configuration") + + commands = [] + if ('network' in config): + net = config['network'] + if ('dev' in net): + commands.append(["tunctl", "-d", net['dev']]) + + chain = "VMNET-FWD-" + vmid.upper() + + commands.append(["iptables", "-F", chain]) + commands.append(["iptables", "-D", "FORWARD", "-j", chain]) + commands.append(["iptables", "--delete-chain", chain]) + + commands.append(["ip6tables", "-F", chain]) + commands.append(["ip6tables", "-D", "FORWARD", "-j", chain]) + commands.append(["ip6tables", "--delete-chain", chain]) + + for cmd in commands: + subprocess.call(cmd, stdout=open("/dev/null")) diff --git a/mc-vm-manager/config.json b/mc-vm-manager/config.json new file mode 100644 index 0000000..a9b742e --- /dev/null +++ b/mc-vm-manager/config.json @@ -0,0 +1,52 @@ +{ + "kvm": { + "executable": "/root/tmp/qemu-wrapper.sh", + "default_args" : "", + "pidfile": "/tmp/$VMID.pid", + "qmpsocket" : "/tmp/$VMID.qmp" + }, + "VMs": { + "foo": { + "cpu": "kvm64", + "smp": 2, + "memory": 2048, + "disk": { + "hw": "virtio", + "file": "/dev/mapper/vg3-foo" + }, + "cdrom": "/pub/debian.iso", + "network": { + "hw": "virtio", + "dev": "tap-foo", + "mac": "54:52:00:00:01:01", + "ip": ["192.0.2.23", "192.0.2.24"], + "ipv6": ["2001:db8::/80"] + }, + "vnc": { + "display": 1 + }, + "keyboard" : "de", + "kernel": "/home/markus/kernel-3.8.5", + "append": "root=/dev/vda", + "owner": "markus" + }, + "bar": { + "cpu": "kvm64", + "smp": 2, + "memory": 2048, + "cdrom": "/root/tmp/install-amd64-minimal-20130207.iso", + "network": { + "hw": "virtio", + "dev": "tap-foo", + "mac": "54:52:00:00:01:01", + "ip": ["192.0.2.23", "192.0.2.24"] + }, + "vnc": { + "display": 2 + }, + "keyboard" : "de", + "owner": "markus" + } + } +} + diff --git a/mc-vm-manager/manager.py b/mc-vm-manager/manager.py index 3bc4809..bcdacd0 100755 --- a/mc-vm-manager/manager.py +++ b/mc-vm-manager/manager.py @@ -2,43 +2,61 @@ import argparse import sys +from VMHelper import VMHelper + +helper = None def vmm_start(args): - if args.v >= 1: - print('Starting VM {0.vmid}.'.format(args)) + print('Starting VM {0.vmid}.'.format(args)) + helper.startVM(args.vmid) def vmm_stop(args): - if args.v >= 1: - print('Stopping VM {0.vmid}.'.format(args)) + print('Stopping VM {0.vmid}.'.format(args)) + helper.stopVM(args['vmid']) def vmm_status(args): - if args.v >= 2: - print('Gathering status information for VM {0.vmid}.'.format(args)) + if args.v >= 1: + print('Gathering status information for VM {0.vmid}.'.format(args)) + + print("VM ID: {0}".format(args.vmid)) + print("Qemu process is running: " + ("yes (pid: {0})".format(helper.getPid(args.vmid)) if helper.process_running(args.vmid) else "no")) + +def vmm_cleanup(args): + print('Cleaning up for VM {0.vmid}.'.format(args)) + helper.teardownNetwork(args.vmid) def main(): - print("MC VM Manager v0.1\nCopyright (c) M. Hauschild, 2013.\n") + global helper - parser = argparse.ArgumentParser(prog='bkvmm', description='Manages VMs') - subparsers = parser.add_subparsers(title='subcommands') - parser.add_argument('-v', action='count', default=0, help='increase verbosity') + print("MC VM Manager v0.1\nCopyright (c) M. Hauschild and P. Dahlberg 2013.\n") - parser_start = subparsers.add_parser('start', help='starts a VM') - parser_start.add_argument('vmid', action='store', help='the ID of the VM') - parser_start.add_argument('-v', action='count', default=0, help='increase verbosity') - parser_start.set_defaults(func=vmm_start) + parser = argparse.ArgumentParser(prog='mcvmm', description='Manages VMs') + subparsers = parser.add_subparsers(title='subcommands') + parser.add_argument('-v', action='count', default=0, help='increase verbosity') - parser_stop = subparsers.add_parser('stop', help='stop a VM') - parser_stop.add_argument('vmid', action='store', help='the ID of the VM') - parser_stop.add_argument('-v', action='count', default=0, help='increase verbosity') - parser_stop.set_defaults(func=vmm_stop) + parser_start = subparsers.add_parser('start', help='starts a VM') + parser_start.add_argument('vmid', action='store', help='the ID of the VM') + parser_start.set_defaults(func=vmm_start) - parser_status = subparsers.add_parser('status', help='statuss a VM') - parser_status.add_argument('-v', action='count', help='increase verbosity') - parser_status.add_argument('vmid', action='store', default=0, help='the ID of the VM') - parser_status.set_defaults(func=vmm_status) + parser_stop = subparsers.add_parser('stop', help='stop a VM') + parser_stop.add_argument('vmid', action='store', help='the ID of the VM') + parser_stop.set_defaults(func=vmm_stop) - args = parser.parse_args() - args.func(args) + parser_status = subparsers.add_parser('status', help='status a VM') + parser_status.add_argument('-v', action='count', help='increase verbosity') + parser_status.add_argument('vmid', action='store', default=0, help='the ID of the VM') + parser_status.set_defaults(func=vmm_status) + + parser_cleanup = subparsers.add_parser('cleanup', help='cleans up stuff for a VM') + parser_cleanup.add_argument('vmid', action='store', default=0, help='the ID of the VM') + parser_cleanup.set_defaults(func=vmm_cleanup) + + helper = VMHelper() + + args = parser.parse_args() + + #TODO abfrage ob vmid existiert + args.func(args) if __name__ == '__main__': - main() + main()