Skip to content

Commit 8d1f1a6

Browse files
committed
Merge pull request apache#1464 from sanju1010/vcenter
[CLOUDSTACK-9337]Enhance vcenter.py to create data center in vcenter server automaticallyThese changes have been made to support vmware deployments in CI. For CI to create cloudstack setup with vmware, it is required to create datacenter, cluster and hosts in vcenter server before adding in cloudstack. Added few methods in vcenter.py to perform these tasks. Please refer to CLOUDSTACK-9337 for more details. * pr/1464: [CLOUDSTACK-9337]Enhance vcenter.py to created data center in vcenter server automatically (Programmatically) Signed-off-by: Rajani Karuturi <rajani.karuturi@accelerite.com>
2 parents f3b132f + 8daaa30 commit 8d1f1a6

1 file changed

Lines changed: 164 additions & 5 deletions

File tree

tools/marvin/marvin/lib/vcenter.py

Lines changed: 164 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,28 @@
1919
from pyVim import connect
2020
import atexit
2121
import ssl
22-
if hasattr(ssl, '_create_unverified_context'):
23-
ssl._create_default_https_context = ssl._create_unverified_context
22+
import subprocess
23+
import time
24+
import json
2425

26+
if hasattr(ssl, '_create_unverified_context'):
27+
ssl._create_default_https_context = ssl._create_unverified_context()
2528

2629
class Vcenter():
2730

2831
def __init__(self, host, user, pwd):
2932
"""
3033
create a service_instance object
3134
"""
32-
self.service_instance = connect.SmartConnect(host=host,
33-
user=user,
34-
pwd=pwd)
35+
if hasattr(ssl, '_create_default_https_context'):
36+
self.service_instance = connect.SmartConnect(host=host,
37+
user=user,
38+
pwd=pwd,
39+
sslContext=ssl._create_default_https_context)
40+
else:
41+
self.service_instance = connect.SmartConnect(host=host,
42+
user=user,
43+
pwd=pwd)
3544
atexit.register(connect.Disconnect, self.service_instance)
3645

