|
19 | 19 | from pyVim import connect |
20 | 20 | import atexit |
21 | 21 | 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 |
24 | 25 |
|
| 26 | +if hasattr(ssl, '_create_unverified_context'): |
| 27 | + ssl._create_default_https_context = ssl._create_unverified_context() |
25 | 28 |
|
26 | 29 | class Vcenter(): |
27 | 30 |
|
28 | 31 | def __init__(self, host, user, pwd): |
29 | 32 | """ |
30 | 33 | create a service_instance object |
31 | 34 | """ |
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) |
35 | 44 | atexit.register(connect.Disconnect, self.service_instance) |
36 | 45 |
|
37 | 46 | @staticmethod |
@@ -183,7 +192,157 @@ def get_clusters(self, dc, clus=None): |
183 | 192 | """ |
184 | 193 | pass |
185 | 194 |
|
| 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): |
186 | 330 |
|
| 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 | + |
187 | 346 | if __name__ == '__main__': |
188 | 347 | vc_object = Vcenter("10.x.x.x", "username", "password") |
189 | 348 |
|
|
0 commit comments