Managing vSphere with pyVmomi - Part 2 - Adding Datacenters and Clusters

This post is part 2 of a small series of articles about how to use pyVMomi to build, configure and manage vmware vsphere environments.

For more information on the earlier posts please refer to Part 1

Updating our YAML file for Datacenters and Clusters

You will recall that the strategy for our sample program is to encapsulate the configuration we want to achieve in a simple YAML file.

In this section we will extend that YAML file structure noting that in a vSphere environment you may want to create multiple datacenters and multiple clusters. For our design we want to be able to cater for multiple datacenters that may contain zero (or more clusters).

For this post we wont add the hosts into the cluster as we’ll cover that in part 3.

YAML configuration file

Previously we had the following definition :

1cat labconfig.yaml
2lab:
3    vsphere:
4        vcenter:
5                   ip: 192.168.10.11
6                   user: administrator@vsphere.local
7                   pw: vmware

We will now extend this by adding a section for datacenters that may contain cluster definitions.

 1cat labconfig.yaml
 2lab:
 3    vsphere:
 4        vcenter:
 5                   ip: 192.168.10.11
 6                   user: administrator@vsphere.local
 7                   pw: vmware
 8        topology:
 9        -          dc:
10                        name: LABDC
11                        clusters:
12                        -    name: LABC
13        -          dc:
14                        name: LABDC1

As you can see, a topology section has been added. Basically, this allows us to represent multiple ‘dc’ items that can in turn encapsulate multiple (or no) cluster?

Now, let’s look at the code side of things. The YAML parser will take care of capturing our configuration from the labconfig.yaml file. We need to use that information to make the correct calls to the vSphere SDK via pyVmomi.

Before we start we need to have some idea how the objects that we want to create Datacenters and Clusters are reprented in the pyVmomi SDK.

The first place we should look is the github site where the pyVmomi project lives https://github.com/vmware/pyvmomi/.

Let’s drill a little deeper into the documentation and browse through the docs/vim directory. Here we can find considerable documentation on how the vSphere API is mapped to python functions and classes.

A quick browse shows us that we have documentation on Datacenters, Clusters and Folders.

Why Folders?

In vSphere, objects live in folders. You cannot create a datacenter object outside of the folder structure and you can see by browsing the Folder.rst file that CreateCluster is actually a method of the vim.Folder class.

We have discovered that to create a datacenter we need a folder to put it in. What folder should we use? The choice is arbitrary for this blog so we choose the top of the folder hierarchy known as the rootFolder unless we specifically request a folder name.

Handling Errors?

Since we are creating and modifying objects we need a strategy to handle situations when objects pre-exist or cannot be modified.

pyVmomi and python in general offer some easy to grasp strategies. pyVmomi allows us to query the vSphere environment to see if objects exist and python allows us to use tryexcept blocks to recover from faults passed back to us from vSphere.

As Datacenters and Clusters are easily identifiable objects we can search for them by name. If they exist then we’ll leave them alone, otherwise we’ll create them.

To search for objects in pyVmomi we’ll add the following helper function to our VCenter class.

 1    def get_obj(self, vimtype, name):
 2        """
 3        Get the vsphere object associated with a given text name
 4        """
 5        obj = None
 6        container = self.content.viewManager.CreateContainerView(self.content.rootFolder, vimtype, True)
 7        for c in container.view:
 8                if c.name == name:
 9                    obj = c
10                    break
11        return obj

This generic method allows us to query the vSphere environment for an object by name. For example, the following code snippet allows us to query for datacenters by name.

1datacenter = get_obj([vim.Datacenter], "LABDC")
2if datacenter is not None:
3    print("datacenter %s already exists" % dcname)
4    return datacenter
A similar strategy would be used for Clusters, however, in that case the class is vim.ClusterComputerResource

At this point we can extend our initial program to include the following functionality :

  1. Checking to see if a Datacenter exists and if it does not then create it in the root folder.
  2. If required, check to see if a specified cluster exists and if it does not then create it in the specified datacenter.

Here is the complete program :

#!/usr/bin/python
"""
Using the pyVmomi python bindings for vSphere connect to a VCSA and configure Datacenters and Clusters
as per th spefified configuration file.
"""

import atexit
import yaml
import inspect

