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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
|
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Ansible Project
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import traceback
REQUESTS_IMP_ERR = None
try:
import requests
HAS_REQUESTS = True
except ImportError:
REQUESTS_IMP_ERR = traceback.format_exc()
HAS_REQUESTS = False
PYVMOMI_IMP_ERR = None
try:
from pyVim import connect
from pyVmomi import vim, vmodl
HAS_PYVMOMI = True
except ImportError:
PYVMOMI_IMP_ERR = traceback.format_exc()
HAS_PYVMOMI = False
VSPHERE_IMP_ERR = None
try:
from com.vmware.vapi.std_client import DynamicID
from vmware.vapi.vsphere.client import create_vsphere_client
from com.vmware.vapi.std.errors_client import Unauthorized
from com.vmware.content.library_client import Item
from com.vmware.vcenter_client import (Folder,
Datacenter,
ResourcePool,
Datastore,
Cluster,
Host)
HAS_VSPHERE = True
except ImportError:
VSPHERE_IMP_ERR = traceback.format_exc()
HAS_VSPHERE = False
from ansible.module_utils.basic import env_fallback, missing_required_lib
class VmwareRestClient(object):
def __init__(self, module):
"""
Constructor
"""
self.module = module
self.params = module.params
self.check_required_library()
self.api_client = self.connect_to_vsphere_client()
# Helper function
def get_error_message(self, error):
"""
Helper function to show human readable error messages.
"""
err_msg = []
if not error.messages:
if isinstance(error, Unauthorized):
return "Authorization required."
return "Generic error occurred."
for err in error.messages:
err_msg.append(err.default_message % err.args)
return " ,".join(err_msg)
def check_required_library(self):
"""
Check required libraries
"""
if not HAS_REQUESTS:
self.module.fail_json(msg=missing_required_lib('requests'),
exception=REQUESTS_IMP_ERR)
if not HAS_PYVMOMI:
self.module.fail_json(msg=missing_required_lib('PyVmomi'),
exception=PYVMOMI_IMP_ERR)
if not HAS_VSPHERE:
self.module.fail_json(
msg=missing_required_lib('vSphere Automation SDK',
url='https://code.vmware.com/web/sdk/65/vsphere-automation-python'),
exception=VSPHERE_IMP_ERR)
@staticmethod
def vmware_client_argument_spec():
return dict(
hostname=dict(type='str',
fallback=(env_fallback, ['VMWARE_HOST'])),
username=dict(type='str',
fallback=(env_fallback, ['VMWARE_USER']),
aliases=['user', 'admin']),
password=dict(type='str',
fallback=(env_fallback, ['VMWARE_PASSWORD']),
aliases=['pass', 'pwd'],
no_log=True),
port=dict(type='int',
default=443,
fallback=(env_fallback, ['VMWARE_PORT'])),
protocol=dict(type='str',
default='https',
choices=['https', 'http']),
validate_certs=dict(type='bool',
fallback=(env_fallback, ['VMWARE_VALIDATE_CERTS']),
default=True),
)
def connect_to_vsphere_client(self):
"""
Connect to vSphere API Client with Username and Password
"""
username = self.params.get('username')
password = self.params.get('password')
hostname = self.params.get('hostname')
port = self.params.get('port')
session = requests.Session()
session.verify = self.params.get('validate_certs')
if not all([hostname, username, password]):
self.module.fail_json(msg="Missing one of the following : hostname, username, password."
" Please read the documentation for more information.")
client = create_vsphere_client(
server="%s:%s" % (hostname, port),
username=username,
password=password,
session=session)
if client is None:
self.module.fail_json(msg="Failed to login to %s" % hostname)
return client
def get_tags_for_object(self, tag_service=None, tag_assoc_svc=None, dobj=None):
"""
Return list of tag objects associated with an object
Args:
dobj: Dynamic object
tag_service: Tag service object
tag_assoc_svc: Tag Association object
Returns: List of tag objects associated with the given object
"""
# This method returns list of tag objects only,
# Please use get_tags_for_dynamic_obj for more object details
tags = []
if not dobj:
return tags
if not tag_service:
tag_service = self.api_client.tagging.Tag
if not tag_assoc_svc:
tag_assoc_svc = self.api_client.tagging.TagAssociation
tag_ids = tag_assoc_svc.list_attached_tags(dobj)
for tag_id in tag_ids:
tags.append(tag_service.get(tag_id))
return tags
def get_tags_for_dynamic_obj(self, dobj=None):
"""
Return list of tag object details associated with object
Args:
mid: Dynamic object for specified object
Returns: List of tag object details associated with the given object
"""
tags = []
if dobj is None:
return tags
temp_tags_model = self.get_tags_for_object(dobj)
category_service = self.api_client.tagging.Category
for tag_obj in temp_tags_model:
tags.append({
'id': tag_obj.id,
'category_name': category_service.get(tag_obj.category_id).name,
'name': tag_obj.name,
'description': tag_obj.description,
'category_id': tag_obj.category_id,
})
return tags
def get_tags_for_cluster(self, cluster_mid=None):
"""
Return list of tag object associated with cluster
Args:
cluster_mid: Dynamic object for cluster
Returns: List of tag object associated with the given cluster
"""
dobj = DynamicID(type='cluster', id=cluster_mid)
return self.get_tags_for_dynamic_obj(dobj)
def get_tags_for_hostsystem(self, hostsystem_mid=None):
"""
Return list of tag object associated with host system
Args:
hostsystem_mid: Dynamic object for host system
Returns: List of tag object associated with the given host system
"""
dobj = DynamicID(type='HostSystem', id=hostsystem_mid)
return self.get_tags_for_dynamic_obj(dobj)
def get_tags_for_vm(self, vm_mid=None):
"""
Return list of tag object associated with virtual machine
Args:
vm_mid: Dynamic object for virtual machine
Returns: List of tag object associated with the given virtual machine
"""
dobj = DynamicID(type='VirtualMachine', id=vm_mid)
return self.get_tags_for_dynamic_obj(dobj)
def get_vm_tags(self, tag_service=None, tag_association_svc=None, vm_mid=None):
"""
Return list of tag name associated with virtual machine
Args:
tag_service: Tag service object
tag_association_svc: Tag association object
vm_mid: Dynamic object for virtual machine
Returns: List of tag names associated with the given virtual machine
"""
# This API returns just names of tags
# Please use get_tags_for_vm for more tag object details
tags = []
if vm_mid is None:
return tags
temp_tags_model = self.get_tags_for_object(
tag_service=tag_service,
tag_assoc_svc=tag_association_svc,
dobj=vm_mid
)
for tag_obj in temp_tags_model:
tags.append(tag_obj.name)
return tags
def get_library_item_by_name(self, name):
"""
Returns the identifier of the library item with the given name.
Args:
name (str): The name of item to look for
Returns:
str: The item ID or None if the item is not found
"""
find_spec = Item.FindSpec(name=name)
item_ids = self.api_client.content.library.Item.find(find_spec)
item_id = item_ids[0] if item_ids else None
return item_id
def get_datacenter_by_name(self, datacenter_name):
"""
Returns the identifier of a datacenter
Note: The method assumes only one datacenter with the mentioned name.
"""
filter_spec = Datacenter.FilterSpec(names=set([datacenter_name]))
datacenter_summaries = self.api_client.vcenter.Datacenter.list(filter_spec)
datacenter = datacenter_summaries[0].datacenter if len(datacenter_summaries) > 0 else None
return datacenter
def get_folder_by_name(self, datacenter_name, folder_name):
"""
Returns the identifier of a folder
with the mentioned names.
"""
datacenter = self.get_datacenter_by_name(datacenter_name)
if not datacenter:
return None
filter_spec = Folder.FilterSpec(type=Folder.Type.VIRTUAL_MACHINE,
names=set([folder_name]),
datacenters=set([datacenter]))
folder_summaries = self.api_client.vcenter.Folder.list(filter_spec)
folder = folder_summaries[0].folder if len(folder_summaries) > 0 else None
return folder
def get_resource_pool_by_name(self, datacenter_name, resourcepool_name):
"""
Returns the identifier of a resource pool
with the mentioned names.
"""
datacenter = self.get_datacenter_by_name(datacenter_name)
if not datacenter:
return None
names = set([resourcepool_name]) if resourcepool_name else None
filter_spec = ResourcePool.FilterSpec(datacenters=set([datacenter]),
names=names)
resource_pool_summaries = self.api_client.vcenter.ResourcePool.list(filter_spec)
resource_pool = resource_pool_summaries[0].resource_pool if len(resource_pool_summaries) > 0 else None
return resource_pool
def get_datastore_by_name(self, datacenter_name, datastore_name):
"""
Returns the identifier of a datastore
with the mentioned names.
"""
datacenter = self.get_datacenter_by_name(datacenter_name)
if not datacenter:
return None
names = set([datastore_name]) if datastore_name else None
filter_spec = Datastore.FilterSpec(datacenters=set([datacenter]),
names=names)
datastore_summaries = self.api_client.vcenter.Datastore.list(filter_spec)
datastore = datastore_summaries[0].datastore if len(datastore_summaries) > 0 else None
return datastore
def get_cluster_by_name(self, datacenter_name, cluster_name):
"""
Returns the identifier of a cluster
with the mentioned names.
"""
datacenter = self.get_datacenter_by_name(datacenter_name)
if not datacenter:
return None
names = set([cluster_name]) if cluster_name else None
filter_spec = Cluster.FilterSpec(datacenters=set([datacenter]),
names=names)
cluster_summaries = self.api_client.vcenter.Cluster.list(filter_spec)
cluster = cluster_summaries[0].cluster if len(cluster_summaries) > 0 else None
return cluster
def get_host_by_name(self, datacenter_name, host_name):
"""
Returns the identifier of a Host
with the mentioned names.
"""
datacenter = self.get_datacenter_by_name(datacenter_name)
if not datacenter:
return None
names = set([host_name]) if host_name else None
filter_spec = Host.FilterSpec(datacenters=set([datacenter]),
names=names)
host_summaries = self.api_client.vcenter.Host.list(filter_spec)
host = host_summaries[0].host if len(host_summaries) > 0 else None
return host
@staticmethod
def search_svc_object_by_name(service, svc_obj_name=None):
"""
Return service object by name
Args:
service: Service object
svc_obj_name: Name of service object to find
Returns: Service object if found else None
"""
if not svc_obj_name:
return None
for svc_object in service.list():
svc_obj = service.get(svc_object)
if svc_obj.name == svc_obj_name:
return svc_obj
return None
def get_tag_by_name(self, tag_name=None):
"""
Return tag object by name
Args:
tag_name: Name of tag
Returns: Tag object if found else None
"""
if not tag_name:
return None
return self.search_svc_object_by_name(service=self.api_client.tagging.Tag, svc_obj_name=tag_name)
def get_category_by_name(self, category_name=None):
"""
Return category object by name
Args:
category_name: Name of category
Returns: Category object if found else None
"""
if not category_name:
return None
return self.search_svc_object_by_name(service=self.api_client.tagging.Category, svc_obj_name=category_name)
def get_tag_by_category(self, tag_name=None, category_name=None):
"""
Return tag object by name and category name specified
Args:
tag_name: Name of tag
category_name: Name of category
Returns: Tag object if found else None
"""
if not tag_name:
return None
if category_name:
category_obj = self.get_category_by_name(category_name=category_name)
if not category_obj:
return None
for tag_object in self.api_client.tagging.Tag.list():
tag_obj = self.api_client.tagging.Tag.get(tag_object)
if tag_obj.name == tag_name and tag_obj.category_id == category_obj.id:
return tag_obj
else:
return self.search_svc_object_by_name(service=self.api_client.tagging.Tag, svc_obj_name=tag_name)
|