Skip to content

Commit 125e6de

Browse files
committed
De-couple backend logic from module logic
1 parent 09c21d5 commit 125e6de

File tree

2 files changed

+109
-5
lines changed

2 files changed

+109
-5
lines changed
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# Copyright: (c) 2015, Joseph Callen <jcallen () csc.com>
4+
# Copyright: (c) 2018, Ansible Project
5+
# Copyright: (c) 2018, James E. King III (@jeking3) <jking@apache.org>
6+
# Copyright: (c) 2025, Mario Lenz (@mariolenz) <m@riolenz.de>
7+
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
8+
# SPDX-License-Identifier: GPL-3.0-or-later
9+
10+
__metaclass__ = type
11+
12+
import atexit
13+
import requests
14+
import ssl
15+
import traceback
16+
17+
from ansible.module_utils.basic import missing_required_lib
18+
from pyVim import connect
19+
from pyVmomi import vim, vmodl
20+
21+
22+
class PyvmomiClient(object):
23+
def __init__(self, hostname, username, password, port=443, validate_certs=True, http_proxy_host=None, http_proxy_port=None):
24+
self.si, self.content = self._connect_to_api(hostname, username, password, port, validate_certs, http_proxy_host, http_proxy_port)
25+
26+
def _connect_to_api(self, hostname, username, password, port, validate_certs, http_proxy_host, http_proxy_port):
27+
def _raise_or_fail(msg):
28+
if module is not None:
29+
module.fail_json(msg=msg)
30+
raise ApiAccessError(msg)
31+
32+
if not hostname:
33+
_raise_or_fail(msg="Hostname parameter is missing."
34+
" Please specify this parameter in task or"
35+
" export environment variable like 'export VMWARE_HOST=ESXI_HOSTNAME'")
36+
37+
if not username:
38+
_raise_or_fail(msg="Username parameter is missing."
39+
" Please specify this parameter in task or"
40+
" export environment variable like 'export VMWARE_USER=ESXI_USERNAME'")
41+
42+
if not password:
43+
_raise_or_fail(msg="Password parameter is missing."
44+
" Please specify this parameter in task or"
45+
" export environment variable like 'export VMWARE_PASSWORD=ESXI_PASSWORD'")
46+
47+
if validate_certs and not hasattr(ssl, 'SSLContext'):
48+
_raise_or_fail(msg='pyVim does not support changing verification mode with python < 2.7.9. Either update '
49+
'python or use validate_certs=false.')
50+
elif validate_certs:
51+
ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
52+
ssl_context.verify_mode = ssl.CERT_REQUIRED
53+
ssl_context.check_hostname = True
54+
ssl_context.load_default_certs()
55+
elif hasattr(ssl, 'SSLContext'):
56+
ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
57+
ssl_context.verify_mode = ssl.CERT_NONE
58+
ssl_context.check_hostname = False
59+
60+
service_instance = None
61+
62+
connect_args = dict(
63+
host=hostname,
64+
port=port,
65+
)
66+
if ssl_context:
67+
connect_args.update(sslContext=ssl_context)
68+
69+
msg_suffix = ''
70+
try:
71+
if http_proxy_host:
72+
msg_suffix = " [proxy: %s:%d]" % (http_proxy_host, http_proxy_port)
73+
connect_args.update(httpProxyHost=http_proxy_host, httpProxyPort=http_proxy_port)
74+
smart_stub = connect.SmartStubAdapter(**connect_args)
75+
session_stub = connect.VimSessionOrientedStub(smart_stub, connect.VimSessionOrientedStub.makeUserLoginMethod(username, password))
76+
service_instance = vim.ServiceInstance('ServiceInstance', session_stub)
77+
else:
78+
connect_args.update(user=username, pwd=password)
79+
service_instance = connect.SmartConnect(**connect_args)
80+
except vim.fault.InvalidLogin as invalid_login:
81+
msg = "Unable to log on to vCenter or ESXi API at %s:%s " % (hostname, port)
82+
_raise_or_fail(msg="%s as %s: %s" % (msg, username, invalid_login.msg) + msg_suffix)
83+
except vim.fault.NoPermission as no_permission:
84+
_raise_or_fail(msg="User %s does not have required permission"
85+
" to log on to vCenter or ESXi API at %s:%s : %s" % (username, hostname, port, no_permission.msg))
86+
except (requests.ConnectionError, ssl.SSLError) as generic_req_exc:
87+
_raise_or_fail(msg="Unable to connect to vCenter or ESXi API at %s on TCP/%s: %s" % (hostname, port, generic_req_exc))
88+
except vmodl.fault.InvalidRequest as invalid_request:
89+
# Request is malformed
90+
msg = "Failed to get a response from server %s:%s " % (hostname, port)
91+
_raise_or_fail(msg="%s as request is malformed: %s" % (msg, invalid_request.msg) + msg_suffix)
92+
except Exception as generic_exc:
93+
msg = "Unknown error while connecting to vCenter or ESXi API at %s:%s" % (hostname, port) + msg_suffix
94+
_raise_or_fail(msg="%s : %s" % (msg, generic_exc))
95+
96+
if service_instance is None:
97+
msg = "Unknown error while connecting to vCenter or ESXi API at %s:%s" % (hostname, port)
98+
_raise_or_fail(msg=msg + msg_suffix)
99+
100+
atexit.register(connect.Disconnect, service_instance)
101+
102+
return service_instance, service_instance.RetrieveContent()

plugins/module_utils/vmware.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
77
# SPDX-License-Identifier: GPL-3.0-or-later
88

9-
from __future__ import absolute_import, division, print_function
109
__metaclass__ = type
1110

1211
import atexit
@@ -22,6 +21,7 @@
2221
import datetime
2322
from collections import OrderedDict
2423
from ansible.module_utils.compat.version import StrictVersion
24+
from ansible_collections.community.vmware.plugins.module_utils.clients._vmware import PyvmomiClient
2525
from random import randint
2626

2727

@@ -1067,11 +1067,8 @@ def quote_obj_name(object_name=None):
10671067
return object_name
10681068

10691069

1070-
class PyVmomi(object):
1070+
class PyVmomi(PyvmomiClient):
10711071
def __init__(self, module):
1072-
"""
1073-
Constructor
1074-
"""
10751072
if not HAS_REQUESTS:
10761073
module.fail_json(msg=missing_required_lib('requests'),
10771074
exception=REQUESTS_IMP_ERR)
@@ -1080,6 +1077,11 @@ def __init__(self, module):
10801077
module.fail_json(msg=missing_required_lib('PyVmomi'),
10811078
exception=PYVMOMI_IMP_ERR)
10821079

1080+
super().__init__(module.params['hostname'], module.params['username'],
1081+
module.params['password'], module.params['port'],
1082+
module.params['validate_certs'],
1083+
module.params['proxy_host'],
1084+
module.params['proxy_port'])
10831085
self.module = module
10841086
self.params = module.params
10851087
self.current_vm_obj = None

0 commit comments

Comments
 (0)