3746
@staticmethod
@@ -183,7 +192,157 @@ def get_clusters(self, dc, clus=None):
183192
"""
184193
pass
185194

195+
def create_datacenter(self, dcname=None, service_instance=None, folder=None):
196+
"""
197+
Creates a new datacenter with the given name.
198+
Any % (percent) character used in this name parameter must be escaped,
199+
unless it is used to start an escape sequence. Clients may also escape
200+
any other characters in this name parameter.
201+
202+
An entity name must be a non-empty string of
203+
less than 80 characters. The slash (/), backslash (\) and percent (%)
204+
will be escaped using the URL syntax. For example, %2F
205+
206+
This can raise the following exceptions:
207+
vim.fault.DuplicateName
208+
vim.fault.InvalidName
209+
vmodl.fault.NotSupported
210+
vmodl.fault.RuntimeFault
211+
ValueError raised if the name len is > 79
212+
https://github.com/vmware/pyvmomi/blob/master/docs/vim/Folder.rst
213+
214+
Required Privileges
215+
Datacenter.Create
216+
217+
:param folder: Folder object to create DC in. If None it will default to
218+
rootFolder
219+
:param dcname: Name for the new datacenter.
220+
:param service_instance: ServiceInstance connection to a given vCenter
221+
:return:
222+
"""
223+
if len(dcname) > 79:
224+
raise ValueError("The name of the datacenter must be under "
225+
"80 characters.")
226+
227+
if folder is None:
228+
folder = self.service_instance.content.rootFolder
229+
230+
if folder is not None and isinstance(folder, vim.Folder):
231+
dc_moref = folder.CreateDatacenter(name=dcname)
232+
return dc_moref
233+
234+
def create_cluster(self, cluster_name, datacenter):
235+
"""
236+
Method to create a Cluster in vCenter
237+
238+
:param cluster_name: Name of the cluster
239+
:param datacenter: Name of the data center
240+
:return: Cluster MORef
241+
"""
242+
# cluster_name = kwargs.get("name")
243+
# cluster_spec = kwargs.get("cluster_spec")
244+
# datacenter = kwargs.get("datacenter")
245+
246+
if cluster_name is None:
247+
raise ValueError("Missing value for name.")
248+
if datacenter is None:
249+
raise ValueError("Missing value for datacenter.")
250+
251+
cluster_spec = vim.cluster.ConfigSpecEx()
252+
253+
host_folder = datacenter.hostFolder
254+
cluster = host_folder.CreateClusterEx(name=cluster_name, spec=cluster_spec)
255+
return cluster
256+
257+
def add_host(self, cluster, hostname, sslthumbprint, username, password):
258+
"""
259+
Method to add host in a vCenter Cluster
260+
261+
:param cluster_name
262+
:param hostname
263+
:param username
264+
:param password
265+
"""
266+
if hostname is None:
267+
raise ValueError("Missing value for name.")
268+
try:
269+
hostspec = vim.host.ConnectSpec(hostName=hostname,
270+
userName=username,
271+
sslThumbprint=sslthumbprint,
272+
password=password,
273+
force=True)
274+
task = cluster.AddHost(spec=hostspec, asConnected=True)
275+
except Exception as e:
276+
print "Error adding host :%s" % e
277+
self.wait_for_task(task)
278+
host = self._get_obj([vim.HostSystem], hostname)
279+
return host
280+
281+
def create_datacenters(self, config):
282+
"""
283+
Method to create data centers in vCenter server programmatically
284+
It expects configuration data in the form of dictionary.
285+
configuration file is same as the one we pass to deployDataCenter.py for creating
286+
datacenter in CS
287+
288+
:param config:
289+
:return:
290+
"""
291+
zones = config['zones']
292+
try:
293+
for zone in zones:
294+
dc_obj = self.create_datacenter(zone['name'])
295+
for pod in zone['pods']:
296+
for cluster in pod['clusters']:
297+
clustername = cluster['clustername'].split('/')[-1]
298+
cluster_obj = self.create_cluster(
299+
cluster_name=clustername,
300+
datacenter=dc_obj
301+
)
302+
for host in cluster['hosts']:
303+
host_ip = host['url'].split("//")[-1]
304+
user = host['username']
305+
passwd = host['password']
306+
sslthumbprint=self.getsslThumbprint(host_ip)
307+
self.add_host(cluster=cluster_obj,
308+
hostname=host_ip,
309+
sslthumbprint=sslthumbprint,
310+
username=user,
311+
password=passwd)
312+
except Exception as e:
313+
print "Failed to create datacenter: %s" % e
314+
315+
def wait_for_task(self, task):
316+
317+
while task.info.state == (vim.TaskInfo.State.running or vim.TaskInfo.State.queued):
318+
time.sleep(2)
319+
320+
if task.info.state == vim.TaskInfo.State.success:
321+
if task.info.result is not None:
322+
out = 'Task completed successfully, result: %s' % (task.info.result,)
323+
print out
324+
elif task.info.state == vim.TaskInfo.State.error:
325+
out = 'Error - Task did not complete successfully: %s' % (task.info.error,)
326+
raise ValueError(out)
327+
return task.info.result
328+
329+
def getsslThumbprint(self,ip):
186330

331+
p1 = subprocess.Popen(('echo', '-n'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
332+
p2 = subprocess.Popen(('openssl', 's_client', '-connect', '{0}:443'.format(ip)),
333+
stdin=p1.stdout,
334+
stdout=subprocess.PIPE,
335+
stderr=subprocess.PIPE
336+
)
337+
p3 = subprocess.Popen(('openssl', 'x509', '-noout', '-fingerprint', '-sha1'),
338+
stdin=p2.stdout,
339+
stdout=subprocess.PIPE,
340+
stderr=subprocess.PIPE
341+
)
342+
out = p3.stdout.read()
343+
ssl_thumbprint = out.split('=')[-1].strip()
344+
return ssl_thumbprint
345+
187346
if __name__ == '__main__':
188347
vc_object = Vcenter("10.x.x.x", "username", "password")
189348

0 commit comments

Comments
 (0)