Friday, July 20, 2012

Virtual manipulation

Today everything is virtual, phones, services and especially computers!
One of the first companies that realized the potential in virtualization is VMware.

Using their easy-to-use yet powerful software, VMware introduced a product called VMware Workstation to the market that changed the SOHO/SMB industry and ESX that changed the enterprise industry, as we know it.

The basic idea behind it was simple: if you need a software product to run on several environments, why not use the same hardware?

While Workstation allows users to virtualize a couple of virtual machines, ESX can manage hundreds if not thousands of virtual machines. Both products are considered the top-of-the-line today, and set the industry standard.

Each product achieves its performance/scalability by different assumptions on different environments/hardware. Because of that, several features exist on Workstation for smaller scale management, but are not included on the ESX product (which sucks by the way).

Since most of my work involves ESX and I LOVE Workstation, I thought why not try to mix the two to fill in the gaps and allow enterprise users to enjoy the full potential of the VMware product line. as expected, VMware was nice enough to provide admins with a nice, easy-to-use command-line interface. All I have to do is fill in the blanks.

Naturally, I chose Python for the task and created a short wrapper to allow fellow Pythoneers (developers in the Python language) to enjoy a simple API using the command line interface via SSH.

  1: class ESX_Wrapper(object):
  2:   def __init__(self):
  3:     import paramiko
  4:     from string import strip
  5:     self.ssh = paramiko.SSHClient()
  6:     self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  7: 
  8:   def Connect(self, ip, usr, passwd):
  9:     from socket import error
 10:     try:
 11:       print "Establishing SSH connection to the server... ",
 12:       self.ssh.connect(ip, username=usr, password=passwd)
 13: 
 14:     except error:
 15:       print "unreachable!"
 16:       raise SystemExit
 17: 
 18:     except KeyboardInterrupt:
 19:       print "aborted by user!"
 20: 
 21:     else:
 22:       print "done!"
 23: 
 24:   def ListAllVirtualMachines(self):
 25:     stdin, stdout, stderr = self.ssh.exec_command("vim-cmd vmsvc/getallvms")
 26:     vms = stdout.readlines()
 27:     print "\nVirtual Machines\n================\n"
 28:     for i in xrange(len(vms)):
 29:       print vms[i],
 30: 
 31:   def MapVMIDtoNameInDict(self):
 32:     print "\nMapping VMIDs to Names... ",
 33:     stdin, stdout, stderr = self.ssh.exec_command("vim-cmd vmsvc/getallvms")
 34:     vms = stdout.readlines()
 35:     self.dict = {}
 36:     for i in xrange(len(vms)):
 37:       for j in xrange(4):
 38:         if vms[i][j].isdigit() == False:
 39:           if j !=0 and vms[i][j-1].isdigit() == True:
 40:             self.dict.update({int(vms[i][j-1]):self.GetVMName(int(vms[i][j-1]))})
 41:     print "done!"
 42:     return self.dict
 43: 
 44:   def GetVMName(self, vmid):
 45:     command = "vim-cmd vmsvc/get.summary "
 46:     command += str(vmid) + " |grep name |awk -F '\"' \'{print $2}\'"
 47:     stdin, stdout, stderr = self.ssh.exec_command(command)
 48:     return str(stdout.readlines()).strip("[]'\\n")
 49: 
 50:   def GetVMStatus(self, vmid):
 51:     command = "vim-cmd vmsvc/power.getstate " + str(vmid)
 52:     stdin, stdout, stderr = self.ssh.exec_command(command)
 53:     vm_status = stdout.readlines()
 54:     print "\nMachine Status\n=============="
 55:     for i in xrange(len(vm_status)):
 56:       print vm_status[i],
 57: 
 58:   def TurnOffVM(self, vmid):
 59:     command = "vim-cmd vmsvc/power.off " + str(vmid)
 60:     stdin, stdout, stderr = self.ssh.exec_command(command)
 61:     return stdout.readlines()
 62: 
 63:   def ForceVMShutdown(self, vmid):
 64:     command = "vim-cmd vmsvc/shutdown.off " + str(vmid)
 65:     stdin, stdout, stderr = self.ssh.exec_command(command)
 66:     return stdout.readlines()
 67: 
 68:   def TurnOnVM(self, vmid):
 69:     command = "vim-cmd vmsvc/power.on " + str(vmid)
 70:     stdin, stdout, stderr = self.ssh.exec_command(command)
 71:     return stdout.readlines()
 72: 
 73:   def RebootVM(self, vmid):
 74:     command = "vim-cmd vmsvc/power.reboot " + str(vmid)
 75:     stdin, stdout, stderr = self.ssh.exec_command(command)
 76:     return stdout.readlines()
 77: 
 78:   def SuspendVM(self, vmid):
 79:     command = "vim-cmd vmsvc/power.suspend " + str(vmid)
 80:     stdin, stdout, stderr = self.ssh.exec_command(command)
 81:     return stdout.readlines()
 82: 
 83:   def WakeFromSuspend(self, vmid):
 84:     command = "vim-cmd vmsvc/power.on " + str(vmid)
 85:     stdin, stdout, stderr = self.ssh.exec_command(command)
 86:     return stdout.readlines()
 87: 
 88:   def CreateSnapshot(self, vmid, snapshotName, snapshotDesc="", includeMemory=""):
 89:     base_string = str(vmid) + " " + snapshotName
 90:     if snapshotDesc !="":
 91:       base_string = base_string + " " + "\"" + snapshotDesc + "\""
 92: 
 93:     if includeMemory !="":
 94:       base_string = base_string + " " + includeMemory
 95: 
 96:     command = "vim-cmd vmsvc/snapshot.create " + base_string
 97:     stdin, stdout, stderr = self.ssh.exec_command(command)
 98:     return stdout.readlines()
 99: 
100:   def RevertToSnapshot(self, vmid, testid=1, suppressPowerOff="yes"):
101:     base_string = str(vmid) + " " + str(testid) + " " + suppressPowerOff
102:     command = "vim-cmd vmsvc/snapshot.revert " + base_string
103:     stdin, stdout, stderr = self.ssh.exec_command(command)
104:     return stdout.readlines()

The constructor uses the paramiko library to connect to the ESX, and send the command-line requests via SSH. The class may look a bit clumsy, but I prefer it this way for readability.


A sample use of this class:

  1: def main():
  2:   dict = {}
  3:   esx_object = ESX_Wrapper()
  4:   esx_object.Connect("192.168.2.2","root", "password")
  5:   esx_object.ListAllVirtualMachines()
  6:   dict = esx_object.MapVMIDtoNameInDict()
  7:   machine_vmid = raw_input("Specify the machine vmid you wish to turn on: ")
  8:   machine_name = dict[int(machine_vmid)]
  9:   print "Sending TurnOn command to " + machine_name + "... ",
 10:   esx_object.TurnOnVM(machine_vmid)
 11:   print "sent!"
 12: 
 13: if __name__ == '__main__':
 14:   main()

Hope you’ll find it useful as I did…


Cheers,
at0m q[^_^]p