Index: vws ================================================================== --- vws +++ vws @@ -1,8 +1,11 @@ #!/usr/bin/python from ConfigParser import ConfigParser +from argparse import ArgumentParser import socket +import errno +import os,sys config=ConfigParser({"SharedVMs":"/var/cache/vws/shared","AutostartVMs":"/var/cache/vws/auto"}) def find_vm(name): search_path=[os.environ['HOME']+"/VWs", config.get("directories","SharedVMs"), config.get("directories","AutostartVMs")] @@ -12,24 +15,151 @@ raise ValueError("Machine "+name+" not found.") def connect_vm(vm_dir): sock=socket.socket(socket.AF_UNIX) sock.connect(vm_dir+"/monitor") + greeting=sock.recv() + return sock + +def send_command(sock,command): + fcntl.flock(sock,fcntl.LOCK_EX) + try: + sock.send(command+"\n") + answer="" + while not answer.endswith("(qemu)"): + chunk=sock.recv() + print "Got chunk = ",repr(chunk) + if chunk == '': + raise IOError("Unexpected EOF From monitor") + answer+=sock.recv() + finally: + fcntl.flock(sock,fcntl.LOCK_UN) + return answer -def get_spice_url(sock): - f=sock.makefile("r") - sock.send("info spice\n") - line="" +def cmd_spiceurl(options): + output=send_command(options.sock,"info spice") url=None - while not line.startswith("(qemu)"): - line=f.getline().strip("\n\r") + for line in output.split("\n"): if url is not None: continue n=line.find("address:") if n != -1: url=line[n+9:] if url.startswith('*:'): url="localhost"+url[1:] - f.close() return "spice://"+url +# +# command implementation +# +def cmd_start(options): + pass +def cmd_stop(options): + send_command(options.sock,'system_powerdown') + +def cmd_reset(options): + send_command(options.sock,'system_reset') +def cmd_cdrom(options): + if options.file is None: + answer=send_command(options.sock,"eject "+options.id) + else: + answer=send_command(options.sock, "change %s %s" % (options.id, + options.file)) + print answer + raise NotImplementedError +def cmd_usb_insert(options): + raise NotImplementedError +def cmd_usb_list(options): + os.system(lspci) + +def cmd_usb_remove(options): + raise NotImplementedError +def cmd_usb_attached(options): + answer=send_command(options.sock,"info usb") + print answer +# +# Utility functions for arg parsing +# +def new_command(cmds,name,**kwargs): + """ + Adds a subparser and adds a machine name argument to it + """ + p=cmds.add_parser(name,**kwargs) + p.add_argument('machine',type=str,help='name of vm to operate on') + return p +# +# arg parsing +# + + + +config=ConfigParser({'SharedVMs':'/var/cache/vws/shared', + 'AuthoStartVMs':'/var/cache/vws/autostart'}) + +config.read(['/etc/vws.conf',os.environ['HOME']+'/.vwsrc']) + +args=ArgumentParser() +cmds=args.add_subparsers(dest='command',help="sub-command help") +# Power management +p=new_command(cmds,'start',help='Start VM and connect to console') +p.add_argument('--no-gui',dest='gui',action='store_const',const=False, + default=True,help='do not open console window') +p.add_argument('--cdrom',dest='cdrom',nargs=1, + help='connect specified iso image to VMs cdrom on start') +# Following commands don't need extra args +new_command(cmds,'stop',help='Shut down virtual machine') +new_command(cmds,'save',help='Save VM state and stop emulation') +new_command(cmds,'reset',help='Reboot a guest OS') +# Removable devices management +p=new_command(cmds,'cdrom',help='manage CDROM Drive') +p.add_argument('--id',type=str,default='cdrom0', + help='Identifier of CDROM drive if VM has more than one') +p.add_argument('file',help='ISO image or special file to connect to drive') +p.add_argument('--eject',dest='file',action='store_const',const=None) +usb=cmds.add_parser('usb').add_subparsers(dest='subcommand',help='manage USB devices') +p=new_command(usb,'insert',help='attach device to the virtual machine') +p.add_argument('pattern',help='Pattern of device name to look up in lsusb') +p.add_argument('--address',nargs=1,help='exact address bus:device') +p=new_command(usb,'remove',help='detach connected usb device') +p.add_argument('pattern',help='Pattern of device name to look up in lsusb') +p.add_argument('--address',nargs=1,help='exact address bus:device') +p=new_command(usb,'attached',help='list devices attached to vm') +usb.add_parser('list',help='list devices available in the host system') +# Snapshot management +p=new_command(cmds,'snapshot',help='Create new snapshot') +p=new_command(cmds,'revert',help='Revert to last snapshot') +p=new_command(cmds,'commit',help='Commit snapshot changes into backing file') +p=new_command(cmds,'snapshots',help='List existing snapshots') +# Screenshoits and recording +p=new_command(cmds,'screenshoot',help='take a screenshot') +p.add_argument('filename',help='image filename to write screenshot to') +p=new_command(cmds,'record',help='Record audio output from VM') +p.add_argument('filename',help='wav file to record autdio to') +new_command(cmds,'stoprecord',help='stop recording audio') +# Miscellenia +p=new_command(cmds,'monitor',help='connect stdin/stdout to monitor of VM') +p=new_command(cmds,'spiceuri',help='Output spice URI of machine') +parsed_args=args.parse_args(sys.argv[1:]) +stopped_vm_commands = ['start','snapshot','revert','commit','snapshots'] +if hasattr(parsed_args,'machine'): + parsed_args.dir=find_vm(parsed_args.machine) + try: + parsed_args.sock=connect_vm(parsed_args.dir) + except IOError as e: + if e.errno == errno.ECONNREFUSED: + # virtal machine is not running + if not parsed_args.command in stopped_vm_commands: + print >>sys.stderr, "Virtual machine %s is not running."%parsed_args.machine + sys.exit(1) + else: + raise e +print repr(parsed_args) +funcname="cmd_"+parsed_args.command +if hasattr(parsed_args."subcommand"): + funcname+="_"+parsed_args.subcommand +try: + func=globals()[funcname] +except KeyError: + print >>sys.stderr,"Operation %s is not implemented"%funcname + sys.exit(3) +func(parsed_args)