|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright: (c) 2018, Ansible Project
|
|
|
|
# Copyright: (c) 2018, Abhijeet Kasurde <akasurde@redhat.com>
|
|
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
|
|
__metaclass__ = type
|
|
|
|
|
|
|
|
import ssl
|
|
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
pyvmomi = pytest.importorskip('pyVmomi')
|
|
|
|
|
|
|
|
from units.compat import mock
|
|
|
|
|
|
|
|
import ansible.module_utils.vmware as vmware_module_utils
|
|
|
|
|
|
|
|
|
|
|
|
test_data = [
|
|
|
|
(
|
|
|
|
dict(
|
|
|
|
username='Administrator@vsphere.local',
|
|
|
|
password='Esxi@123$%',
|
|
|
|
hostname=False,
|
|
|
|
validate_certs=False,
|
|
|
|
),
|
|
|
|
"Hostname parameter is missing. Please specify this parameter in task or"
|
|
|
|
" export environment variable like 'export VMWARE_HOST=ESXI_HOSTNAME'"
|
|
|
|
),
|
|
|
|
(
|
|
|
|
dict(
|
|
|
|
username=False,
|
|
|
|
password='Esxi@123$%',
|
|
|
|
hostname='esxi1',
|
|
|
|
validate_certs=False,
|
|
|
|
),
|
|
|
|
"Username parameter is missing. Please specify this parameter in task or"
|
|
|
|
" export environment variable like 'export VMWARE_USER=ESXI_USERNAME'"
|
|
|
|
),
|
|
|
|
(
|
|
|
|
dict(
|
|
|
|
username='Administrator@vsphere.local',
|
|
|
|
password=False,
|
|
|
|
hostname='esxi1',
|
|
|
|
validate_certs=False,
|
|
|
|
),
|
|
|
|
"Password parameter is missing. Please specify this parameter in task or"
|
|
|
|
" export environment variable like 'export VMWARE_PASSWORD=ESXI_PASSWORD'"
|
|
|
|
),
|
|
|
|
(
|
|
|
|
dict(
|
|
|
|
username='Administrator@vsphere.local',
|
|
|
|
password='Esxi@123$%',
|
|
|
|
hostname='esxi1',
|
|
|
|
validate_certs=True,
|
|
|
|
),
|
|
|
|
"Unknown error while connecting to vCenter or ESXi API at esxi1:443"
|
|
|
|
),
|
|
|
|
(
|
|
|
|
dict(
|
|
|
|
username='Administrator@vsphere.local',
|
|
|
|
password='Esxi@123$%',
|
|
|
|
hostname='esxi1',
|
|
|
|
proxy_host='myproxyserver.com',
|
|
|
|
proxy_port=80,
|
|
|
|
validate_certs=False,
|
|
|
|
),
|
|
|
|
" [proxy: myproxyserver.com:80]"
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
test_ids = [
|
|
|
|
'hostname',
|
|
|
|
'username',
|
|
|
|
'password',
|
|
|
|
'validate_certs',
|
|
|
|
'valid_http_proxy',
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class FailJsonException(BaseException):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def fake_ansible_module():
|
|
|
|
ret = mock.Mock()
|
|
|
|
ret.params = test_data[3][0]
|
|
|
|
ret.tmpdir = None
|
|
|
|
ret.fail_json.side_effect = FailJsonException()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
|
|
def fake_connect_to_api(module, return_si=None):
|
|
|
|
return None, mock.Mock(),
|
|
|
|
|
|
|
|
|
|
|
|
testdata = [
|
|
|
|
('HAS_PYVMOMI', 'PyVmomi'),
|
|
|
|
('HAS_REQUESTS', 'requests'),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("key,libname", testdata)
|
|
|
|
def test_lib_loading_failure(monkeypatch, fake_ansible_module, key, libname):
|
|
|
|
""" Test if Pyvmomi is present or not"""
|
|
|
|
monkeypatch.setattr(vmware_module_utils, key, False)
|
|
|
|
with pytest.raises(FailJsonException):
|
|
|
|
vmware_module_utils.PyVmomi(fake_ansible_module)
|
|
|
|
error_str = 'Failed to import the required Python library (%s)' % libname
|
|
|
|
assert fake_ansible_module.fail_json.called_once()
|
|
|
|
assert error_str in fake_ansible_module.fail_json.call_args[1]['msg']
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.skipif(sys.version_info < (2, 7), reason="requires python2.7 and greater")
|
|
|
|
@pytest.mark.parametrize("params, msg", test_data, ids=test_ids)
|
|
|
|
def test_required_params(request, params, msg, fake_ansible_module):
|
|
|
|
""" Test if required params are correct or not"""
|
|
|
|
fake_ansible_module.params = params
|
|
|
|
with pytest.raises(FailJsonException):
|
|
|
|
vmware_module_utils.connect_to_api(fake_ansible_module)
|
|
|
|
assert fake_ansible_module.fail_json.called_once()
|
|
|
|
assert msg in fake_ansible_module.fail_json.call_args[1]['msg']
|
|
|
|
|
|
|
|
|
|
|
|
def test_validate_certs(monkeypatch, fake_ansible_module):
|
|
|
|
""" Test if SSL is required or not"""
|
|
|
|
fake_ansible_module.params = test_data[3][0]
|
|
|
|
|
|
|
|
monkeypatch.setattr(vmware_module_utils, 'ssl', None)
|
|
|
|
with pytest.raises(FailJsonException):
|
|
|
|
vmware_module_utils.PyVmomi(fake_ansible_module)
|
|
|
|
msg = 'pyVim does not support changing verification mode with python < 2.7.9.' \
|
|
|
|
' Either update python or use validate_certs=false.'
|
|
|
|
assert fake_ansible_module.fail_json.called_once()
|
|
|
|
assert msg in fake_ansible_module.fail_json.call_args[1]['msg']
|
|
|
|
|
|
|
|
|
|
|
|
def test_vmdk_disk_path_split(monkeypatch, fake_ansible_module):
|
|
|
|
""" Test vmdk_disk_path_split function"""
|
|
|
|
fake_ansible_module.params = test_data[0][0]
|
|
|
|
|
|
|
|
monkeypatch.setattr(vmware_module_utils, 'connect_to_api', fake_connect_to_api)
|
|
|
|
pyv = vmware_module_utils.PyVmomi(fake_ansible_module)
|
|
|
|
v = pyv.vmdk_disk_path_split('[ds1] VM_0001/VM0001_0.vmdk')
|
|
|
|
assert v == ('ds1', 'VM_0001/VM0001_0.vmdk', 'VM0001_0.vmdk', 'VM_0001')
|
|
|
|
|
|
|
|
|
|
|
|
def test_vmdk_disk_path_split_negative(monkeypatch, fake_ansible_module):
|
|
|
|
""" Test vmdk_disk_path_split function"""
|
|
|
|
fake_ansible_module.params = test_data[0][0]
|
|
|
|
|
|
|
|
monkeypatch.setattr(vmware_module_utils, 'connect_to_api', fake_connect_to_api)
|
|
|
|
with pytest.raises(FailJsonException):
|
|
|
|
pyv = vmware_module_utils.PyVmomi(fake_ansible_module)
|
|
|
|
pyv.vmdk_disk_path_split('[ds1]')
|
|
|
|
assert fake_ansible_module.fail_json.called_once()
|
|
|
|
assert 'Bad path' in fake_ansible_module.fail_json.call_args[1]['msg']
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.skipif(sys.version_info < (2, 7), reason="requires python2.7 and greater")
|
|
|
|
def test_connect_to_api_validate_certs(monkeypatch, fake_ansible_module):
|
|
|
|
monkeypatch.setattr(vmware_module_utils, 'connect', mock.Mock())
|
|
|
|
|
|
|
|
def MockSSLContext(proto):
|
|
|
|
ssl_context.proto = proto
|
|
|
|
return ssl_context
|
|
|
|
|
|
|
|
# New Python with SSLContext + validate_certs=True
|
|
|
|
vmware_module_utils.connect.reset_mock()
|
|
|
|
ssl_context = mock.Mock()
|
|
|
|
monkeypatch.setattr(vmware_module_utils.ssl, 'SSLContext', MockSSLContext)
|
|
|
|
fake_ansible_module.params['validate_certs'] = True
|
|
|
|
vmware_module_utils.connect_to_api(fake_ansible_module)
|
|
|
|
assert ssl_context.proto == ssl.PROTOCOL_SSLv23
|
|
|
|
assert ssl_context.verify_mode == ssl.CERT_REQUIRED
|
|
|
|
assert ssl_context.check_hostname is True
|
|
|
|
vmware_module_utils.connect.SmartConnect.assert_called_once_with(
|
|
|
|
host='esxi1',
|
|
|
|
port=443,
|
|
|
|
pwd='Esxi@123$%',
|
|
|
|
user='Administrator@vsphere.local',
|
|
|
|
sslContext=ssl_context)
|
|
|
|
|
|
|
|
# New Python with SSLContext + validate_certs=False
|
|
|
|
vmware_module_utils.connect.reset_mock()
|
|
|
|
ssl_context = mock.Mock()
|
|
|
|
monkeypatch.setattr(vmware_module_utils.ssl, 'SSLContext', MockSSLContext)
|
|
|
|
fake_ansible_module.params['validate_certs'] = False
|
|
|
|
vmware_module_utils.connect_to_api(fake_ansible_module)
|
|
|
|
assert ssl_context.proto == ssl.PROTOCOL_SSLv23
|
|
|
|
assert ssl_context.verify_mode == ssl.CERT_NONE
|
|
|
|
assert ssl_context.check_hostname is False
|
|
|
|
vmware_module_utils.connect.SmartConnect.assert_called_once_with(
|
|
|
|
host='esxi1',
|
|
|
|
port=443,
|
|
|
|
pwd='Esxi@123$%',
|
|
|
|
user='Administrator@vsphere.local',
|
|
|
|
sslContext=ssl_context)
|
|
|
|
|
|
|
|
# Old Python with no SSLContext + validate_certs=True
|
|
|
|
vmware_module_utils.connect.reset_mock()
|
|
|
|
ssl_context = mock.Mock()
|
|
|
|
ssl_context.proto = None
|
|
|
|
monkeypatch.delattr(vmware_module_utils.ssl, 'SSLContext')
|
|
|
|
fake_ansible_module.params['validate_certs'] = True
|
|
|
|
with pytest.raises(FailJsonException):
|
|
|
|
vmware_module_utils.connect_to_api(fake_ansible_module)
|
|
|
|
assert ssl_context.proto is None
|
|
|
|
fake_ansible_module.fail_json.assert_called_once_with(msg=(
|
|
|
|
'pyVim does not support changing verification mode with python '
|
|
|
|
'< 2.7.9. Either update python or use validate_certs=false.'))
|
|
|
|
assert not vmware_module_utils.connect.SmartConnect.called
|
|
|
|
|
|
|
|
# Old Python with no SSLContext + validate_certs=False
|
|
|
|
vmware_module_utils.connect.reset_mock()
|
|
|
|
ssl_context = mock.Mock()
|
|
|
|
ssl_context.proto = None
|
|
|
|
monkeypatch.delattr(vmware_module_utils.ssl, 'SSLContext', raising=False)
|
|
|
|
fake_ansible_module.params['validate_certs'] = False
|
|
|
|
vmware_module_utils.connect_to_api(fake_ansible_module)
|
|
|
|
assert ssl_context.proto is None
|
|
|
|
vmware_module_utils.connect.SmartConnect.assert_called_once_with(
|
|
|
|
host='esxi1',
|
|
|
|
port=443,
|
|
|
|
pwd='Esxi@123$%',
|
|
|
|
user='Administrator@vsphere.local')
|