{"id":1583,"date":"2013-08-30T10:59:51","date_gmt":"2013-08-30T17:59:51","guid":{"rendered":"http:\/\/xiehang.com\/blog\/?p=1583"},"modified":"2014-01-28T11:04:44","modified_gmt":"2014-01-28T18:04:44","slug":"play-with-python-on-windows","status":"publish","type":"post","link":"https:\/\/xiehang.com\/blog\/2013\/08\/30\/play-with-python-on-windows\/","title":{"rendered":"Play with Python on Windows"},"content":{"rendered":"

As I mentioned – I’m migrating my sysadm tasks from Perl to Python, and Windows is just one of them.<\/p>\n

This is a real case, I like VirtualBox as a neat visualization container, and spending lot of time on using it, actually there are always 2~3 VMs running on my laptop while another 4~5 lying on HDD. However, I have different requirements for different types of VMs, like for Windows VM, I used to launch them in GUI mode so that I can use another Windows environment, but for Linux and other *nix machines I used to launch them in headless mode and use putty (another neat tool \ud83d\ude42 ) to access.<\/p>\n

The problem is that VirtualBox’s console does not support starting VMs in headless mode, so I created some BAT files to do it, but this makes things complicated that I have to go to two places to do actually one thing.<\/p>\n

Now here comes Python, plus VirtualBox guys kindly released a Python SDK. It was for Python 2.x, but no wonder some smart guy convert it to work with Python 3<\/a>. I was thinking of using win32 binding, but later on found Tkinter is good enough for this purpose. Codes posted below, feel free to take it as long as you can mention my name and link back to this post (I hate GPL … you can guess I’m a fan of BSD).<\/p>\n

I’ll do some more enhancement if I have to, but so far it can show button status based on VM state, and start\/stop\/reset the VMs, that’s pretty all I want at this moment. \ud83d\ude1b
\n[python]
\nimport sys
\nimport tkinter
\nfrom tkinter import messagebox
\nimport vboxapi
\nimport time<\/p>\n

mgr = vboxapi.VirtualBoxManager(None, None)<\/p>\n

def list_vms():
\n global mgr
\n vm_list = []
\n for vm in mgr.getArray(mgr.vbox, ‘machines’):
\n vm_list.append(vm)
\n vm_list = sorted(vm_list, key = lambda k: k.name)
\n return vm_list<\/p>\n

def start_vm(vm_id):
\n global mgr, root, button_list
\n root.config(cursor=’clock’)
\n session = mgr.mgr.getSessionObject(mgr.vbox)
\n try:
\n # start the VM
\n machine = mgr.vbox.FindMachine(vm_id)
\n if mgr.vbox.getGuestOSType(machine.OSTypeId).familyId == ‘Windows’:
\n start_type = ‘gui’
\n else:
\n start_type = ‘headless’
\n progress = machine.launchVMProcess(session, start_type, ”)
\n progress.waitForCompletion(-1)<\/p>\n

# change UI
\n button_list[vm_id][‘start’].config(state=tkinter.DISABLED)
\n button_list[vm_id][‘stop’].config(state=tkinter.NORMAL)
\n except Exception as e:
\n messagebox.showerror(‘Error Happened’, e)
\n finally:
\n if session.state == mgr.constants.SessionState_Locked:
\n session.unlockMachine()
\n root.config(cursor=”)<\/p>\n

def stop_vm(vm_id):
\n global mgr, root
\n root.config(cursor=’clock’)
\n session = mgr.mgr.getSessionObject(mgr.vbox)
\n try:
\n # stop (savestate) the VM
\n mgr.vbox.FindMachine(vm_id).lockMachine(session, mgr.constants.LockType_Shared)
\n session.console.saveState()<\/p>\n

# change UI
\n button_list[vm_id][‘start’].config(state=tkinter.NORMAL)
\n button_list[vm_id][‘stop’].config(state=tkinter.DISABLED)
\n except Exception as e:
\n messagebox.showerror(‘Error Happened’, e)
\n finally:
\n if session.state == mgr.constants.SessionState_Locked:
\n session.unlockMachine()
\n root.config(cursor=”)<\/p>\n

def reset_vm(vm_id):
\n global mgr, root
\n if not messagebox.askyesno(‘Reset VM’, ‘Are you sure?’, default=’no’):
\n return<\/p>\n

root.config(cursor=’clock’)
\n session = mgr.mgr.getSessionObject(mgr.vbox)
\n try:
\n # stop (savestate) the VM
\n mgr.vbox.FindMachine(vm_id).lockMachine(session, mgr.constants.LockType_Shared)
\n session.console.reset()<\/p>\n

# change UI
\n button_list[vm_id][‘start’].config(state=tkinter.DISABLED)
\n button_list[vm_id][‘stop’].config(state=tkinter.NORMAL)
\n except Exception as e:
\n messagebox.showerror(‘Error Happened’, e)
\n finally:
\n if session.state == mgr.constants.SessionState_Locked:
\n session.unlockMachine()
\n root.config(cursor=”)<\/p>\n

def timer():
\n pass
\n global mgr, vm_list, button_list, timer_lbl, root<\/p>\n

# update button status according to VM state
\n for index in range(0, len(vm_list)):
\n if vm_list[index].state == mgr.constants.MachineState_Running:
\n # VM is running
\n button_list[vm_list[index].id][‘start’].config(state=tkinter.DISABLED)
\n button_list[vm_list[index].id][‘stop’].config(state=tkinter.NORMAL)
\n button_list[vm_list[index].id][‘reset’].config(state=tkinter.NORMAL)
\n elif vm_list[index].state == mgr.constants.MachineState_Saved or vm_list[index].state == mgr.constants.MachineState_PoweredOff or vm_list[index].state == mgr.constants.MachineState_Aborted:
\n # VM is not running
\n button_list[vm_list[index].id][‘start’].config(state=tkinter.NORMAL)
\n button_list[vm_list[index].id][‘stop’].config(state=tkinter.DISABLED)
\n button_list[vm_list[index].id][‘reset’].config(state=tkinter.DISABLED)
\n else:
\n # VM is in interim state
\n button_list[vm_list[index].id][‘start’].config(state=tkinter.DISABLED)
\n button_list[vm_list[index].id][‘stop’].config(state=tkinter.DISABLED)
\n button_list[vm_list[index].id][‘reset’].config(state=tkinter.DISABLED)<\/p>\n

# update clock
\n timer_lbl.configure(text=time.strftime(“%Y-%m-%d %H:%M:%S”))
\n root.after(1000, timer)<\/p>\n

vm_list = list_vms()
\nbutton_list = {}
\nroot = tkinter.Tk()
\ntimer_lbl = tkinter.Label(root, text=”, justify=tkinter.RIGHT)
\ntimer_lbl.grid(row=0, columnspan=4, sticky=tkinter.N, padx=10, pady=10)
\nfor index in range(0, len(vm_list)):
\n if vm_list[index].state == mgr.constants.MachineState_Running:
\n start_btn_state = tkinter.DISABLED
\n stop_btn_state = tkinter.NORMAL
\n else:
\n start_btn_state = tkinter.NORMAL
\n stop_btn_state = tkinter.DISABLED<\/p>\n

# VM label
\n lbl = tkinter.Label(root, text=vm_list[index].name)
\n lbl.grid(row=index+1, sticky=tkinter.W, padx=5, pady=5)<\/p>\n

# start button
\n start_btn = tkinter.Button(root, text=’Start’, state=start_btn_state)
\n start_btn[‘command’] = lambda vm_id = vm_list[index].id: start_vm(vm_id)
\n start_btn.grid(row=index+1, column=1, padx=5, pady=5)<\/p>\n

# stop (save state) button
\n stop_btn = tkinter.Button(root, text=’Stop’, state=stop_btn_state)
\n stop_btn[‘command’] = lambda vm_id = vm_list[index].id: stop_vm(vm_id)
\n stop_btn.grid(row=index+1, column=2, padx=5, pady=5)<\/p>\n

# reset (power recycle) button
\n reset_btn = tkinter.Button(root, text=’Reset’, state=stop_btn_state)
\n reset_btn[‘command’] = lambda vm_id = vm_list[index].id: reset_vm(vm_id)
\n reset_btn.grid(row=index+1, column=3, padx=5, pady=5)<\/p>\n

button_list[vm_list[index].id] = {‘start’: start_btn, ‘stop’: stop_btn, ‘reset’: reset_btn}<\/p>\n

timer()
\nroot.bind(‘‘, lambda event: root.quit())
\nroot.mainloop()
\n[\/python]<\/p>\n","protected":false},"excerpt":{"rendered":"

As I mentioned – I’m migrating my sysadm tasks from Perl to Python, and Windows is just one of them. This is a real case, I like VirtualBox as a neat visualization container, and spending lot of time on using it, actually there are always 2~3 VMs running on my laptop while another 4~5 lying […]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[456,27,454,455,38],"_links":{"self":[{"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/posts\/1583"}],"collection":[{"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/comments?post=1583"}],"version-history":[{"count":9,"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/posts\/1583\/revisions"}],"predecessor-version":[{"id":1645,"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/posts\/1583\/revisions\/1645"}],"wp:attachment":[{"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/media?parent=1583"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/categories?post=1583"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/xiehang.com\/blog\/wp-json\/wp\/v2\/tags?post=1583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}