mirror of
https://github.com/vmware/vsphere-automation-sdk-python.git
synced 2024-11-21 17:29:59 -05:00
Add tests to make sure vsphere client stubs are present
Add unittests for vsphere client Fixed some format issues Run the tests as part of travis ci
This commit is contained in:
parent
5ba4450b3b
commit
cfa9acdb88
@ -6,6 +6,7 @@ python:
|
|||||||
install:
|
install:
|
||||||
- pip install -r requirements.txt --extra-index-url file://$PWD/lib --upgrade --ignore-installed six
|
- pip install -r requirements.txt --extra-index-url file://$PWD/lib --upgrade --ignore-installed six
|
||||||
- pip install -r test-requirements.txt
|
- pip install -r test-requirements.txt
|
||||||
- pip install pycodestyle
|
|
||||||
# command to run tests
|
# command to run tests
|
||||||
script: pycodestyle samples/*.py
|
script: pycodestyle samples tests
|
||||||
|
script: pytest
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ class BackupSchedule(object):
|
|||||||
|
|
||||||
self._schedule_id = 'test_schedule'
|
self._schedule_id = 'test_schedule'
|
||||||
|
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
parser = sample_cli.build_arg_parser()
|
parser = sample_cli.build_arg_parser()
|
||||||
|
|
||||||
@ -154,5 +153,6 @@ def main():
|
|||||||
schedule.setup()
|
schedule.setup()
|
||||||
schedule.run()
|
schedule.run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -15,7 +15,7 @@ __author__ = 'VMware, Inc.'
|
|||||||
__copyright__ = 'Copyright 2013, 2016, 2017 VMware, Inc. All rights reserved.'
|
__copyright__ = 'Copyright 2013, 2016, 2017 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
|
||||||
#Standard library imports.
|
# Standard library imports.
|
||||||
import six.moves.http_client
|
import six.moves.http_client
|
||||||
import re
|
import re
|
||||||
from six import PY3
|
from six import PY3
|
||||||
@ -33,7 +33,7 @@ from pyVmomi import ThumbprintMismatchException
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from six.moves.urllib.parse import urlparse
|
from six.moves.urllib.parse import urlparse
|
||||||
#Third-party imports.
|
# Third-party imports.
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from OpenSSL import crypto
|
from OpenSSL import crypto
|
||||||
import ssl
|
import ssl
|
||||||
@ -42,6 +42,7 @@ UTF_8 = 'utf-8'
|
|||||||
SHA256 = 'sha256'
|
SHA256 = 'sha256'
|
||||||
SHA512 = 'sha512'
|
SHA512 = 'sha512'
|
||||||
|
|
||||||
|
|
||||||
def _extract_certificate(cert):
|
def _extract_certificate(cert):
|
||||||
'''
|
'''
|
||||||
Extract DER certificate/private key from DER/base64-ed DER/PEM string.
|
Extract DER certificate/private key from DER/base64-ed DER/PEM string.
|
||||||
@ -72,6 +73,7 @@ class SoapException(Exception):
|
|||||||
'''
|
'''
|
||||||
Exception raised in case of STS request failure.
|
Exception raised in case of STS request failure.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, soap_msg, fault_code, fault_string):
|
def __init__(self, soap_msg, fault_code, fault_string):
|
||||||
'''
|
'''
|
||||||
Initializer for SoapException.
|
Initializer for SoapException.
|
||||||
@ -104,6 +106,7 @@ class SSOHTTPSConnection(six.moves.http_client.HTTPSConnection):
|
|||||||
'''
|
'''
|
||||||
An HTTPS class that verifies server's certificate on connect.
|
An HTTPS class that verifies server's certificate on connect.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
'''
|
'''
|
||||||
Initializer. See httplib.HTTPSConnection for other arguments
|
Initializer. See httplib.HTTPSConnection for other arguments
|
||||||
@ -154,7 +157,7 @@ class SSOHTTPSConnection(six.moves.http_client.HTTPSConnection):
|
|||||||
self.sock.close()
|
self.sock.close()
|
||||||
self.sock = None
|
self.sock = None
|
||||||
raise ThumbprintMismatchException(
|
raise ThumbprintMismatchException(
|
||||||
expected=self.server_thumbprint, actual=thumbprint)
|
expected=self.server_thumbprint, actual=thumbprint)
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''
|
'''
|
||||||
@ -407,7 +410,8 @@ class SsoAuthenticator(object):
|
|||||||
@rtype: C{str}
|
@rtype: C{str}
|
||||||
@return: The SAML assertion.
|
@return: The SAML assertion.
|
||||||
'''
|
'''
|
||||||
import sspi, win32api
|
import sspi
|
||||||
|
import win32api
|
||||||
spn = "sts/%s.com" % win32api.GetDomainName()
|
spn = "sts/%s.com" % win32api.GetDomainName()
|
||||||
sspiclient = sspi.ClientAuth("Kerberos", targetspn=spn)
|
sspiclient = sspi.ClientAuth("Kerberos", targetspn=spn)
|
||||||
in_buf = None
|
in_buf = None
|
||||||
@ -467,7 +471,8 @@ class SsoAuthenticator(object):
|
|||||||
@rtype: C{str}
|
@rtype: C{str}
|
||||||
@return: The SAML assertion in Unicode.
|
@return: The SAML assertion in Unicode.
|
||||||
'''
|
'''
|
||||||
import kerberos, platform
|
import kerberos
|
||||||
|
import platform
|
||||||
service = 'host@%s' % platform.node()
|
service = 'host@%s' % platform.node()
|
||||||
_, context = kerberos.authGSSClientInit(service, 0)
|
_, context = kerberos.authGSSClientInit(service, 0)
|
||||||
challenge = ''
|
challenge = ''
|
||||||
@ -533,7 +538,7 @@ class SsoAuthenticator(object):
|
|||||||
token_duration, delegatable, renewable)
|
token_duration, delegatable, renewable)
|
||||||
else:
|
else:
|
||||||
raise Exception("Currently, not supported on this platform")
|
raise Exception("Currently, not supported on this platform")
|
||||||
## TODO Remove this exception once SSO supports validation of tickets
|
# TODO Remove this exception once SSO supports validation of tickets
|
||||||
# generated against host machines
|
# generated against host machines
|
||||||
# saml_token = self._get_bearer_saml_assertion_lin(request_duration, token_duration, delegatable)
|
# saml_token = self._get_bearer_saml_assertion_lin(request_duration, token_duration, delegatable)
|
||||||
return saml_token
|
return saml_token
|
||||||
@ -647,13 +652,14 @@ class SsoAuthenticator(object):
|
|||||||
{'saml2': "urn:oasis:names:tc:SAML:2.0:assertion"}),
|
{'saml2': "urn:oasis:names:tc:SAML:2.0:assertion"}),
|
||||||
pretty_print=False).decode(UTF_8)
|
pretty_print=False).decode(UTF_8)
|
||||||
|
|
||||||
|
|
||||||
class SecurityTokenRequest(object):
|
class SecurityTokenRequest(object):
|
||||||
'''
|
'''
|
||||||
SecurityTokenRequest class handles the serialization of request to the STS
|
SecurityTokenRequest class handles the serialization of request to the STS
|
||||||
for a SAML token.
|
for a SAML token.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
#pylint: disable=R0902
|
# pylint: disable=R0902
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
username=None,
|
username=None,
|
||||||
password=None,
|
password=None,
|
||||||
@ -699,8 +705,7 @@ class SecurityTokenRequest(object):
|
|||||||
self._expires = time.strftime(TIME_FORMAT,
|
self._expires = time.strftime(TIME_FORMAT,
|
||||||
time.gmtime(current + token_duration))
|
time.gmtime(current + token_duration))
|
||||||
self._request_expires = time.strftime(TIME_FORMAT,
|
self._request_expires = time.strftime(TIME_FORMAT,
|
||||||
time.gmtime(current +
|
time.gmtime(current + request_duration))
|
||||||
request_duration))
|
|
||||||
self._timestamp = TIMESTAMP_TEMPLATE % self.__dict__
|
self._timestamp = TIMESTAMP_TEMPLATE % self.__dict__
|
||||||
self._username = escape(username) if username else username
|
self._username = escape(username) if username else username
|
||||||
self._password = escape(password) if password else password
|
self._password = escape(password) if password else password
|
||||||
@ -714,9 +719,9 @@ class SecurityTokenRequest(object):
|
|||||||
self._binary_exchange = None
|
self._binary_exchange = None
|
||||||
self._public_key = None
|
self._public_key = None
|
||||||
if gss_binary_token:
|
if gss_binary_token:
|
||||||
self._binary_exchange = BINARY_EXCHANGE_TEMPLATE % gss_binary_token
|
self._binary_exchange = BINARY_EXCHANGE_TEMPLATE % gss_binary_token
|
||||||
#The following are populated later. Set to None here to keep in-line
|
# The following are populated later. Set to None here to keep in-line
|
||||||
#with PEP8.
|
# with PEP8.
|
||||||
self._binary_security_token = None
|
self._binary_security_token = None
|
||||||
self._hok_token = hok_token
|
self._hok_token = hok_token
|
||||||
self._key_type = None
|
self._key_type = None
|
||||||
@ -730,7 +735,7 @@ class SecurityTokenRequest(object):
|
|||||||
self._xml = None
|
self._xml = None
|
||||||
self._request_digest = None
|
self._request_digest = None
|
||||||
|
|
||||||
#These will only be populated if requesting an HoK token.
|
# These will only be populated if requesting an HoK token.
|
||||||
if self._private_key_file:
|
if self._private_key_file:
|
||||||
with open(self._private_key_file) as fp:
|
with open(self._private_key_file) as fp:
|
||||||
self._private_key = fp.read()
|
self._private_key = fp.read()
|
||||||
@ -942,15 +947,17 @@ def _load_private_key(der_key):
|
|||||||
for key_type in ('PRIVATE KEY', 'RSA PRIVATE KEY'):
|
for key_type in ('PRIVATE KEY', 'RSA PRIVATE KEY'):
|
||||||
try:
|
try:
|
||||||
return crypto.load_privatekey(crypto.FILETYPE_PEM,
|
return crypto.load_privatekey(crypto.FILETYPE_PEM,
|
||||||
'-----BEGIN ' + key_type + '-----\n' +
|
'-----BEGIN {}-----\n{}-----END {}-----\n'.format(
|
||||||
base64.encodestring(der_key).decode(UTF_8) +
|
key_type,
|
||||||
'-----END ' + key_type + '-----\n',
|
base64.encodestring(der_key).decode(UTF_8),
|
||||||
|
key_type),
|
||||||
b'')
|
b'')
|
||||||
except (crypto.Error, ValueError):
|
except (crypto.Error, ValueError):
|
||||||
pass
|
pass
|
||||||
# We could try 'ENCRYPTED PRIVATE KEY' here - but we do not know passphrase.
|
# We could try 'ENCRYPTED PRIVATE KEY' here - but we do not know passphrase.
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def _sign(private_key, data, digest=SHA256):
|
def _sign(private_key, data, digest=SHA256):
|
||||||
'''
|
'''
|
||||||
An internal helper method to sign the 'data' with the 'private_key'.
|
An internal helper method to sign the 'data' with the 'private_key'.
|
||||||
@ -972,6 +979,7 @@ def _sign(private_key, data, digest=SHA256):
|
|||||||
pkey = _load_private_key(_extract_certificate(private_key))
|
pkey = _load_private_key(_extract_certificate(private_key))
|
||||||
return base64.b64encode(crypto.sign(pkey, data, digest))
|
return base64.b64encode(crypto.sign(pkey, data, digest))
|
||||||
|
|
||||||
|
|
||||||
def _canonicalize(xml_string):
|
def _canonicalize(xml_string):
|
||||||
'''
|
'''
|
||||||
Given an xml string, canonicalize the string per
|
Given an xml string, canonicalize the string per
|
||||||
@ -989,6 +997,7 @@ def _canonicalize(xml_string):
|
|||||||
tree.write_c14n(string, exclusive=True, with_comments=False)
|
tree.write_c14n(string, exclusive=True, with_comments=False)
|
||||||
return string.getvalue().decode(UTF_8)
|
return string.getvalue().decode(UTF_8)
|
||||||
|
|
||||||
|
|
||||||
def _extract_element(xml, element_name, namespace):
|
def _extract_element(xml, element_name, namespace):
|
||||||
'''
|
'''
|
||||||
An internal method provided to extract an element from the given XML.
|
An internal method provided to extract an element from the given XML.
|
||||||
@ -1042,9 +1051,9 @@ def _make_hash_sha512(data):
|
|||||||
|
|
||||||
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.987Z"
|
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.987Z"
|
||||||
|
|
||||||
#The SAML token requests usually contain an xmldsig which guarantees that the
|
# The SAML token requests usually contain an xmldsig which guarantees that the
|
||||||
#message hasn't been tampered with during the transport. The following
|
# message hasn't been tampered with during the transport. The following
|
||||||
#SIGNED_INFO_TEMPLATE is used to construct the signedinfo part of the signature.
|
# SIGNED_INFO_TEMPLATE is used to construct the signedinfo part of the signature.
|
||||||
SIGNED_INFO_TEMPLATE = """\
|
SIGNED_INFO_TEMPLATE = """\
|
||||||
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||||
@ -1066,11 +1075,11 @@ SIGNED_INFO_TEMPLATE = """\
|
|||||||
</ds:SignedInfo>
|
</ds:SignedInfo>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#The following template is used as the container for signed info in WS-Trust
|
# The following template is used as the container for signed info in WS-Trust
|
||||||
#SOAP requests signed with the SAML token. It contains the digest of the
|
# SOAP requests signed with the SAML token. It contains the digest of the
|
||||||
#signed info, signed with the private key of the Solution user and contains a
|
# signed info, signed with the private key of the Solution user and contains a
|
||||||
#reference to the actual SAML token which contains the solution user's public
|
# reference to the actual SAML token which contains the solution user's public
|
||||||
#key.
|
# key.
|
||||||
REQUEST_SIGNATURE_TEMPLATE = """\
|
REQUEST_SIGNATURE_TEMPLATE = """\
|
||||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||||
%(_signed_info)s
|
%(_signed_info)s
|
||||||
@ -1084,9 +1093,9 @@ REQUEST_SIGNATURE_TEMPLATE = """\
|
|||||||
</ds:KeyInfo>
|
</ds:KeyInfo>
|
||||||
</ds:Signature>"""
|
</ds:Signature>"""
|
||||||
|
|
||||||
#The following template is used as a signed info container for the actual SAML
|
# The following template is used as a signed info container for the actual SAML
|
||||||
#token requests requesting a SAML token. It contains the digest of the signed
|
# token requests requesting a SAML token. It contains the digest of the signed
|
||||||
#info signed with the Service User's private key.
|
# info signed with the Service User's private key.
|
||||||
SIGNATURE_TEMPLATE = """\
|
SIGNATURE_TEMPLATE = """\
|
||||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="%(_signature_id)s">
|
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="%(_signature_id)s">
|
||||||
%(_signed_info)s
|
%(_signed_info)s
|
||||||
@ -1098,7 +1107,7 @@ SIGNATURE_TEMPLATE = """\
|
|||||||
</ds:KeyInfo>
|
</ds:KeyInfo>
|
||||||
</ds:Signature>"""
|
</ds:Signature>"""
|
||||||
|
|
||||||
#The following template is used to construct the token requests to the STS.
|
# The following template is used to construct the token requests to the STS.
|
||||||
REQUEST_TEMPLATE = """\
|
REQUEST_TEMPLATE = """\
|
||||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||||
<SOAP-ENV:Header>
|
<SOAP-ENV:Header>
|
||||||
@ -1128,7 +1137,7 @@ REQUEST_TEMPLATE = """\
|
|||||||
</SOAP-ENV:Body>
|
</SOAP-ENV:Body>
|
||||||
</SOAP-ENV:Envelope>"""
|
</SOAP-ENV:Envelope>"""
|
||||||
|
|
||||||
#The following template is used to construct the token-by-token requests to the STS.
|
# The following template is used to construct the token-by-token requests to the STS.
|
||||||
REQUEST_TEMPLATE_TOKEN_BY_TOKEN = """\
|
REQUEST_TEMPLATE_TOKEN_BY_TOKEN = """\
|
||||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
|
||||||
<SOAP-ENV:Header>
|
<SOAP-ENV:Header>
|
||||||
@ -1185,8 +1194,8 @@ GSS_REQUEST_TEMPLATE = """\
|
|||||||
</SOAP-ENV:Body>
|
</SOAP-ENV:Body>
|
||||||
</SOAP-ENV:Envelope>"""
|
</SOAP-ENV:Envelope>"""
|
||||||
|
|
||||||
#Template container for the service user's public key when requesting an HoK
|
# Template container for the service user's public key when requesting an HoK
|
||||||
#token.
|
# token.
|
||||||
BINARY_SECURITY_TOKEN_TEMPLATE = """\
|
BINARY_SECURITY_TOKEN_TEMPLATE = """\
|
||||||
<ns2:BinarySecurityToken xmlns:ns1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
<ns2:BinarySecurityToken xmlns:ns1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
|
||||||
xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
|
||||||
@ -1195,19 +1204,19 @@ BINARY_SECURITY_TOKEN_TEMPLATE = """\
|
|||||||
ns1:Id="%(_security_token_id)s">%(_binary_security_token)s</ns2:BinarySecurityToken>
|
ns1:Id="%(_security_token_id)s">%(_binary_security_token)s</ns2:BinarySecurityToken>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#Template container for user's credentials when requesting a bearer token.
|
# Template container for user's credentials when requesting a bearer token.
|
||||||
USERNAME_TOKEN_TEMPLATE = """\
|
USERNAME_TOKEN_TEMPLATE = """\
|
||||||
<ns2:UsernameToken xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
<ns2:UsernameToken xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
||||||
<ns2:Username>%(_username)s</ns2:Username>
|
<ns2:Username>%(_username)s</ns2:Username>
|
||||||
<ns2:Password>%(_password)s</ns2:Password>
|
<ns2:Password>%(_password)s</ns2:Password>
|
||||||
</ns2:UsernameToken>"""
|
</ns2:UsernameToken>"""
|
||||||
|
|
||||||
#Template containing the anchor to the signature.
|
# Template containing the anchor to the signature.
|
||||||
USE_KEY_TEMPLATE = """\
|
USE_KEY_TEMPLATE = """\
|
||||||
<UseKey Sig="%(_signature_id)s"/>"""
|
<UseKey Sig="%(_signature_id)s"/>"""
|
||||||
|
|
||||||
#The follwoing template is used to create a timestamp for the various messages.
|
# The follwoing template is used to create a timestamp for the various messages.
|
||||||
#The timestamp is used to indicate the duration of the request itself.
|
# The timestamp is used to indicate the duration of the request itself.
|
||||||
TIMESTAMP_TEMPLATE = """\
|
TIMESTAMP_TEMPLATE = """\
|
||||||
<ns3:Timestamp xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" ns3:Id="%(_timestamp_id)s">
|
<ns3:Timestamp xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" ns3:Id="%(_timestamp_id)s">
|
||||||
<ns3:Created>%(_created)s</ns3:Created><ns3:Expires>%(_request_expires)s</ns3:Expires></ns3:Timestamp>"""
|
<ns3:Created>%(_created)s</ns3:Created><ns3:Expires>%(_request_expires)s</ns3:Expires></ns3:Timestamp>"""
|
||||||
|
@ -19,7 +19,7 @@ from samples.vsphere.common.vim.inventory import get_datastore_mo
|
|||||||
|
|
||||||
from samples.vsphere.common.vim import datastore_file
|
from samples.vsphere.common.vim import datastore_file
|
||||||
|
|
||||||
datastore_path_regex = re.compile('\[(.+)\]\s?(.*)')
|
datastore_path_regex = re.compile(br'\[(.+)\]\s?(.*)')
|
||||||
|
|
||||||
|
|
||||||
def parse_datastore_path(datastore_path):
|
def parse_datastore_path(datastore_path):
|
||||||
|
@ -128,5 +128,6 @@ def main():
|
|||||||
log_forwarding.setup()
|
log_forwarding.setup()
|
||||||
log_forwarding.run()
|
log_forwarding.run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -25,6 +25,7 @@ from samples.vsphere.common.ssl_helper import get_unverified_session
|
|||||||
from samples.vsphere.common import sample_cli
|
from samples.vsphere.common import sample_cli
|
||||||
from samples.vsphere.common import sample_util
|
from samples.vsphere.common import sample_util
|
||||||
|
|
||||||
|
|
||||||
class ListServices(object):
|
class ListServices(object):
|
||||||
"""
|
"""
|
||||||
Demonstrates the details of vCenter Services
|
Demonstrates the details of vCenter Services
|
||||||
@ -35,8 +36,7 @@ class ListServices(object):
|
|||||||
- vCenter Server
|
- vCenter Server
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
def __init__(self):
|
|
||||||
# Create argument parser for standard inputs:
|
# Create argument parser for standard inputs:
|
||||||
# server, username, password and skipverification
|
# server, username, password and skipverification
|
||||||
parser = sample_cli.build_arg_parser()
|
parser = sample_cli.build_arg_parser()
|
||||||
@ -51,10 +51,11 @@ class ListServices(object):
|
|||||||
username=args.username,
|
username=args.username,
|
||||||
password=args.password,
|
password=args.password,
|
||||||
session=session)
|
session=session)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
services_list = self.client.vcenter.services.Service.list_details()
|
services_list = self.client.vcenter.services.Service.list_details()
|
||||||
table = []
|
table = []
|
||||||
for key,value in services_list.items():
|
for key, value in services_list.items():
|
||||||
row = [key,
|
row = [key,
|
||||||
value.name_key,
|
value.name_key,
|
||||||
value.health,
|
value.health,
|
||||||
@ -62,11 +63,13 @@ class ListServices(object):
|
|||||||
value.startup_type]
|
value.startup_type]
|
||||||
table.append(row)
|
table.append(row)
|
||||||
headers = ["Service Name", "Service Name Key", "Service Health", "Service Status", "Service Startup Type"]
|
headers = ["Service Name", "Service Name Key", "Service Health", "Service Status", "Service Startup Type"]
|
||||||
print(tabulate(table,headers))
|
print(tabulate(table, headers))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
list_services = ListServices()
|
list_services = ListServices()
|
||||||
list_services.run()
|
list_services.run()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
@ -87,11 +87,11 @@ def run():
|
|||||||
|
|
||||||
print('\n# Example: Create SCSI adapter with defaults')
|
print('\n# Example: Create SCSI adapter with defaults')
|
||||||
scsi_create_spec = Scsi.CreateSpec()
|
scsi_create_spec = Scsi.CreateSpec()
|
||||||
scsi = client.vcenter.vm.hardware.adapter.Scsi.create(vm, scsi_create_spec)
|
scsi = client.vcenter.vm.hardware.adapter.Scsi.create(vm, scsi_create_spec)
|
||||||
print('vm.hardware.adapter.Scsi.create({}, {}) -> {}'.
|
print('vm.hardware.adapter.Scsi.create({}, {}) -> {}'.
|
||||||
format(vm, scsi_create_spec, scsi))
|
format(vm, scsi_create_spec, scsi))
|
||||||
scsis_to_delete.append(scsi)
|
scsis_to_delete.append(scsi)
|
||||||
scsi_info = client.vcenter.vm.hardware.adapter.Scsi.get(vm, scsi)
|
scsi_info = client.vcenter.vm.hardware.adapter.Scsi.get(vm, scsi)
|
||||||
print('vm.hardware.adapter.Scsi.get({}, {}) -> {}'.
|
print('vm.hardware.adapter.Scsi.get({}, {}) -> {}'.
|
||||||
format(vm, scsi, pp(scsi_info)))
|
format(vm, scsi, pp(scsi_info)))
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ def run():
|
|||||||
client.vcenter.vm.hardware.adapter.Scsi.update(vm, scsi, scsi_update_spec)
|
client.vcenter.vm.hardware.adapter.Scsi.update(vm, scsi, scsi_update_spec)
|
||||||
print('vm.hardware.adapter.Scsi.update({}, {}, {})'.
|
print('vm.hardware.adapter.Scsi.update({}, {}, {})'.
|
||||||
format(vm, scsi, scsi_create_spec))
|
format(vm, scsi, scsi_create_spec))
|
||||||
scsi_info = client.vcenter.vm.hardware.adapter.Scsi.get(vm, scsi)
|
scsi_info = client.vcenter.vm.hardware.adapter.Scsi.get(vm, scsi)
|
||||||
print('vm.hardware.adapter.Scsi.get({}, {}) -> {}'.
|
print('vm.hardware.adapter.Scsi.get({}, {}) -> {}'.
|
||||||
format(vm, scsi, pp(scsi_info)))
|
format(vm, scsi, pp(scsi_info)))
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ def setup(context=None):
|
|||||||
password=password,
|
password=password,
|
||||||
session=session)
|
session=session)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
global vm
|
global vm
|
||||||
vm = get_vm(client, vm_name)
|
vm = get_vm(client, vm_name)
|
||||||
|
@ -63,6 +63,7 @@ def setup(context=None):
|
|||||||
password=password,
|
password=password,
|
||||||
session=session)
|
session=session)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
global vm
|
global vm
|
||||||
vm = get_vm(client, vm_name)
|
vm = get_vm(client, vm_name)
|
||||||
|
@ -58,6 +58,7 @@ def setup(context=None):
|
|||||||
password=password,
|
password=password,
|
||||||
session=session)
|
session=session)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
global vm
|
global vm
|
||||||
vm = get_vm(client, vm_name)
|
vm = get_vm(client, vm_name)
|
||||||
|
@ -59,6 +59,7 @@ def setup(context=None):
|
|||||||
password=password,
|
password=password,
|
||||||
session=session)
|
session=session)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
global vm
|
global vm
|
||||||
vm = get_vm(client, vm_name)
|
vm = get_vm(client, vm_name)
|
||||||
|
@ -59,6 +59,7 @@ def setup(context=None):
|
|||||||
password=password,
|
password=password,
|
||||||
session=session)
|
session=session)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
# * Floppy images must be pre-existing. This API does not expose
|
# * Floppy images must be pre-existing. This API does not expose
|
||||||
# a way to create new floppy images.
|
# a way to create new floppy images.
|
||||||
|
@ -58,6 +58,7 @@ def setup(context=None):
|
|||||||
password=password,
|
password=password,
|
||||||
session=session)
|
session=session)
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
global vm
|
global vm
|
||||||
vm = get_vm(client, vm_name)
|
vm = get_vm(client, vm_name)
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
[pycodestyle]
|
[pycodestyle]
|
||||||
ignore = E402, E501, E122, E126, E127, E128, E129, E131
|
ignore = E402, E501, E122, E126, E127, E128, E129, E131, W503, W504
|
@ -1 +1,3 @@
|
|||||||
testtools>=0.9.34
|
pytest
|
||||||
|
pycodestyle
|
||||||
|
|
||||||
|
119
tests/test_vsphere_client.py
Normal file
119
tests/test_vsphere_client.py
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* Copyright (c) VMware, Inc. 2018. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
* *******************************************************
|
||||||
|
*
|
||||||
|
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
|
||||||
|
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
|
||||||
|
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||||
|
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from vmware.vapi.bindings.stub import ApiClient, StubFactoryBase
|
||||||
|
from vmware.vapi.lib.connect import get_requests_connector
|
||||||
|
from vmware.vapi.stdlib.client.factories import StubConfigurationFactory
|
||||||
|
|
||||||
|
from vmware.vapi.vsphere.client import StubFactory
|
||||||
|
|
||||||
|
stub_config = StubConfigurationFactory.new_std_configuration(
|
||||||
|
get_requests_connector(session=requests.session(), url='https://localhost/vapi'))
|
||||||
|
stub_factory = StubFactory(stub_config)
|
||||||
|
client = ApiClient(stub_factory)
|
||||||
|
|
||||||
|
|
||||||
|
def test_vcenter_client():
|
||||||
|
assert hasattr(client, 'vcenter')
|
||||||
|
assert isinstance(client.vcenter, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cluster_client():
|
||||||
|
assert hasattr(client.vcenter, 'Cluster')
|
||||||
|
|
||||||
|
|
||||||
|
def test_datacenter_client():
|
||||||
|
assert hasattr(client.vcenter, 'Datacenter')
|
||||||
|
|
||||||
|
|
||||||
|
def test_datastore_client():
|
||||||
|
assert hasattr(client.vcenter, 'Datastore')
|
||||||
|
|
||||||
|
|
||||||
|
def test_deployment_client():
|
||||||
|
assert hasattr(client.vcenter, 'Deployment')
|
||||||
|
|
||||||
|
|
||||||
|
def test_configuration_client():
|
||||||
|
assert hasattr(client.content, 'Configuration')
|
||||||
|
|
||||||
|
|
||||||
|
def test_appliance_client():
|
||||||
|
assert hasattr(client, 'appliance')
|
||||||
|
assert isinstance(client.appliance, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_content_client():
|
||||||
|
assert hasattr(client, 'content')
|
||||||
|
assert isinstance(client.content, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_tagging_client():
|
||||||
|
assert hasattr(client, 'tagging')
|
||||||
|
assert isinstance(client.tagging, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_ovf_client():
|
||||||
|
assert hasattr(client.vcenter, 'ovf')
|
||||||
|
assert isinstance(client.vcenter.ovf, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_hvc_client():
|
||||||
|
assert hasattr(client.vcenter, 'hvc')
|
||||||
|
assert isinstance(client.vcenter.hvc, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_inventory_client():
|
||||||
|
assert hasattr(client.vcenter, 'inventory')
|
||||||
|
assert isinstance(client.vcenter.inventory, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_iso_client():
|
||||||
|
assert hasattr(client.vcenter, 'iso')
|
||||||
|
assert isinstance(client.vcenter.iso, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_ovf_client():
|
||||||
|
assert hasattr(client.vcenter, 'ovf')
|
||||||
|
assert isinstance(client.vcenter.ovf, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_vm_template_client():
|
||||||
|
assert hasattr(client.vcenter, 'vm_template')
|
||||||
|
assert isinstance(client.vcenter.vm_template, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_appliance_update_client():
|
||||||
|
assert hasattr(client.appliance, 'recovery')
|
||||||
|
assert isinstance(client.appliance.recovery, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_appliance_vmon_client():
|
||||||
|
assert hasattr(client.appliance, 'vmon')
|
||||||
|
assert isinstance(client.appliance.vmon, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_compute_policy_client():
|
||||||
|
assert hasattr(client.vcenter, 'compute')
|
||||||
|
assert isinstance(client.vcenter.compute, StubFactoryBase)
|
||||||
|
|
||||||
|
|
||||||
|
def test_vm_compute_policy_client():
|
||||||
|
assert hasattr(client.vcenter.vm, 'compute')
|
||||||
|
assert isinstance(client.vcenter.vm.compute, StubFactoryBase)
|
Loading…
Reference in New Issue
Block a user