Thursday, August 14, 2014

Python sort list of SNAPSHOT versions

Problem Description:
Return unexpected order when using sorted(unsorted_list, reverse=True) for snapshot versions. For example:
unsorted_list
[
'1.1.7-SNAPSHOT',
'1.1.6-SNAPSHOT',
'1.1.8-SNAPSHOT',
'1.1.9-SNAPSHOT',
'1.1.10-SNAPSHOT'
]

sorted(unsorted_list, reverse=True), return:
[
'1.1.9-SNAPSHOT',
'1.1.8-SNAPSHOT',
'1.1.7-SNAPSHOT',
'1.1.6-SNAPSHOT',
'1.1.10-SNAPSHOT'
]

However, the expected result we want:
[
'1.1.10-SNAPSHOT',
'1.1.9-SNAPSHOT',
'1.1.8-SNAPSHOT',
'1.1.7-SNAPSHOT',
'1.1.6-SNAPSHOT'
]

Existing Solutions:
There are some blogs which can handle above issue by sorting a list in a alphabetical order, links:
http://www.davekoelle.com/alphanum.html
http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/
http://www.interact-sw.co.uk/iangblog/2007/12/13/natural-sorting

I tested this,
def sort_list(unsort_list):
    """
    Sort the given list in the way that humans expect.
    """
    convert = lambda text: int(text) if text.isdigit() else text
    alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
    unsort_list.sort(key=alphanum_key, reverse=True)
Easier Solution:
I tested another easier solution by using LooseVersion library, and it works well.
sorted(unsorted_list, key=LooseVersion, reverse=True)

Note: I have not compared different solutions, and I do not know which one is higher efficiency. But I read a blog, which compared a list of sorting method related with alphabetical human sorting, http://dave.st.germa.in/blog/2007/12/11/exception-handling-slow/. I really hope this will help someone who has this problem later.



Friday, April 11, 2014

pysphere deploy VMs from vm template with customization specification


Background:
    I created a vm template in vcenter through vsphere web client. But when I deployed this vm template to a VM, then the hostname is still the old VM name, which I used it to create vm template, and the IP address is not configued. For my case, I can create and use a customized specification file in my vcenter to fix the hostname, but DHCP is not configured in my working environment, and I have to manually set static IP address for my VMs. I do not like this.

Questions:
  1. What if I want to clone and deploy vm template in an automation way?
  2. How to fix the hostname and IP address issues?
Investigation:
   To make vm template automation, I searched and found some python client libraries:
  • psphere
  • pyvisdk
  • pysphere
  • vijava
    There is a very good blog to compare above four python  ibraries, http://dunniganp.wordpress.com/2012/09/10/comparison-of-python-vmware-vsphere-client-libraries/. I truly recommend to read this.

My Solution:
    For my case, I just picked pysphere to get a solution, and I am lucky to made it.
  1. create vm template based on an existing virtual machine, vm.create_template(args).
  2. deploy vm template to VMs, vm.clone(<target vm name>,<vm resource pool>).
  3. customize hostname and assign IP address, VI.CustomizeVM_TaskRequestMsg().
Examples:
#connect with vmware server:
server=VIServer()
server.connect(<remote host>, <user>, <password>)
# Get vm object
vm_obj = server.get_vm_by_name(target_vm)
# Customize hostname and IP address
        request = VI.CustomizeVM_TaskRequestMsg()
        _this = request.new__this(vm_obj._mor)
        _this.set_attribute_type(vm_obj._mor.get_attribute_type())
        request.set_element__this(_this)
        spec = request.new_spec()
        globalIPSettings = spec.new_globalIPSettings()
        spec.set_element_globalIPSettings(globalIPSettings)
        # NIC settings, I used static ip, but it is able to set DHCP here, but I did not test it.
        nicSetting = spec.new_nicSettingMap()
        adapter = nicSetting.new_adapter()
        fixedip = VI.ns0.CustomizationFixedIp_Def("ipAddress").pyclass()
        fixedip.set_element_ipAddress(ip_address)
        adapter.set_element_ip(fixedip)
        adapter.set_element_subnetMask(netmask)
        nicSetting.set_element_adapter(adapter)
        spec.set_element_nicSettingMap([nicSetting,])
        identity = VI.ns0.CustomizationLinuxPrep_Def("identity").pyclass()
        identity.set_element_domain("domain name")
        hostName = VI.ns0.CustomizationFixedName_Def("hostName").pyclass()
        hostName.set_element_name(target_vm.replace("_", ""))
        identity.set_element_hostName(hostName)
        spec.set_element_identity(identity)
        request.set_element_spec(spec)
        task = server._proxy.CustomizeVM_Task(request)._returnval
        vi_task = VITask(task, server)
        status = vi_task.wait_for_state([vi_task.STATE_SUCCESS, vi_task.STATE_ERROR], <timeout setting>)

Hopefully, this can help people, who have the same problems.