MrPointy's journey designing, building and deploying private clouds

Managing vSphere with pyVmomi - Part 4 - Adding a NFS share to a Cluster of Hosts

2015-10-24

This post is part 4 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, Part 2 or Part 3

Updating our YAML file

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 such that NFS shared storage can be associated with the Clusters.

YAML configuration file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
cat labconfig.yaml
lab:
vsphere:
host:
-
ip: 192.168.10.101
hostname: "beast1.example.com"
user: root
pw: vmware123
-
ip: 192.168.10.102
hostname: "beast2.example.com"
user: root
pw: vmware123
vcenter:
ip: 192.168.10.11
user: administrator@vsphere.local
pw: vmware
topology:
- dc:
name: LABDC
clusters:
- name: LABC
datastore:
type: nfs
ip: 192.168.10.66
path: /mnt/vol1/VMWARE-NFS
name: NAS
members:
- ip: 192.168.10.101
- ip: 192.168.10.102

As you can see, a simple change has been made to associate a NAS share with the cluster.

Adding a NAS Datastore to a host

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def create_nasdatastore(self, host_name, nas_ip, nas_mount, datastore_name):
if datastore_name is None:
raise ValueError("Missing value for datastore_name.")
if nas_ip is None:
raise ValueError("Missing value for nas_ip.")
if nas_mount is None:
raise ValueError("Missing value for nas_mount.")
if host_name is None:
raise ValueError("Missing value for host_name.")
print(host_name)
host = self.get_obj([self.pyVmomi.vim.HostSystem], host_name)
datastore_spec = self.pyVmomi.vim.host.NasVolume.Specification()
datastore_spec.remoteHost=nas_ip
datastore_spec.remotePath=nas_mount
datastore_spec.localPath=datastore_name
datastore_spec.accessMode="readWrite"
datastore=host.configManager.datastoreSystem.CreateNasDatastore(datastore_spec)
return datastore

By now, you’re most likely getting the hang of the pyVmomi implementation of the vSphere API. You can see from the above code we create a specification for a new NasVolume and then call the CreateNasDarastore mthod using that specification as input

Here is the updated program :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#!/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
import time
import subprocess
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 add_host(self, cluster_name, hostname, sslthumbprint, username, password):
host = self.get_obj([self.pyVmomi.vim.HostSystem], hostname)
if host is not None:
print("host already exists")
return host
else:
if hostname is None:
raise ValueError("Missing value for name.")
cluster = self.get_obj([self.pyVmomi.vim.ClusterComputeResource], cluster_name)
if cluster is None:
error = 'Error - Cluster %s not found. Unable to add host %s' % (cluster_name, hostname)
raise ValueError(error)
try:
hostspec = self.pyVmomi.vim.host.ConnectSpec(hostName=hostname,userName=username, sslThumbprint=sslthumbprint, password=password, force=True)
task=cluster.AddHost(spec=hostspec,asConnected=True)
except self.pyVmomi.vmodl.MethodFault as error:
print "Caught vmodl fault : " + error.msg
return -1
self.wait_for_task(task)
host = self.get_obj([self.pyVmomi.vim.HostSystem], hostname)
return host
def create_nasdatastore(self, host_name, nas_ip, nas_mount, datastore_name):
if datastore_name is None:
raise ValueError("Missing value for datastore_name.")
if nas_ip is None:
raise ValueError("Missing value for nas_ip.")
if nas_mount is None:
raise ValueError("Missing value for nas_mount.")
if host_name is None:
raise ValueError("Missing value for host_name.")
print(host_name)
host = self.get_obj([self.pyVmomi.vim.HostSystem], host_name)
datastore_spec = self.pyVmomi.vim.host.NasVolume.Specification()
datastore_spec.remoteHost=nas_ip
datastore_spec.remotePath=nas_mount
datastore_spec.localPath=datastore_name
datastore_spec.accessMode="readWrite"
datastore=host.configManager.datastoreSystem.CreateNasDatastore(datastore_spec)
return datastore
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 wait_for_task(self, task):
while task.info.state == (self.pyVmomi.vim.TaskInfo.State.running or self.pyVmomi.vim.TaskInfo.State.queued):
time.sleep(2)
if task.info.state == self.pyVmomi.vim.TaskInfo.State.success:
if task.info.result is not None:
out = 'Task completed successfully, result: %s' % (task.info.result,)
print out
elif task.info.state == self.pyVmomi.vim.TaskInfo.State.error:
out = 'Error - Task did not complete successfully: %s' % (task.info.error,)
raise ValueError(out)
return task.info.result
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 getsslThumbprint(self,ip):
p1 = subprocess.Popen(('echo', '-n'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen(('openssl', 's_client', '-connect', '{0}:443'.format(ip)), stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p3 = subprocess.Popen(('openssl', 'x509', '-noout', '-fingerprint', '-sha1'), stdin=p2.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out = p3.stdout.read()
ssl_thumbprint = out.split('=')[-1].strip()
return ssl_thumbprint
def main():
config = yaml.load(open("labconfig.yaml"))
vc=Vcenter(config["lab"]["vsphere"]["vcenter"]);
dc=config["lab"]["vsphere"]["topology"]
hostlist = config['lab']['vsphere']['host']
# 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)
if j.has_key('members') :
for k in j['members']:
iptoadd=None
user=None
pw=None
for l in hostlist: # lookup the member details in the hosts section in the YAML to find the
if l['ip']==k['ip']: #
iptoadd=l['ip'] #
user=l['user'] # user and pasword details
pw=l['pw']
if iptoadd == None:
print("Couldnt find credentials for ip %s" % k['ip'])
else:
sslthumbprint=vc.getsslThumbprint(iptoadd)
vc.add_host(j['name'],iptoadd,sslthumbprint,user,pw)
vc.create_nasdatastore(iptoadd,j['datastore']['ip'],j['datastore']['path'],j['datastore']['name'])
return 0
# Start program
if __name__ == "__main__":
main()
  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