mirror of
https://github.com/vmware/vsphere-automation-sdk-python.git
synced 2024-11-25 18:59:59 -05:00
Merge pull request #96 from tianhao64/master
Add tests to make sure vsphere client stubs are present
This commit is contained in:
commit
2939cc304f
@ -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