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
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.
Previously we had the following definition :
1cat labconfig.yaml 2lab: 3 vsphere: 4 vcenter: 5 ip: 192.168.10.11 6 user: email@example.com 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: firstname.lastname@example.org 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.
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.
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 try … except 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
At this point we can extend our initial program to include the following functionality :
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.
$ ./buildLabConfig.py Connecting to 192.168.10.11 using username email@example.com /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.
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 firstname.lastname@example.org /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 :