class Vcenter(object):
    def __init__(self, vcenter_params):
        self.pyVmomi =  __import__("pyVmomi")
        self.server = vcenter_params['ip']
        self.username = vcenter_params['user']
        self.password = vcenter_params['pw']
        self.connect_to_vcenter()


    def create_datacenter(self, dcname=None, folder=None):
        datacenter = self.get_obj([self.pyVmomi.vim.Datacenter], dcname)
        if datacenter is not None:
            print("datacenter %s already exists" % dcname)
            return datacenter
        else:
            if len(dcname) > 79:
                raise ValueError("The name of the datacenter must be under 80 characters.")
            if folder is None:
                folder = self.service_instance.content.rootFolder
            if folder is not None and isinstance(folder, self.pyVmomi.vim.Folder):

                print("Creating Datacenter %s " % dcname )

                dc_moref = folder.CreateDatacenter(name=dcname)
                return dc_moref

    def create_cluster(self, cluster_name, datacenter):

        cluster = self.get_obj([self.pyVmomi.vim.ClusterComputeResource], cluster_name)
        if cluster is not None:
            print("cluster already exists")
            return cluster

        else:
            if cluster_name is None:
                raise ValueError("Missing value for name.")
            if datacenter is None:
                raise ValueError("Missing value for datacenter.")

            print("Creating Cluster %s " % cluster_name )

            cluster_spec = self.pyVmomi.vim.cluster.ConfigSpecEx()

            host_folder = datacenter.hostFolder
            cluster = host_folder.CreateClusterEx(name=cluster_name, spec=cluster_spec)
            return cluster

    def get_obj(self, vimtype, name):
        """
        Get the vsphere object associated with a given text name
        """
        obj = None
        container = self.content.viewManager.CreateContainerView(self.content.rootFolder, vimtype, True)
        for c in container.view:
                if c.name == name:
                    obj = c
                    break
        return obj

    def connect_to_vcenter(self):
        from pyVim import connect

        print("Connecting to %s using username %s" % (self.server, self.username))
        self.service_instance = connect.SmartConnect(host=self.server,
                                                user=self.username,
                                                pwd=self.password,
                                                port=443)
        self.content = self.service_instance.RetrieveContent()
        about = self.service_instance.content.about
        print("Connected to %s, %s" % (self.server, about.fullName))
        atexit.register(connect.Disconnect, self.service_instance)


def main():

    config = yaml.load(open("labconfig.yaml"))

    vc=Vcenter(config["lab"]["vsphere"]["vcenter"]);
    dc=config["lab"]["vsphere"]["topology"]

    # for each datacenter, get the name and optionally if there is a key for clusters 
    # then create matching clusters
    # in this datacenter, otherwise just create the datacenter.

    for i in dc:
       datacenter = vc.create_datacenter(dcname=i['dc']['name'])
       if i['dc'].has_key('clusters') :
          for j in i['dc']['clusters']:
             cluster=vc.create_cluster(j['name'],datacenter)

    return 0

# Start program
if __name__ == "__main__":
    main()

Here is what the VCSA looked like before the job executed.

VCSA Before

$ ./buildLabConfig.py
Connecting to 192.168.10.11 using username administrator@vsphere.local
/usr/lib/python2.7/site-packages/urllib3/connectionpool.py:769: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.org/en/latest/security.html
  InsecureRequestWarning)
Connected to 192.168.10.11, VMware vCenter Server 5.5.0 build-2183111
Creating Datacenter LABDC
Creating Cluster LABC
Creating Datacenter LABDC1

and this is what it looks like after execution.

VCSA After

If the program is executed a second or subsequent time then you will see warnings as follows :

$ ./buildLabConfig.py
Connecting to 192.168.10.11 using username administrator@vsphere.local
/usr/lib/python2.7/site-packages/urllib3/connectionpool.py:769: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.org/en/latest/security.html
  InsecureRequestWarning)
Connected to 192.168.10.11, VMware vCenter Server 5.5.0 build-2183111
datacenter LABDC already exists
cluster already exists
datacenter LABDC1 already exists

Other parts in the series can be found below :

  1. Part 1 :- Connecting to the VCSA
  2. Part 2 :- Creating Datacenters and Clusters
  3. Part 3 :- Adding Hosts to Clusters
  4. Part 4 :- Adding a NFS Share to a Cluster of Hosts