mirror of
https://github.com/ansible/awx.git
synced 2026-01-10 15:32:07 -03:30
VMware support within Tower.
This commit is contained in:
parent
2abf9ee653
commit
4723ad0a71
359
awx/lib/site-packages/psphere/__init__.py
Normal file
359
awx/lib/site-packages/psphere/__init__.py
Normal file
@ -0,0 +1,359 @@
|
||||
# Copyright 2010 Jonathan Kinred
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import time
|
||||
|
||||
from suds import MethodNotFound
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
__version__ = '0.5.2'
|
||||
__released__ = '0.5.2'
|
||||
|
||||
class cached_property(object):
|
||||
"""Decorator for read-only properties evaluated only once within TTL period.
|
||||
|
||||
It can be used to created a cached property like this::
|
||||
|
||||
import random
|
||||
|
||||
# the class containing the property must be a new-style class
|
||||
class MyClass(object):
|
||||
# create property whose value is cached for ten minutes
|
||||
@cached_property(ttl=600)
|
||||
def randint(self):
|
||||
# will only be evaluated every 10 min. at maximum.
|
||||
return random.randint(0, 100)
|
||||
|
||||
The value is cached in the '_cache' attribute of the object instance that
|
||||
has the property getter method wrapped by this decorator. The '_cache'
|
||||
attribute value is a dictionary which has a key for every property of the
|
||||
object which is wrapped by this decorator. Each entry in the cache is
|
||||
created only when the property is accessed for the first time and is a
|
||||
two-element tuple with the last computed property value and the last time
|
||||
it was updated in seconds since the epoch.
|
||||
|
||||
The default time-to-live (TTL) is 300 seconds (5 minutes). Set the TTL to
|
||||
zero for the cached value to never expire.
|
||||
|
||||
To expire a cached property value manually just do::
|
||||
|
||||
del instance._cache[<property name>]
|
||||
|
||||
"""
|
||||
def __init__(self, fget, doc=None):
|
||||
self.ttl = 300
|
||||
self.fget = fget
|
||||
self.__doc__ = doc or fget.__doc__
|
||||
self.__name__ = fget.__name__
|
||||
self.__module__ = fget.__module__
|
||||
|
||||
def __get__(self, inst, owner):
|
||||
now = time.time()
|
||||
try:
|
||||
# Get the value from the cache
|
||||
value, last_update = inst._cache[self.__name__]
|
||||
logger.info("Found cached value for %s", self.__name__)
|
||||
# If the value in the cache exceeds the TTL then raise
|
||||
# AttributeError so that we retrieve the value again below
|
||||
if self.ttl > 0 and now - last_update > self.ttl:
|
||||
logger.info("Cached value has exceeded TTL")
|
||||
raise AttributeError
|
||||
except (KeyError, AttributeError):
|
||||
# We end up here if the value hasn't been cached
|
||||
# or the value exceeds the TTL. We call the decorated
|
||||
# function to get the value.
|
||||
logger.info("%s is not cached.", self.__name__)
|
||||
value = self.fget(inst)
|
||||
try:
|
||||
# See if the instance has a cache attribute
|
||||
cache = inst._cache
|
||||
except AttributeError:
|
||||
# If it doesn't, initialise the attribute and use it
|
||||
cache = inst._cache = {}
|
||||
# Set the value in the cache dict to our values
|
||||
cache[self.__name__] = (value, now)
|
||||
# Finally, return either the value from the cache or the
|
||||
# newly retrieved value
|
||||
return value
|
||||
|
||||
|
||||
class ManagedObject(object):
|
||||
"""The base class which all managed object's derive from.
|
||||
|
||||
:param mo_ref: The managed object reference used to create this instance
|
||||
:type mo_ref: ManagedObjectReference
|
||||
:param client: A reference back to the psphere client object, which \
|
||||
we use to make calls.
|
||||
:type client: Client
|
||||
|
||||
"""
|
||||
_valid_attrs = set([])
|
||||
def __init__(self, mo_ref, client):
|
||||
self._cache = {}
|
||||
logger.debug("===== Have been passed %s as mo_ref: ", mo_ref)
|
||||
self._mo_ref = mo_ref
|
||||
self._client = client
|
||||
|
||||
def _get_dataobject(self, name, multivalued):
|
||||
"""This function only gets called if the decorated property
|
||||
doesn't have a value in the cache."""
|
||||
logger.debug("Querying server for uncached data object %s", name)
|
||||
# This will retrieve the value and inject it into the cache
|
||||
self.update_view_data(properties=[name])
|
||||
return self._cache[name][0]
|
||||
|
||||
def _get_mor(self, name, multivalued):
|
||||
"""This function only gets called if the decorated property
|
||||
doesn't have a value in the cache."""
|
||||
logger.debug("Querying server for uncached MOR %s", name)
|
||||
# This will retrieve the value and inject it into the cache
|
||||
logger.debug("Getting view for MOR")
|
||||
self.update(properties=[name])
|
||||
return self._cache[name][0]
|
||||
|
||||
# return self._cache[name][0]
|
||||
# if multivalued is True:
|
||||
# logger.debug("Getting views for MOR")
|
||||
# self.update(properties=[name])
|
||||
# views = self._client.get_views(self._cache[name][0])
|
||||
# return views
|
||||
# else:
|
||||
# logger.debug("Getting view for MOR")
|
||||
# self.update(properties=[name])
|
||||
# return self._cache[name][0]
|
||||
|
||||
def flush_cache(self, properties=None):
|
||||
"""Flushes the cache being held for this instance.
|
||||
|
||||
:param properties: The list of properties to flush from the cache.
|
||||
:type properties: list or None (default). If None, flush entire cache.
|
||||
|
||||
"""
|
||||
if hasattr(self, '_cache'):
|
||||
if properties is None:
|
||||
del(self._cache)
|
||||
else:
|
||||
for prop in properties:
|
||||
if prop in self._cache:
|
||||
del(self._cache[prop])
|
||||
|
||||
def update(self, properties=None):
|
||||
"""Updates the properties being held for this instance.
|
||||
|
||||
:param properties: The list of properties to update.
|
||||
:type properties: list or None (default). If None, update all
|
||||
currently cached properties.
|
||||
|
||||
"""
|
||||
if properties is None:
|
||||
try:
|
||||
self.update_view_data(properties=self._cache.keys())
|
||||
except AttributeError:
|
||||
# We end up here and ignore it self._cache doesn't exist
|
||||
pass
|
||||
else:
|
||||
self.update_view_data(properties=properties)
|
||||
|
||||
def _get_properties(self, properties=None):
|
||||
"""Retrieve the requested properties from the server.
|
||||
|
||||
:param properties: The list of properties to update.
|
||||
:type properties: list or None (default).
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
def update_view_data(self, properties=None):
|
||||
"""Update the local object from the server-side object.
|
||||
|
||||
>>> vm = VirtualMachine.find_one(client, filter={"name": "genesis"})
|
||||
>>> # Update all properties
|
||||
>>> vm.update_view_data()
|
||||
>>> # Update the config and summary properties
|
||||
>>> vm.update_view_data(properties=["config", "summary"]
|
||||
|
||||
:param properties: A list of properties to update.
|
||||
:type properties: list
|
||||
|
||||
"""
|
||||
if properties is None:
|
||||
properties = []
|
||||
logger.info("Updating view data for object of type %s",
|
||||
self._mo_ref._type)
|
||||
property_spec = self._client.create('PropertySpec')
|
||||
property_spec.type = str(self._mo_ref._type)
|
||||
# Determine which properties to retrieve from the server
|
||||
if properties is None:
|
||||
properties = []
|
||||
else:
|
||||
if properties == "all":
|
||||
logger.debug("Retrieving all properties")
|
||||
property_spec.all = True
|
||||
else:
|
||||
logger.debug("Retrieving %s properties", len(properties))
|
||||
property_spec.all = False
|
||||
property_spec.pathSet = properties
|
||||
|
||||
object_spec = self._client.create('ObjectSpec')
|
||||
object_spec.obj = self._mo_ref
|
||||
|
||||
pfs = self._client.create('PropertyFilterSpec')
|
||||
pfs.propSet = [property_spec]
|
||||
pfs.objectSet = [object_spec]
|
||||
|
||||
# Create a copy of the property collector and call the method
|
||||
pc = self._client.sc.propertyCollector
|
||||
object_content = pc.RetrieveProperties(specSet=pfs)[0]
|
||||
if not object_content:
|
||||
# TODO: Improve error checking and reporting
|
||||
logger.error("Nothing returned from RetrieveProperties!")
|
||||
|
||||
self._set_view_data(object_content)
|
||||
|
||||
def preload(self, name, properties=None):
|
||||
"""Pre-loads the requested properties for each object in the "name"
|
||||
attribute.
|
||||
|
||||
:param name: The name of the attribute containing the list to
|
||||
preload.
|
||||
:type name: str
|
||||
:param properties: The properties to preload on the objects or the
|
||||
string all to preload all properties.
|
||||
:type properties: list or the string "all"
|
||||
|
||||
"""
|
||||
if properties is None:
|
||||
raise ValueError("You must specify some properties to preload. To"
|
||||
" preload all properties use the string \"all\".")
|
||||
# Don't do anything if the attribute contains an empty list
|
||||
if not getattr(self, name):
|
||||
return
|
||||
|
||||
mo_refs = []
|
||||
# Iterate over each item and collect the mo_ref
|
||||
for item in getattr(self, name):
|
||||
# Make sure the items are ManagedObjectReference's
|
||||
if isinstance(item, ManagedObject) is False:
|
||||
raise ValueError("Only ManagedObject's can be pre-loaded.")
|
||||
|
||||
mo_refs.append(item._mo_ref)
|
||||
|
||||
# Send a single query to the server which gets views
|
||||
views = self._client.get_views(mo_refs, properties)
|
||||
|
||||
# Populate the inst.attr item with the retrieved object/properties
|
||||
self._cache[name] = (views, time.time())
|
||||
|
||||
def _set_view_data(self, object_content):
|
||||
"""Update the local object from the passed in object_content."""
|
||||
# A debugging convenience, allows inspection of the object_content
|
||||
# that was used to create the object
|
||||
logger.info("Setting view data for a %s", self.__class__)
|
||||
self._object_content = object_content
|
||||
|
||||
for dynprop in object_content.propSet:
|
||||
# If the class hasn't defined the property, don't use it
|
||||
if dynprop.name not in self._valid_attrs:
|
||||
logger.error("Server returned a property '%s' but the object"
|
||||
" hasn't defined it so it is being ignored." %
|
||||
dynprop.name)
|
||||
continue
|
||||
|
||||
try:
|
||||
if not len(dynprop.val):
|
||||
logger.info("Server returned empty value for %s",
|
||||
dynprop.name)
|
||||
except TypeError:
|
||||
# This except allows us to pass over:
|
||||
# TypeError: object of type 'datetime.datetime' has no len()
|
||||
# It will be processed in the next code block
|
||||
logger.info("%s of type %s has no len!",
|
||||
dynprop.name, type(dynprop.val))
|
||||
pass
|
||||
|
||||
try:
|
||||
# See if we have a cache attribute
|
||||
cache = self._cache
|
||||
except AttributeError:
|
||||
# If we don't create one and use it
|
||||
cache = self._cache = {}
|
||||
|
||||
# Values which contain classes starting with Array need
|
||||
# to be converted into a nicer Python list
|
||||
if dynprop.val.__class__.__name__.startswith('Array'):
|
||||
# suds returns a list containing a single item, which
|
||||
# is another list. Use the first item which is the real list
|
||||
logger.info("Setting value of an Array* property")
|
||||
logger.debug("%s being set to %s",
|
||||
dynprop.name, dynprop.val[0])
|
||||
now = time.time()
|
||||
cache[dynprop.name] = (dynprop.val[0], now)
|
||||
else:
|
||||
logger.info("Setting value of a single-valued property")
|
||||
logger.debug("DynamicProperty value is a %s: ",
|
||||
dynprop.val.__class__.__name__)
|
||||
logger.debug("%s being set to %s", dynprop.name, dynprop.val)
|
||||
now = time.time()
|
||||
cache[dynprop.name] = (dynprop.val, now)
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""Overridden so that SOAP methods can be proxied.
|
||||
|
||||
The magic contained here allows us to automatically access vSphere
|
||||
SOAP methods through the Python object, like:
|
||||
>>> client.si.content.rootFolder.CreateFolder(name="foo")
|
||||
|
||||
This is achieved by asking the underlying SOAP service if the
|
||||
requested name is a valid method. If the method name is not valid
|
||||
then we pass the attribute retrieval back to __getattribute__
|
||||
which will use the default behaviour (i.e. just get the attribute).
|
||||
|
||||
TODO: There's no checking if the SOAP method is valid for the type
|
||||
of object being called. e.g. You could do folder.Login() which would
|
||||
be totally bogus.
|
||||
|
||||
:param name: The name of the method to call.
|
||||
:param type: str
|
||||
|
||||
"""
|
||||
logger.debug("Entering overridden built-in __getattr__"
|
||||
" with %s" % name)
|
||||
# Built-ins always use the default behaviour
|
||||
# if name.startswith("__"):
|
||||
# logger.debug("Returning built-in attribute %s", name)
|
||||
# return object.__getattribute__(self, name)
|
||||
|
||||
# Here we must access _client through __getattribute__, if we were
|
||||
# to use "self._client" we'd call recursively through __getattr__
|
||||
client = object.__getattribute__(self, "_client")
|
||||
|
||||
try:
|
||||
getattr(client.service, name)
|
||||
except MethodNotFound:
|
||||
# It doesn't, so we let the object check if it's a standard
|
||||
# attribute. This is cool because it
|
||||
return object.__getattribute__(self, name)
|
||||
|
||||
# Caller has requested a valid SOAP reference
|
||||
logger.debug("Constructing proxy method %s for a %s",
|
||||
name, self._mo_ref._type)
|
||||
def func(**kwargs):
|
||||
result = self._client.invoke(name, _this=self._mo_ref,
|
||||
**kwargs)
|
||||
logger.debug("Invoke returned %s", result)
|
||||
return result
|
||||
|
||||
return func
|
||||
632
awx/lib/site-packages/psphere/client.py
Normal file
632
awx/lib/site-packages/psphere/client.py
Normal file
@ -0,0 +1,632 @@
|
||||
"""
|
||||
:mod:`psphere.client` - A client for communicating with a vSphere server
|
||||
========================================================================
|
||||
|
||||
.. module:: client
|
||||
|
||||
The main module for accessing a vSphere server.
|
||||
|
||||
.. moduleauthor:: Jonathan Kinred <jonathan.kinred@gmail.com>
|
||||
|
||||
"""
|
||||
|
||||
# Copyright 2010 Jonathan Kinred
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import logging
|
||||
import os
|
||||
import suds
|
||||
import time
|
||||
|
||||
from urllib2 import URLError
|
||||
from suds.plugin import MessagePlugin
|
||||
from suds.transport import TransportError
|
||||
|
||||
from psphere import soap, ManagedObject
|
||||
from psphere.config import _config_value
|
||||
from psphere.errors import (ConfigError, ObjectNotFoundError, TaskFailedError,
|
||||
NotLoggedInError)
|
||||
from psphere.managedobjects import ServiceInstance, Task, classmapper
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Client(suds.client.Client):
|
||||
"""A client for communicating with a VirtualCenter/ESX/ESXi server
|
||||
|
||||
>>> from psphere.client import Client
|
||||
>>> Client = Client(server="esx.foo.com", username="me", password="pass")
|
||||
|
||||
:param server: The server of the server. e.g. https://esx.foo.com/sdk
|
||||
:type server: str
|
||||
:param username: The username to connect with
|
||||
:type username: str
|
||||
:param password: The password to connect with
|
||||
:type password: str
|
||||
:param wsdl_location: Whether to use the provided WSDL or load the server WSDL
|
||||
:type wsdl_location: The string "local" (default) or "remote"
|
||||
:param timeout: The timeout to use when connecting to the server
|
||||
:type timeout: int (default=30)
|
||||
:param plugins: The plugins classes that will be used to process messages
|
||||
before send them to the web service
|
||||
:type plugins: list of classes
|
||||
"""
|
||||
def __init__(self, server=None, username=None, password=None,
|
||||
wsdl_location="local", timeout=30, plugins=[]):
|
||||
self._logged_in = False
|
||||
if server is None:
|
||||
server = _config_value("general", "server")
|
||||
if username is None:
|
||||
username = _config_value("general", "username")
|
||||
if password is None:
|
||||
password = _config_value("general", "password")
|
||||
if server is None:
|
||||
raise ConfigError("server must be set in config file or Client()")
|
||||
if username is None:
|
||||
raise ConfigError("username must be set in config file or Client()")
|
||||
if password is None:
|
||||
raise ConfigError("password must be set in config file or Client()")
|
||||
self.server = server
|
||||
self.username = username
|
||||
self.password = password
|
||||
url = "https://%s/sdk" % self.server
|
||||
if wsdl_location == "local":
|
||||
current_path = os.path.abspath(os.path.dirname(__file__))
|
||||
current_path = current_path.replace('\\', '/')
|
||||
if not current_path.startswith('/') :
|
||||
current_path = '/' + current_path
|
||||
if current_path.endswith('/') :
|
||||
current_path = current_path[:-1]
|
||||
wsdl_uri = ("file://%s/wsdl/vimService.wsdl" % current_path)
|
||||
elif wsdl_location == "remote":
|
||||
wsdl_uri = url + "/vimService.wsdl"
|
||||
else:
|
||||
raise ValueError("wsdl_location must be \"local\" or \"remote\"")
|
||||
# Init the base class
|
||||
try:
|
||||
# Add ExtraConfigPlugin to the plugins
|
||||
plugins.append(ExtraConfigPlugin())
|
||||
suds.client.Client.__init__(self, wsdl_uri, plugins=plugins)
|
||||
except URLError:
|
||||
logger.critical("Failed to connect to %s", self.server)
|
||||
raise
|
||||
except IOError:
|
||||
logger.critical("Failed to load the local WSDL from %s", wsdl_uri)
|
||||
raise
|
||||
except TransportError:
|
||||
logger.critical("Failed to load the remote WSDL from %s", wsdl_uri)
|
||||
raise
|
||||
self.options.transport.options.timeout = timeout
|
||||
self.set_options(location=url)
|
||||
mo_ref = soap.ManagedObjectReference("ServiceInstance",
|
||||
"ServiceInstance")
|
||||
self.si = ServiceInstance(mo_ref, self)
|
||||
try:
|
||||
self.sc = self.si.RetrieveServiceContent()
|
||||
except URLError, e:
|
||||
logger.critical("Failed to connect to %s" % self.server)
|
||||
logger.critical("urllib2 said: %s" % e.reason)
|
||||
raise
|
||||
|
||||
if self._logged_in is False:
|
||||
self.login(self.username, self.password)
|
||||
|
||||
def login(self, username=None, password=None):
|
||||
"""Login to a vSphere server.
|
||||
|
||||
>>> client.login(username='Administrator', password='strongpass')
|
||||
|
||||
:param username: The username to authenticate as.
|
||||
:type username: str
|
||||
:param password: The password to authenticate with.
|
||||
:type password: str
|
||||
"""
|
||||
if username is None:
|
||||
username = self.username
|
||||
if password is None:
|
||||
password = self.password
|
||||
logger.debug("Logging into server")
|
||||
self.sc.sessionManager.Login(userName=username, password=password)
|
||||
self._logged_in = True
|
||||
|
||||
def logout(self):
|
||||
"""Logout of a vSphere server."""
|
||||
if self._logged_in is True:
|
||||
self.si.flush_cache()
|
||||
self.sc.sessionManager.Logout()
|
||||
self._logged_in = False
|
||||
|
||||
def invoke(self, method, _this, **kwargs):
|
||||
"""Invoke a method on the server.
|
||||
|
||||
>>> client.invoke('CurrentTime', client.si)
|
||||
|
||||
:param method: The method to invoke, as found in the SDK.
|
||||
:type method: str
|
||||
:param _this: The managed object reference against which to invoke \
|
||||
the method.
|
||||
:type _this: ManagedObject
|
||||
:param kwargs: The arguments to pass to the method, as \
|
||||
found in the SDK.
|
||||
:type kwargs: TODO
|
||||
|
||||
"""
|
||||
if (self._logged_in is False and
|
||||
method not in ["Login", "RetrieveServiceContent"]):
|
||||
logger.critical("Cannot exec %s unless logged in", method)
|
||||
raise NotLoggedInError("Cannot exec %s unless logged in" % method)
|
||||
|
||||
for kwarg in kwargs:
|
||||
kwargs[kwarg] = self._marshal(kwargs[kwarg])
|
||||
|
||||
result = getattr(self.service, method)(_this=_this, **kwargs)
|
||||
if hasattr(result, '__iter__') is False:
|
||||
logger.debug("Returning non-iterable result")
|
||||
return result
|
||||
|
||||
# We must traverse the result and convert any ManagedObjectReference
|
||||
# to a psphere class, this will then be lazy initialised on use
|
||||
logger.debug(result.__class__)
|
||||
logger.debug("Result: %s", result)
|
||||
logger.debug("Length: %s", len(result))
|
||||
if type(result) == list:
|
||||
new_result = []
|
||||
for item in result:
|
||||
new_result.append(self._unmarshal(item))
|
||||
else:
|
||||
new_result = self._unmarshal(result)
|
||||
|
||||
logger.debug("Finished in invoke.")
|
||||
#property = self.find_and_destroy(property)
|
||||
#print result
|
||||
# Return the modified result to the caller
|
||||
return new_result
|
||||
|
||||
def _mor_to_pobject(self, mo_ref):
|
||||
"""Converts a MOR to a psphere object."""
|
||||
kls = classmapper(mo_ref._type)
|
||||
new_object = kls(mo_ref, self)
|
||||
return new_object
|
||||
|
||||
def _marshal(self, obj):
|
||||
"""Walks an object and marshals any psphere object into MORs."""
|
||||
logger.debug("Checking if %s needs to be marshalled", obj)
|
||||
if isinstance(obj, ManagedObject):
|
||||
logger.debug("obj is a psphere object, converting to MOR")
|
||||
return obj._mo_ref
|
||||
|
||||
if isinstance(obj, list):
|
||||
logger.debug("obj is a list, recursing it")
|
||||
new_list = []
|
||||
for item in obj:
|
||||
new_list.append(self._marshal(item))
|
||||
return new_list
|
||||
|
||||
if not isinstance(obj, suds.sudsobject.Object):
|
||||
logger.debug("%s is not a sudsobject subclass, skipping", obj)
|
||||
return obj
|
||||
|
||||
if hasattr(obj, '__iter__'):
|
||||
logger.debug("obj is iterable, recursing it")
|
||||
for (name, value) in obj:
|
||||
setattr(obj, name, self._marshal(value))
|
||||
return obj
|
||||
|
||||
# The obj has nothing that we want to marshal or traverse, return it
|
||||
logger.debug("obj doesn't need to be marshalled")
|
||||
return obj
|
||||
|
||||
def _unmarshal(self, obj):
|
||||
"""Walks an object and unmarshals any MORs into psphere objects."""
|
||||
if isinstance(obj, suds.sudsobject.Object) is False:
|
||||
logger.debug("%s is not a suds instance, skipping", obj)
|
||||
return obj
|
||||
|
||||
logger.debug("Processing:")
|
||||
logger.debug(obj)
|
||||
logger.debug("...with keylist:")
|
||||
logger.debug(obj.__keylist__)
|
||||
# If the obj that we're looking at has a _type key
|
||||
# then create a class of that type and return it immediately
|
||||
if "_type" in obj.__keylist__:
|
||||
logger.debug("obj is a MOR, converting to psphere class")
|
||||
return self._mor_to_pobject(obj)
|
||||
|
||||
new_object = obj.__class__()
|
||||
for sub_obj in obj:
|
||||
logger.debug("Looking at %s of type %s", sub_obj, type(sub_obj))
|
||||
|
||||
if isinstance(sub_obj[1], list):
|
||||
new_embedded_objs = []
|
||||
for emb_obj in sub_obj[1]:
|
||||
new_emb_obj = self._unmarshal(emb_obj)
|
||||
new_embedded_objs.append(new_emb_obj)
|
||||
setattr(new_object, sub_obj[0], new_embedded_objs)
|
||||
continue
|
||||
|
||||
if not issubclass(sub_obj[1].__class__, suds.sudsobject.Object):
|
||||
logger.debug("%s is not a sudsobject subclass, skipping",
|
||||
sub_obj[1].__class__)
|
||||
setattr(new_object, sub_obj[0], sub_obj[1])
|
||||
continue
|
||||
|
||||
logger.debug("Obj keylist: %s", sub_obj[1].__keylist__)
|
||||
if "_type" in sub_obj[1].__keylist__:
|
||||
logger.debug("Converting nested MOR to psphere class:")
|
||||
logger.debug(sub_obj[1])
|
||||
kls = classmapper(sub_obj[1]._type)
|
||||
logger.debug("Setting %s.%s to %s",
|
||||
new_object.__class__.__name__,
|
||||
sub_obj[0],
|
||||
sub_obj[1])
|
||||
setattr(new_object, sub_obj[0], kls(sub_obj[1], self))
|
||||
else:
|
||||
logger.debug("Didn't find _type in:")
|
||||
logger.debug(sub_obj[1])
|
||||
setattr(new_object, sub_obj[0], self._unmarshal(sub_obj[1]))
|
||||
|
||||
return new_object
|
||||
|
||||
def create(self, type_, **kwargs):
|
||||
"""Create a SOAP object of the requested type.
|
||||
|
||||
>>> client.create('VirtualE1000')
|
||||
|
||||
:param type_: The type of SOAP object to create.
|
||||
:type type_: str
|
||||
:param kwargs: TODO
|
||||
:type kwargs: TODO
|
||||
|
||||
"""
|
||||
obj = self.factory.create("ns0:%s" % type_)
|
||||
for key, value in kwargs.items():
|
||||
setattr(obj, key, value)
|
||||
return obj
|
||||
|
||||
# Notes
|
||||
# -----
|
||||
# A view is a local, static representation of a managed object in
|
||||
# the inventory. The view is not automatically synchronised with
|
||||
# the server-side object and can therefore be out of date a moment
|
||||
# after it is retrieved.
|
||||
#
|
||||
# Retrieval of only the properties you intend to use -- through
|
||||
# the use of the properties parameter -- is considered best
|
||||
# practise as the properties of some managed objects can be
|
||||
# costly to retrieve.
|
||||
|
||||
def get_view(self, mo_ref, properties=None):
|
||||
"""Get a view of a vSphere managed object.
|
||||
|
||||
:param mo_ref: The MOR to get a view of
|
||||
:type mo_ref: ManagedObjectReference
|
||||
:param properties: A list of properties to retrieve from the \
|
||||
server
|
||||
:type properties: list
|
||||
:returns: A view representing the ManagedObjectReference.
|
||||
:rtype: ManagedObject
|
||||
|
||||
"""
|
||||
# This maps the mo_ref into a psphere class and then instantiates it
|
||||
kls = classmapper(mo_ref._type)
|
||||
view = kls(mo_ref, self)
|
||||
# Update the requested properties of the instance
|
||||
#view.update_view_data(properties=properties)
|
||||
|
||||
return view
|
||||
|
||||
def get_views(self, mo_refs, properties=None):
|
||||
"""Get a list of local view's for multiple managed objects.
|
||||
|
||||
:param mo_refs: The list of ManagedObjectReference's that views are \
|
||||
to be created for.
|
||||
:type mo_refs: ManagedObjectReference
|
||||
:param properties: The properties to retrieve in the views.
|
||||
:type properties: list
|
||||
:returns: A list of local instances representing the server-side \
|
||||
managed objects.
|
||||
:rtype: list of ManagedObject's
|
||||
|
||||
"""
|
||||
property_specs = []
|
||||
for mo_ref in mo_refs:
|
||||
property_spec = self.create('PropertySpec')
|
||||
property_spec.type = str(mo_ref._type)
|
||||
if properties is None:
|
||||
properties = []
|
||||
else:
|
||||
# Only retrieve the requested properties
|
||||
if properties == "all":
|
||||
property_spec.all = True
|
||||
else:
|
||||
property_spec.all = False
|
||||
property_spec.pathSet = properties
|
||||
property_specs.append(property_spec)
|
||||
|
||||
object_specs = []
|
||||
for mo_ref in mo_refs:
|
||||
object_spec = self.create('ObjectSpec')
|
||||
object_spec.obj = mo_ref
|
||||
object_specs.append(object_spec)
|
||||
|
||||
pfs = self.create('PropertyFilterSpec')
|
||||
pfs.propSet = property_specs
|
||||
pfs.objectSet = object_specs
|
||||
|
||||
object_contents = self.sc.propertyCollector.RetrieveProperties(
|
||||
specSet=pfs)
|
||||
views = []
|
||||
for object_content in object_contents:
|
||||
# Update the instance with the data in object_content
|
||||
object_content.obj._set_view_data(object_content=object_content)
|
||||
views.append(object_content.obj)
|
||||
|
||||
return views
|
||||
|
||||
def get_search_filter_spec(self, begin_entity, property_spec):
|
||||
"""Build a PropertyFilterSpec capable of full inventory traversal.
|
||||
|
||||
By specifying all valid traversal specs we are creating a PFS that
|
||||
can recursively select any object under the given entity.
|
||||
|
||||
:param begin_entity: The place in the MOB to start the search.
|
||||
:type begin_entity: ManagedEntity
|
||||
:param property_spec: TODO
|
||||
:type property_spec: TODO
|
||||
:returns: A PropertyFilterSpec, suitable for recursively searching \
|
||||
under the given ManagedEntity.
|
||||
:rtype: PropertyFilterSpec
|
||||
|
||||
"""
|
||||
# The selection spec for additional objects we want to filter
|
||||
ss_strings = ['resource_pool_traversal_spec',
|
||||
'resource_pool_vm_traversal_spec',
|
||||
'folder_traversal_spec',
|
||||
'datacenter_host_traversal_spec',
|
||||
'datacenter_vm_traversal_spec',
|
||||
'compute_resource_rp_traversal_spec',
|
||||
'compute_resource_host_traversal_spec',
|
||||
'host_vm_traversal_spec']
|
||||
|
||||
# Create a selection spec for each of the strings specified above
|
||||
selection_specs = [
|
||||
self.create('SelectionSpec', name=ss_string)
|
||||
for ss_string in ss_strings
|
||||
]
|
||||
|
||||
# A traversal spec for deriving ResourcePool's from found VMs
|
||||
rpts = self.create('TraversalSpec')
|
||||
rpts.name = 'resource_pool_traversal_spec'
|
||||
rpts.type = 'ResourcePool'
|
||||
rpts.path = 'resourcePool'
|
||||
rpts.selectSet = [selection_specs[0], selection_specs[1]]
|
||||
|
||||
# A traversal spec for deriving ResourcePool's from found VMs
|
||||
rpvts = self.create('TraversalSpec')
|
||||
rpvts.name = 'resource_pool_vm_traversal_spec'
|
||||
rpvts.type = 'ResourcePool'
|
||||
rpvts.path = 'vm'
|
||||
|
||||
crrts = self.create('TraversalSpec')
|
||||
crrts.name = 'compute_resource_rp_traversal_spec'
|
||||
crrts.type = 'ComputeResource'
|
||||
crrts.path = 'resourcePool'
|
||||
crrts.selectSet = [selection_specs[0], selection_specs[1]]
|
||||
|
||||
crhts = self.create('TraversalSpec')
|
||||
crhts.name = 'compute_resource_host_traversal_spec'
|
||||
crhts.type = 'ComputeResource'
|
||||
crhts.path = 'host'
|
||||
|
||||
dhts = self.create('TraversalSpec')
|
||||
dhts.name = 'datacenter_host_traversal_spec'
|
||||
dhts.type = 'Datacenter'
|
||||
dhts.path = 'hostFolder'
|
||||
dhts.selectSet = [selection_specs[2]]
|
||||
|
||||
dvts = self.create('TraversalSpec')
|
||||
dvts.name = 'datacenter_vm_traversal_spec'
|
||||
dvts.type = 'Datacenter'
|
||||
dvts.path = 'vmFolder'
|
||||
dvts.selectSet = [selection_specs[2]]
|
||||
|
||||
hvts = self.create('TraversalSpec')
|
||||
hvts.name = 'host_vm_traversal_spec'
|
||||
hvts.type = 'HostSystem'
|
||||
hvts.path = 'vm'
|
||||
hvts.selectSet = [selection_specs[2]]
|
||||
|
||||
fts = self.create('TraversalSpec')
|
||||
fts.name = 'folder_traversal_spec'
|
||||
fts.type = 'Folder'
|
||||
fts.path = 'childEntity'
|
||||
fts.selectSet = [selection_specs[2], selection_specs[3],
|
||||
selection_specs[4], selection_specs[5],
|
||||
selection_specs[6], selection_specs[7],
|
||||
selection_specs[1]]
|
||||
|
||||
obj_spec = self.create('ObjectSpec')
|
||||
obj_spec.obj = begin_entity
|
||||
obj_spec.selectSet = [fts, dvts, dhts, crhts, crrts,
|
||||
rpts, hvts, rpvts]
|
||||
|
||||
pfs = self.create('PropertyFilterSpec')
|
||||
pfs.propSet = [property_spec]
|
||||
pfs.objectSet = [obj_spec]
|
||||
return pfs
|
||||
|
||||
def invoke_task(self, method, **kwargs):
|
||||
"""Execute a \*_Task method and wait for it to complete.
|
||||
|
||||
:param method: The \*_Task method to invoke.
|
||||
:type method: str
|
||||
:param kwargs: The arguments to pass to the method.
|
||||
:type kwargs: TODO
|
||||
|
||||
"""
|
||||
# Don't execute methods which don't return a Task object
|
||||
if not method.endswith('_Task'):
|
||||
logger.error('invoke_task can only be used for methods which '
|
||||
'return a ManagedObjectReference to a Task.')
|
||||
return None
|
||||
|
||||
task_mo_ref = self.invoke(method=method, **kwargs)
|
||||
task = Task(task_mo_ref, self)
|
||||
task.update_view_data(properties=['info'])
|
||||
# TODO: This returns true when there is an error
|
||||
while True:
|
||||
if task.info.state == 'success':
|
||||
return task
|
||||
elif task.info.state == 'error':
|
||||
# TODO: Handle error checking properly
|
||||
raise TaskFailedError(task.info.error.localizedMessage)
|
||||
|
||||
# TODO: Implement progresscallbackfunc
|
||||
# Sleep two seconds and then refresh the data from the server
|
||||
time.sleep(2)
|
||||
task.update_view_data(properties=['info'])
|
||||
|
||||
def find_entity_views(self, view_type, begin_entity=None, properties=None):
|
||||
"""Find all ManagedEntity's of the requested type.
|
||||
|
||||
:param view_type: The type of ManagedEntity's to find.
|
||||
:type view_type: str
|
||||
:param begin_entity: The MOR to start searching for the entity. \
|
||||
The default is to start the search at the root folder.
|
||||
:type begin_entity: ManagedObjectReference or None
|
||||
:returns: A list of ManagedEntity's
|
||||
:rtype: list
|
||||
|
||||
"""
|
||||
if properties is None:
|
||||
properties = []
|
||||
|
||||
# Start the search at the root folder if no begin_entity was given
|
||||
if not begin_entity:
|
||||
begin_entity = self.sc.rootFolder._mo_ref
|
||||
|
||||
property_spec = self.create('PropertySpec')
|
||||
property_spec.type = view_type
|
||||
property_spec.all = False
|
||||
property_spec.pathSet = properties
|
||||
|
||||
pfs = self.get_search_filter_spec(begin_entity, property_spec)
|
||||
|
||||
# Retrieve properties from server and update entity
|
||||
obj_contents = self.sc.propertyCollector.RetrieveProperties(specSet=pfs)
|
||||
|
||||
views = []
|
||||
for obj_content in obj_contents:
|
||||
logger.debug("In find_entity_view with object of type %s",
|
||||
obj_content.obj.__class__.__name__)
|
||||
obj_content.obj.update_view_data(properties=properties)
|
||||
views.append(obj_content.obj)
|
||||
|
||||
return views
|
||||
|
||||
def find_entity_view(self, view_type, begin_entity=None, filter={},
|
||||
properties=None):
|
||||
"""Find a ManagedEntity of the requested type.
|
||||
|
||||
Traverses the MOB looking for an entity matching the filter.
|
||||
|
||||
:param view_type: The type of ManagedEntity to find.
|
||||
:type view_type: str
|
||||
:param begin_entity: The MOR to start searching for the entity. \
|
||||
The default is to start the search at the root folder.
|
||||
:type begin_entity: ManagedObjectReference or None
|
||||
:param filter: Key/value pairs to filter the results. The key is \
|
||||
a valid parameter of the ManagedEntity type. The value is what \
|
||||
that parameter should match.
|
||||
:type filter: dict
|
||||
:returns: If an entity is found, a ManagedEntity matching the search.
|
||||
:rtype: ManagedEntity
|
||||
|
||||
"""
|
||||
if properties is None:
|
||||
properties = []
|
||||
|
||||
kls = classmapper(view_type)
|
||||
# Start the search at the root folder if no begin_entity was given
|
||||
if not begin_entity:
|
||||
begin_entity = self.sc.rootFolder._mo_ref
|
||||
logger.debug("Using %s", self.sc.rootFolder._mo_ref)
|
||||
|
||||
property_spec = self.create('PropertySpec')
|
||||
property_spec.type = view_type
|
||||
property_spec.all = False
|
||||
property_spec.pathSet = filter.keys()
|
||||
|
||||
pfs = self.get_search_filter_spec(begin_entity, property_spec)
|
||||
|
||||
# Retrieve properties from server and update entity
|
||||
#obj_contents = self.propertyCollector.RetrieveProperties(specSet=pfs)
|
||||
obj_contents = self.sc.propertyCollector.RetrieveProperties(specSet=pfs)
|
||||
|
||||
# TODO: Implement filtering
|
||||
if not filter:
|
||||
logger.warning('No filter specified, returning first match.')
|
||||
# If no filter is specified we just return the first item
|
||||
# in the list of returned objects
|
||||
logger.debug("Creating class in find_entity_view (filter)")
|
||||
view = kls(obj_contents[0].obj, self)
|
||||
logger.debug("Completed creating class in find_entity_view (filter)")
|
||||
#view.update_view_data(properties)
|
||||
return view
|
||||
|
||||
matched = False
|
||||
# Iterate through obj_contents retrieved
|
||||
for obj_content in obj_contents:
|
||||
# If there are is no propSet, skip this one
|
||||
if not obj_content.propSet:
|
||||
continue
|
||||
|
||||
matches = 0
|
||||
# Iterate through each property in the set
|
||||
for prop in obj_content.propSet:
|
||||
for key in filter.keys():
|
||||
# If the property name is in the defined filter
|
||||
if prop.name == key:
|
||||
# ...and it matches the value specified
|
||||
# TODO: Regex this?
|
||||
if prop.val == filter[prop.name]:
|
||||
# We've found a match
|
||||
matches += 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
continue
|
||||
if matches == len(filter):
|
||||
filtered_obj_content = obj_content
|
||||
matched = True
|
||||
break
|
||||
else:
|
||||
continue
|
||||
|
||||
if matched is not True:
|
||||
# There were no matches
|
||||
raise ObjectNotFoundError("No matching objects for filter")
|
||||
|
||||
logger.debug("Creating class in find_entity_view")
|
||||
view = kls(filtered_obj_content.obj._mo_ref, self)
|
||||
logger.debug("Completed creating class in find_entity_view")
|
||||
#view.update_view_data(properties=properties)
|
||||
return view
|
||||
|
||||
class ExtraConfigPlugin(MessagePlugin):
|
||||
def addAttributeForValue(self, node):
|
||||
if node.parent.name == 'extraConfig' and node.name == 'value':
|
||||
node.set('xsi:type', 'xsd:string')
|
||||
def marshalled(self, context):
|
||||
context.envelope.walk(self.addAttributeForValue)
|
||||
26
awx/lib/site-packages/psphere/config.py
Normal file
26
awx/lib/site-packages/psphere/config.py
Normal file
@ -0,0 +1,26 @@
|
||||
import os
|
||||
import yaml
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
config_path = os.path.expanduser('~/.psphere/config.yaml')
|
||||
try:
|
||||
config_file = open(config_path, "r")
|
||||
PSPHERE_CONFIG = yaml.load(config_file)
|
||||
config_file.close()
|
||||
except IOError:
|
||||
logger.warning("Configuration file %s could not be opened, perhaps you"
|
||||
" haven't created one?" % config_path)
|
||||
PSPHERE_CONFIG = {"general": {}, "logging": {}}
|
||||
pass
|
||||
|
||||
|
||||
def _config_value(section, name, default=None):
|
||||
file_value = None
|
||||
if name in PSPHERE_CONFIG[section]:
|
||||
file_value = PSPHERE_CONFIG[section][name]
|
||||
|
||||
if file_value:
|
||||
return file_value
|
||||
else:
|
||||
return default
|
||||
37
awx/lib/site-packages/psphere/errors.py
Normal file
37
awx/lib/site-packages/psphere/errors.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright 2010 Jonathan Kinred
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
class ConfigError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NotLoggedInError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ObjectNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TaskFailedError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class TemplateNotFoundError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class NotImplementedError(Exception):
|
||||
pass
|
||||
1500
awx/lib/site-packages/psphere/managedobjects.py
Normal file
1500
awx/lib/site-packages/psphere/managedobjects.py
Normal file
File diff suppressed because it is too large
Load Diff
106
awx/lib/site-packages/psphere/scripting.py
Normal file
106
awx/lib/site-packages/psphere/scripting.py
Normal file
@ -0,0 +1,106 @@
|
||||
|
||||
"""
|
||||
Parse command line options, allow users to append their own options and
|
||||
read predefined configuration from the users .visdkrc file.
|
||||
"""
|
||||
|
||||
# Copyright 2010 Jonathan Kinred
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import optparse
|
||||
|
||||
class BaseScript(object):
|
||||
def __init__(self, client):
|
||||
self.client = client
|
||||
self.required_opts = []
|
||||
|
||||
usage = ('usage: %prog --url https://<host>/sdk --username <username> '
|
||||
'--password <password>')
|
||||
self.parser = optparse.OptionParser(usage)
|
||||
self.parser.add_option('--url', dest='url',
|
||||
help='the url of the vSphere server')
|
||||
self.parser.add_option('--username', dest='username',
|
||||
help='the username to connnect with')
|
||||
self.parser.add_option('--password', dest='password',
|
||||
help='the password to connect with')
|
||||
|
||||
def add_option(self, opt, dest, help, required):
|
||||
self.parser.add_option(opt, dest=dest, help=help)
|
||||
# TODO: Append to usage
|
||||
# Add to the list of required options which we'll use later
|
||||
if required:
|
||||
self.required_opts.append(dest)
|
||||
|
||||
def get_options(self):
|
||||
"""Get the options that have been set.
|
||||
|
||||
Called after the user has added all their own options
|
||||
and is ready to use the variables.
|
||||
|
||||
"""
|
||||
(options, args) = self.parser.parse_args()
|
||||
|
||||
# Set values from .visdkrc, but only if they haven't already been set
|
||||
visdkrc_opts = self.read_visdkrc()
|
||||
for opt in self.config_vars:
|
||||
if not getattr(options, opt):
|
||||
# Try and use value from visdkrc
|
||||
if visdkrc_opts:
|
||||
if opt in visdkrc_opts:
|
||||
setattr(options, opt, visdkrc_opts[opt])
|
||||
|
||||
# Ensure all the required options are set
|
||||
for opt in self.required_opts:
|
||||
if opt not in dir(options) or getattr(options, opt) == None:
|
||||
self.parser.error('%s must be set!' % opt)
|
||||
|
||||
return options
|
||||
|
||||
def read_visdkrc(self):
|
||||
try:
|
||||
config = open(self.visdkrc)
|
||||
except IOError, e:
|
||||
if e.errno == 2:
|
||||
# Doesn't exist, ignore it
|
||||
return None
|
||||
elif e.errno == 13:
|
||||
print('ERROR: Permission denied opening %s' % self.visdkrc)
|
||||
return None
|
||||
else:
|
||||
print('ERROR: Could not open %s: %s' % (self.visdkrc, e.strerror))
|
||||
return None
|
||||
|
||||
lines = config.readlines()
|
||||
config.close()
|
||||
|
||||
parsed_opts = {}
|
||||
for line in lines:
|
||||
(key, value) = line.split('=')
|
||||
parsed_opts[key] = value.rstrip('\n')
|
||||
|
||||
visdkrc_opts = {}
|
||||
if('VI_PROTOCOL' in parsed_opts and 'VI_SERVER' in parsed_opts and
|
||||
'VI_SERVICEPATH' in parsed_opts):
|
||||
visdkrc_opts['url'] = '%s://%s%s' % (parsed_opts['VI_PROTOCOL'],
|
||||
parsed_opts['VI_SERVER'],
|
||||
parsed_opts['VI_SERVICEPATH'])
|
||||
if 'VI_USERNAME' in parsed_opts:
|
||||
visdkrc_opts['username'] = parsed_opts['VI_USERNAME']
|
||||
|
||||
if 'VI_PASSWORD' in parsed_opts:
|
||||
visdkrc_opts['password'] = parsed_opts['VI_PASSWORD']
|
||||
|
||||
return visdkrc_opts
|
||||
|
||||
95
awx/lib/site-packages/psphere/soap.py
Normal file
95
awx/lib/site-packages/psphere/soap.py
Normal file
@ -0,0 +1,95 @@
|
||||
"""
|
||||
A leaky wrapper for the underlying suds library.
|
||||
"""
|
||||
|
||||
# Copyright 2010 Jonathan Kinred
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
# use this file except in compliance with the License. You may obtain a copy
|
||||
# of the License at:
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import logging
|
||||
import urllib2
|
||||
import suds
|
||||
|
||||
from pprint import pprint
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class VimFault(Exception):
|
||||
def __init__(self, fault):
|
||||
self.fault = fault
|
||||
self.fault_type = fault.__class__.__name__
|
||||
self._fault_dict = {}
|
||||
for attr in fault:
|
||||
self._fault_dict[attr[0]] = attr[1]
|
||||
|
||||
Exception.__init__(self, "%s: %s" % (self.fault_type, self._fault_dict))
|
||||
|
||||
|
||||
def get_client(url):
|
||||
client = suds.client.Client(url + "/vimService.wsdl")
|
||||
client.set_options(location=url)
|
||||
return client
|
||||
|
||||
|
||||
def create(client, _type, **kwargs):
|
||||
"""Create a suds object of the requested _type."""
|
||||
obj = client.factory.create("ns0:%s" % _type)
|
||||
for key, value in kwargs.items():
|
||||
setattr(obj, key, value)
|
||||
return obj
|
||||
|
||||
|
||||
def invoke(client, method, **kwargs):
|
||||
"""Invoke a method on the underlying soap service."""
|
||||
try:
|
||||
# Proxy the method to the suds service
|
||||
result = getattr(client.service, method)(**kwargs)
|
||||
except AttributeError, e:
|
||||
logger.critical("Unknown method: %s", method)
|
||||
raise
|
||||
except urllib2.URLError, e:
|
||||
logger.debug(pprint(e))
|
||||
logger.debug("A URL related error occurred while invoking the '%s' "
|
||||
"method on the VIM server, this can be caused by "
|
||||
"name resolution or connection problems.", method)
|
||||
logger.debug("The underlying error is: %s", e.reason[1])
|
||||
raise
|
||||
except suds.client.TransportError, e:
|
||||
logger.debug(pprint(e))
|
||||
logger.debug("TransportError: %s", e)
|
||||
except suds.WebFault, e:
|
||||
# Get the type of fault
|
||||
logger.critical("SUDS Fault: %s" % e.fault.faultstring)
|
||||
if len(e.fault.faultstring) > 0:
|
||||
raise
|
||||
|
||||
detail = e.document.childAtPath("/Envelope/Body/Fault/detail")
|
||||
fault_type = detail.getChildren()[0].name
|
||||
fault = create(fault_type)
|
||||
if isinstance(e.fault.detail[0], list):
|
||||
for attr in e.fault.detail[0]:
|
||||
setattr(fault, attr[0], attr[1])
|
||||
else:
|
||||
fault["text"] = e.fault.detail[0]
|
||||
|
||||
raise VimFault(fault)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class ManagedObjectReference(suds.sudsobject.Property):
|
||||
"""Custom class to replace the suds generated class, which lacks _type."""
|
||||
def __init__(self, _type, value):
|
||||
suds.sudsobject.Property.__init__(self, value)
|
||||
self._type = _type
|
||||
61
awx/lib/site-packages/psphere/template.py
Normal file
61
awx/lib/site-packages/psphere/template.py
Normal file
@ -0,0 +1,61 @@
|
||||
import glob
|
||||
import os
|
||||
import yaml
|
||||
import logging
|
||||
|
||||
from psphere import config
|
||||
from psphere.errors import TemplateNotFoundError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
template_path = os.path.expanduser(config._config_value("general",
|
||||
"template_dir"))
|
||||
|
||||
def _merge(first, second):
|
||||
"""Merge a list of templates.
|
||||
|
||||
The templates will be merged with values in higher templates
|
||||
taking precedence.
|
||||
|
||||
:param templates: The templates to merge.
|
||||
:type templates: list
|
||||
|
||||
"""
|
||||
return dict(first.items() + second.items())
|
||||
|
||||
|
||||
def load_template(name=None):
|
||||
"""Loads a template of the specified name.
|
||||
|
||||
Templates are placed in the <template_dir> directory in YAML format with
|
||||
a .yaml extension.
|
||||
|
||||
If no name is specified then the function will return the default
|
||||
template (<template_dir>/default.yaml) if it exists.
|
||||
|
||||
:param name: The name of the template to load.
|
||||
:type name: str or None (default)
|
||||
|
||||
"""
|
||||
if name is None:
|
||||
name = "default"
|
||||
|
||||
logger.info("Loading template with name %s", name)
|
||||
try:
|
||||
template_file = open("%s/%s.yaml" % (template_path, name))
|
||||
except IOError:
|
||||
raise TemplateNotFoundError
|
||||
|
||||
template = yaml.safe_load(template_file)
|
||||
template_file.close()
|
||||
if "extends" in template:
|
||||
logger.debug("Merging %s with %s", name, template["extends"])
|
||||
template = _merge(load_template(template["extends"]), template)
|
||||
|
||||
return template
|
||||
|
||||
|
||||
def list_templates():
|
||||
"""Returns a list of all templates."""
|
||||
templates = [f for f in glob.glob(os.path.join(template_path, '*.yaml'))]
|
||||
return templates
|
||||
267
awx/lib/site-packages/psphere/wsdl/core-types.xsd
Normal file
267
awx/lib/site-packages/psphere/wsdl/core-types.xsd
Normal file
@ -0,0 +1,267 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
Copyright 2005-2010 VMware, Inc. All rights reserved.
|
||||
-->
|
||||
<schema
|
||||
targetNamespace="urn:vim25"
|
||||
xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:vim25="urn:vim25"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
>
|
||||
<complexType name="DynamicArray">
|
||||
<sequence>
|
||||
<element name="dynamicType" type="xsd:string" minOccurs="0" />
|
||||
<element name="val" type="xsd:anyType" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="DynamicData">
|
||||
<sequence>
|
||||
<element name="dynamicType" type="xsd:string" minOccurs="0" />
|
||||
<element name="dynamicProperty" type="vim25:DynamicProperty" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="DynamicProperty">
|
||||
<sequence>
|
||||
<element name="name" type="xsd:string" />
|
||||
<element name="val" type="xsd:anyType" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfDynamicProperty">
|
||||
<sequence>
|
||||
<element name="DynamicProperty" type="vim25:DynamicProperty" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="KeyAnyValue">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="key" type="xsd:string" />
|
||||
<element name="value" type="xsd:anyType" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfKeyAnyValue">
|
||||
<sequence>
|
||||
<element name="KeyAnyValue" type="vim25:KeyAnyValue" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="LocalizableMessage">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="key" type="xsd:string" />
|
||||
<element name="arg" type="vim25:KeyAnyValue" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="message" type="xsd:string" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfLocalizableMessage">
|
||||
<sequence>
|
||||
<element name="LocalizableMessage" type="vim25:LocalizableMessage" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="HostCommunication">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="HostNotConnected">
|
||||
<complexContent>
|
||||
<extension base="vim25:HostCommunication">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="HostNotReachable">
|
||||
<complexContent>
|
||||
<extension base="vim25:HostCommunication">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="InvalidArgument">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
<element name="invalidProperty" type="xsd:string" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="InvalidRequest">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="InvalidType">
|
||||
<complexContent>
|
||||
<extension base="vim25:InvalidRequest">
|
||||
<sequence>
|
||||
<element name="argument" type="xsd:string" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ManagedObjectNotFound">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
<element name="obj" type="vim25:ManagedObjectReference" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="MethodNotFound">
|
||||
<complexContent>
|
||||
<extension base="vim25:InvalidRequest">
|
||||
<sequence>
|
||||
<element name="receiver" type="vim25:ManagedObjectReference" />
|
||||
<element name="method" type="xsd:string" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="NotEnoughLicenses">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="NotImplemented">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="NotSupported">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="RequestCanceled">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="SecurityError">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="SystemError">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
<element name="reason" type="xsd:string" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="UnexpectedFault">
|
||||
<complexContent>
|
||||
<extension base="vim25:RuntimeFault">
|
||||
<sequence>
|
||||
<element name="faultName" type="xsd:string" />
|
||||
<element name="fault" type="vim25:LocalizedMethodFault" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="LocalizedMethodFault">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="fault" type="vim25:MethodFault" />
|
||||
<element name="localizedMessage" type="xsd:string" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="MethodFault">
|
||||
<sequence>
|
||||
<element name="dynamicType" type="xsd:string" minOccurs="0" />
|
||||
<element name="dynamicProperty" type="vim25:DynamicProperty" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="faultCause" type="vim25:LocalizedMethodFault" minOccurs="0" />
|
||||
<element name="faultMessage" type="vim25:LocalizableMessage" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfMethodFault">
|
||||
<sequence>
|
||||
<element name="MethodFault" type="vim25:MethodFault" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="RuntimeFault">
|
||||
<complexContent>
|
||||
<extension base="vim25:MethodFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ManagedObjectReference">
|
||||
<simpleContent>
|
||||
<extension base="xsd:string">
|
||||
<attribute name="type" type="xsd:string"/>
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfString">
|
||||
<sequence>
|
||||
<element name="string" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfAnyType">
|
||||
<sequence>
|
||||
<element name="anyType" type="xsd:anyType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfManagedObjectReference">
|
||||
<sequence>
|
||||
<element name="ManagedObjectReference" type="vim25:ManagedObjectReference" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfByte">
|
||||
<sequence>
|
||||
<element name="byte" type="xsd:byte" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfInt">
|
||||
<sequence>
|
||||
<element name="int" type="xsd:int" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfLong">
|
||||
<sequence>
|
||||
<element name="long" type="xsd:long" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfShort">
|
||||
<sequence>
|
||||
<element name="short" type="xsd:short" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
</schema>
|
||||
85
awx/lib/site-packages/psphere/wsdl/query-messagetypes.xsd
Normal file
85
awx/lib/site-packages/psphere/wsdl/query-messagetypes.xsd
Normal file
@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
Copyright 2005-2010 VMware, Inc. All rights reserved.
|
||||
-->
|
||||
<schema
|
||||
targetNamespace="urn:vim25"
|
||||
xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:vim25="urn:vim25"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
>
|
||||
<include schemaLocation="core-types.xsd" />
|
||||
<include schemaLocation="query-types.xsd" />
|
||||
<complexType name="DestroyPropertyFilterRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="CreateFilterRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="spec" type="vim25:PropertyFilterSpec" />
|
||||
<element name="partialUpdates" type="xsd:boolean" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="RetrievePropertiesRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="specSet" type="vim25:PropertyFilterSpec" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="CheckForUpdatesRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="version" type="xsd:string" minOccurs="0" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="WaitForUpdatesRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="version" type="xsd:string" minOccurs="0" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="CancelWaitForUpdatesRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="WaitForUpdatesExRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="version" type="xsd:string" minOccurs="0" />
|
||||
<element name="options" type="vim25:WaitOptions" minOccurs="0" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="RetrievePropertiesExRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="specSet" type="vim25:PropertyFilterSpec" maxOccurs="unbounded" />
|
||||
<element name="options" type="vim25:RetrieveOptions" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ContinueRetrievePropertiesExRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="token" type="xsd:string" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="CancelRetrievePropertiesExRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
<element name="token" type="xsd:string" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="CreatePropertyCollectorRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="DestroyPropertyCollectorRequestType">
|
||||
<sequence>
|
||||
<element name="_this" type="vim25:ManagedObjectReference" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
</schema>
|
||||
254
awx/lib/site-packages/psphere/wsdl/query-types.xsd
Normal file
254
awx/lib/site-packages/psphere/wsdl/query-types.xsd
Normal file
@ -0,0 +1,254 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
Copyright 2005-2010 VMware, Inc. All rights reserved.
|
||||
-->
|
||||
<schema
|
||||
targetNamespace="urn:vim25"
|
||||
xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:vim25="urn:vim25"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
>
|
||||
<include schemaLocation="core-types.xsd" />
|
||||
<complexType name="InvalidCollectorVersion">
|
||||
<complexContent>
|
||||
<extension base="vim25:MethodFault">
|
||||
<sequence>
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="InvalidProperty">
|
||||
<complexContent>
|
||||
<extension base="vim25:MethodFault">
|
||||
<sequence>
|
||||
<element name="name" type="xsd:string" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="PropertyFilterSpec">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="propSet" type="vim25:PropertySpec" maxOccurs="unbounded" />
|
||||
<element name="objectSet" type="vim25:ObjectSpec" maxOccurs="unbounded" />
|
||||
<element name="reportMissingObjectsInResults" type="xsd:boolean" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfPropertyFilterSpec">
|
||||
<sequence>
|
||||
<element name="PropertyFilterSpec" type="vim25:PropertyFilterSpec" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="PropertySpec">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="type" type="xsd:string" />
|
||||
<element name="all" type="xsd:boolean" minOccurs="0" />
|
||||
<element name="pathSet" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfPropertySpec">
|
||||
<sequence>
|
||||
<element name="PropertySpec" type="vim25:PropertySpec" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="ObjectSpec">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="obj" type="vim25:ManagedObjectReference" />
|
||||
<element name="skip" type="xsd:boolean" minOccurs="0" />
|
||||
<element name="selectSet" type="vim25:SelectionSpec" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfObjectSpec">
|
||||
<sequence>
|
||||
<element name="ObjectSpec" type="vim25:ObjectSpec" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="SelectionSpec">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="name" type="xsd:string" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfSelectionSpec">
|
||||
<sequence>
|
||||
<element name="SelectionSpec" type="vim25:SelectionSpec" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="TraversalSpec">
|
||||
<complexContent>
|
||||
<extension base="vim25:SelectionSpec">
|
||||
<sequence>
|
||||
<element name="type" type="xsd:string" />
|
||||
<element name="path" type="xsd:string" />
|
||||
<element name="skip" type="xsd:boolean" minOccurs="0" />
|
||||
<element name="selectSet" type="vim25:SelectionSpec" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ObjectContent">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="obj" type="vim25:ManagedObjectReference" />
|
||||
<element name="propSet" type="vim25:DynamicProperty" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="missingSet" type="vim25:MissingProperty" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfObjectContent">
|
||||
<sequence>
|
||||
<element name="ObjectContent" type="vim25:ObjectContent" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="UpdateSet">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="version" type="xsd:string" />
|
||||
<element name="filterSet" type="vim25:PropertyFilterUpdate" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="truncated" type="xsd:boolean" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="PropertyFilterUpdate">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="filter" type="vim25:ManagedObjectReference" />
|
||||
<element name="objectSet" type="vim25:ObjectUpdate" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="missingSet" type="vim25:MissingObject" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfPropertyFilterUpdate">
|
||||
<sequence>
|
||||
<element name="PropertyFilterUpdate" type="vim25:PropertyFilterUpdate" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<simpleType name="ObjectUpdateKind">
|
||||
<restriction base="xsd:string">
|
||||
<enumeration value="modify" />
|
||||
<enumeration value="enter" />
|
||||
<enumeration value="leave" />
|
||||
</restriction>
|
||||
</simpleType>
|
||||
<complexType name="ObjectUpdate">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="kind" type="vim25:ObjectUpdateKind" />
|
||||
<element name="obj" type="vim25:ManagedObjectReference" />
|
||||
<element name="changeSet" type="vim25:PropertyChange" minOccurs="0" maxOccurs="unbounded" />
|
||||
<element name="missingSet" type="vim25:MissingProperty" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfObjectUpdate">
|
||||
<sequence>
|
||||
<element name="ObjectUpdate" type="vim25:ObjectUpdate" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<simpleType name="PropertyChangeOp">
|
||||
<restriction base="xsd:string">
|
||||
<enumeration value="add" />
|
||||
<enumeration value="remove" />
|
||||
<enumeration value="assign" />
|
||||
<enumeration value="indirectRemove" />
|
||||
</restriction>
|
||||
</simpleType>
|
||||
<complexType name="PropertyChange">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="name" type="xsd:string" />
|
||||
<element name="op" type="vim25:PropertyChangeOp" />
|
||||
<element name="val" type="xsd:anyType" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfPropertyChange">
|
||||
<sequence>
|
||||
<element name="PropertyChange" type="vim25:PropertyChange" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="MissingProperty">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="path" type="xsd:string" />
|
||||
<element name="fault" type="vim25:LocalizedMethodFault" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfMissingProperty">
|
||||
<sequence>
|
||||
<element name="MissingProperty" type="vim25:MissingProperty" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="MissingObject">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="obj" type="vim25:ManagedObjectReference" />
|
||||
<element name="fault" type="vim25:LocalizedMethodFault" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="ArrayOfMissingObject">
|
||||
<sequence>
|
||||
<element name="MissingObject" type="vim25:MissingObject" minOccurs="0" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</complexType>
|
||||
<complexType name="WaitOptions">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="maxWaitSeconds" type="xsd:int" minOccurs="0" />
|
||||
<element name="maxObjectUpdates" type="xsd:int" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="RetrieveOptions">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="maxObjects" type="xsd:int" minOccurs="0" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
<complexType name="RetrieveResult">
|
||||
<complexContent>
|
||||
<extension base="vim25:DynamicData">
|
||||
<sequence>
|
||||
<element name="token" type="xsd:string" minOccurs="0" />
|
||||
<element name="objects" type="vim25:ObjectContent" maxOccurs="unbounded" />
|
||||
</sequence>
|
||||
</extension>
|
||||
</complexContent>
|
||||
</complexType>
|
||||
</schema>
|
||||
3082
awx/lib/site-packages/psphere/wsdl/vim-messagetypes.xsd
Normal file
3082
awx/lib/site-packages/psphere/wsdl/vim-messagetypes.xsd
Normal file
File diff suppressed because it is too large
Load Diff
22161
awx/lib/site-packages/psphere/wsdl/vim-types.xsd
Normal file
22161
awx/lib/site-packages/psphere/wsdl/vim-types.xsd
Normal file
File diff suppressed because it is too large
Load Diff
19528
awx/lib/site-packages/psphere/wsdl/vim.wsdl
Normal file
19528
awx/lib/site-packages/psphere/wsdl/vim.wsdl
Normal file
File diff suppressed because it is too large
Load Diff
16
awx/lib/site-packages/psphere/wsdl/vimService.wsdl
Normal file
16
awx/lib/site-packages/psphere/wsdl/vimService.wsdl
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
Copyright 2005-2010 VMware, Inc. All rights reserved.
|
||||
-->
|
||||
<definitions targetNamespace="urn:vim25Service"
|
||||
xmlns="http://schemas.xmlsoap.org/wsdl/"
|
||||
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
||||
xmlns:interface="urn:vim25"
|
||||
>
|
||||
<import location="vim.wsdl" namespace="urn:vim25" />
|
||||
<service name="VimService">
|
||||
<port binding="interface:VimBinding" name="VimPort">
|
||||
<soap:address location="https://localhost/sdk/vimService" />
|
||||
</port>
|
||||
</service>
|
||||
</definitions>
|
||||
154
awx/lib/site-packages/suds/__init__.py
Normal file
154
awx/lib/site-packages/suds/__init__.py
Normal file
@ -0,0 +1,154 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Suds is a lightweight SOAP python client that provides a
|
||||
service proxy for Web Services.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
#
|
||||
# Project properties
|
||||
#
|
||||
|
||||
__version__ = '0.4'
|
||||
__build__="GA R699-20100913"
|
||||
|
||||
#
|
||||
# Exceptions
|
||||
#
|
||||
|
||||
class MethodNotFound(Exception):
|
||||
def __init__(self, name):
|
||||
Exception.__init__(self, "Method not found: '%s'" % name)
|
||||
|
||||
class PortNotFound(Exception):
|
||||
def __init__(self, name):
|
||||
Exception.__init__(self, "Port not found: '%s'" % name)
|
||||
|
||||
class ServiceNotFound(Exception):
|
||||
def __init__(self, name):
|
||||
Exception.__init__(self, "Service not found: '%s'" % name)
|
||||
|
||||
class TypeNotFound(Exception):
|
||||
def __init__(self, name):
|
||||
Exception.__init__(self, "Type not found: '%s'" % tostr(name))
|
||||
|
||||
class BuildError(Exception):
|
||||
msg = \
|
||||
"""
|
||||
An error occured while building a instance of (%s). As a result
|
||||
the object you requested could not be constructed. It is recommended
|
||||
that you construct the type manually using a Suds object.
|
||||
Please open a ticket with a description of this error.
|
||||
Reason: %s
|
||||
"""
|
||||
def __init__(self, name, exception):
|
||||
Exception.__init__(self, BuildError.msg % (name, exception))
|
||||
|
||||
class SoapHeadersNotPermitted(Exception):
|
||||
msg = \
|
||||
"""
|
||||
Method (%s) was invoked with SOAP headers. The WSDL does not
|
||||
define SOAP headers for this method. Retry without the soapheaders
|
||||
keyword argument.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
Exception.__init__(self, self.msg % name)
|
||||
|
||||
class WebFault(Exception):
|
||||
def __init__(self, fault, document):
|
||||
if hasattr(fault, 'faultstring'):
|
||||
Exception.__init__(self, "Server raised fault: '%s'" % fault.faultstring)
|
||||
self.fault = fault
|
||||
self.document = document
|
||||
|
||||
#
|
||||
# Logging
|
||||
#
|
||||
|
||||
class Repr:
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
def __str__(self):
|
||||
return repr(self.x)
|
||||
|
||||
#
|
||||
# Utility
|
||||
#
|
||||
|
||||
def tostr(object, encoding=None):
|
||||
""" get a unicode safe string representation of an object """
|
||||
if isinstance(object, basestring):
|
||||
if encoding is None:
|
||||
return object
|
||||
else:
|
||||
return object.encode(encoding)
|
||||
if isinstance(object, tuple):
|
||||
s = ['(']
|
||||
for item in object:
|
||||
if isinstance(item, basestring):
|
||||
s.append(item)
|
||||
else:
|
||||
s.append(tostr(item))
|
||||
s.append(', ')
|
||||
s.append(')')
|
||||
return ''.join(s)
|
||||
if isinstance(object, list):
|
||||
s = ['[']
|
||||
for item in object:
|
||||
if isinstance(item, basestring):
|
||||
s.append(item)
|
||||
else:
|
||||
s.append(tostr(item))
|
||||
s.append(', ')
|
||||
s.append(']')
|
||||
return ''.join(s)
|
||||
if isinstance(object, dict):
|
||||
s = ['{']
|
||||
for item in object.items():
|
||||
if isinstance(item[0], basestring):
|
||||
s.append(item[0])
|
||||
else:
|
||||
s.append(tostr(item[0]))
|
||||
s.append(' = ')
|
||||
if isinstance(item[1], basestring):
|
||||
s.append(item[1])
|
||||
else:
|
||||
s.append(tostr(item[1]))
|
||||
s.append(', ')
|
||||
s.append('}')
|
||||
return ''.join(s)
|
||||
try:
|
||||
return unicode(object)
|
||||
except:
|
||||
return str(object)
|
||||
|
||||
class null:
|
||||
"""
|
||||
The I{null} object.
|
||||
Used to pass NULL for optional XML nodes.
|
||||
"""
|
||||
pass
|
||||
|
||||
def objid(obj):
|
||||
return obj.__class__.__name__\
|
||||
+':'+hex(id(obj))
|
||||
|
||||
|
||||
import client
|
||||
20
awx/lib/site-packages/suds/bindings/__init__.py
Normal file
20
awx/lib/site-packages/suds/bindings/__init__.py
Normal file
@ -0,0 +1,20 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides modules containing classes to support Web Services (SOAP)
|
||||
bindings.
|
||||
"""
|
||||
538
awx/lib/site-packages/suds/bindings/binding.py
Normal file
538
awx/lib/site-packages/suds/bindings/binding.py
Normal file
@ -0,0 +1,538 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides classes for (WS) SOAP bindings.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sax import Namespace
|
||||
from suds.sax.parser import Parser
|
||||
from suds.sax.document import Document
|
||||
from suds.sax.element import Element
|
||||
from suds.sudsobject import Factory, Object
|
||||
from suds.mx import Content
|
||||
from suds.mx.literal import Literal as MxLiteral
|
||||
from suds.umx.basic import Basic as UmxBasic
|
||||
from suds.umx.typed import Typed as UmxTyped
|
||||
from suds.bindings.multiref import MultiRef
|
||||
from suds.xsd.query import TypeQuery, ElementQuery
|
||||
from suds.xsd.sxbasic import Element as SchemaElement
|
||||
from suds.options import Options
|
||||
from suds.plugin import PluginContainer
|
||||
from copy import deepcopy
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
envns = ('SOAP-ENV', 'http://schemas.xmlsoap.org/soap/envelope/')
|
||||
|
||||
|
||||
class Binding:
|
||||
"""
|
||||
The soap binding class used to process outgoing and imcoming
|
||||
soap messages per the WSDL port binding.
|
||||
@cvar replyfilter: The reply filter function.
|
||||
@type replyfilter: (lambda s,r: r)
|
||||
@ivar wsdl: The wsdl.
|
||||
@type wsdl: L{suds.wsdl.Definitions}
|
||||
@ivar schema: The collective schema contained within the wsdl.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
@ivar options: A dictionary options.
|
||||
@type options: L{Options}
|
||||
"""
|
||||
|
||||
replyfilter = (lambda s,r: r)
|
||||
|
||||
def __init__(self, wsdl):
|
||||
"""
|
||||
@param wsdl: A wsdl.
|
||||
@type wsdl: L{wsdl.Definitions}
|
||||
"""
|
||||
self.wsdl = wsdl
|
||||
self.multiref = MultiRef()
|
||||
|
||||
def schema(self):
|
||||
return self.wsdl.schema
|
||||
|
||||
def options(self):
|
||||
return self.wsdl.options
|
||||
|
||||
def unmarshaller(self, typed=True):
|
||||
"""
|
||||
Get the appropriate XML decoder.
|
||||
@return: Either the (basic|typed) unmarshaller.
|
||||
@rtype: L{UmxTyped}
|
||||
"""
|
||||
if typed:
|
||||
return UmxTyped(self.schema())
|
||||
else:
|
||||
return UmxBasic()
|
||||
|
||||
def marshaller(self):
|
||||
"""
|
||||
Get the appropriate XML encoder.
|
||||
@return: An L{MxLiteral} marshaller.
|
||||
@rtype: L{MxLiteral}
|
||||
"""
|
||||
return MxLiteral(self.schema(), self.options().xstq)
|
||||
|
||||
def param_defs(self, method):
|
||||
"""
|
||||
Get parameter definitions.
|
||||
Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject})
|
||||
@param method: A servic emethod.
|
||||
@type method: I{service.Method}
|
||||
@return: A collection of parameter definitions
|
||||
@rtype: [I{pdef},..]
|
||||
"""
|
||||
raise Exception, 'not implemented'
|
||||
|
||||
def get_message(self, method, args, kwargs):
|
||||
"""
|
||||
Get the soap message for the specified method, args and soapheaders.
|
||||
This is the entry point for creating the outbound soap message.
|
||||
@param method: The method being invoked.
|
||||
@type method: I{service.Method}
|
||||
@param args: A list of args for the method invoked.
|
||||
@type args: list
|
||||
@param kwargs: Named (keyword) args for the method invoked.
|
||||
@type kwargs: dict
|
||||
@return: The soap envelope.
|
||||
@rtype: L{Document}
|
||||
"""
|
||||
|
||||
content = self.headercontent(method)
|
||||
header = self.header(content)
|
||||
content = self.bodycontent(method, args, kwargs)
|
||||
body = self.body(content)
|
||||
env = self.envelope(header, body)
|
||||
if self.options().prefixes:
|
||||
body.normalizePrefixes()
|
||||
env.promotePrefixes()
|
||||
else:
|
||||
env.refitPrefixes()
|
||||
return Document(env)
|
||||
|
||||
def get_reply(self, method, reply):
|
||||
"""
|
||||
Process the I{reply} for the specified I{method} by sax parsing the I{reply}
|
||||
and then unmarshalling into python object(s).
|
||||
@param method: The name of the invoked method.
|
||||
@type method: str
|
||||
@param reply: The reply XML received after invoking the specified method.
|
||||
@type reply: str
|
||||
@return: The unmarshalled reply. The returned value is an L{Object} for a
|
||||
I{list} depending on whether the service returns a single object or a
|
||||
collection.
|
||||
@rtype: tuple ( L{Element}, L{Object} )
|
||||
"""
|
||||
reply = self.replyfilter(reply)
|
||||
sax = Parser()
|
||||
replyroot = sax.parse(string=reply)
|
||||
plugins = PluginContainer(self.options().plugins)
|
||||
plugins.message.parsed(reply=replyroot)
|
||||
soapenv = replyroot.getChild('Envelope')
|
||||
soapenv.promotePrefixes()
|
||||
soapbody = soapenv.getChild('Body')
|
||||
self.detect_fault(soapbody)
|
||||
soapbody = self.multiref.process(soapbody)
|
||||
nodes = self.replycontent(method, soapbody)
|
||||
rtypes = self.returned_types(method)
|
||||
if len(rtypes) > 1:
|
||||
result = self.replycomposite(rtypes, nodes)
|
||||
return (replyroot, result)
|
||||
if len(rtypes) == 1:
|
||||
if rtypes[0].unbounded():
|
||||
result = self.replylist(rtypes[0], nodes)
|
||||
return (replyroot, result)
|
||||
if len(nodes):
|
||||
unmarshaller = self.unmarshaller()
|
||||
resolved = rtypes[0].resolve(nobuiltin=True)
|
||||
result = unmarshaller.process(nodes[0], resolved)
|
||||
return (replyroot, result)
|
||||
return (replyroot, None)
|
||||
|
||||
def detect_fault(self, body):
|
||||
"""
|
||||
Detect I{hidden} soapenv:Fault element in the soap body.
|
||||
@param body: The soap envelope body.
|
||||
@type body: L{Element}
|
||||
@raise WebFault: When found.
|
||||
"""
|
||||
fault = body.getChild('Fault', envns)
|
||||
if fault is None:
|
||||
return
|
||||
unmarshaller = self.unmarshaller(False)
|
||||
p = unmarshaller.process(fault)
|
||||
if self.options().faults:
|
||||
raise WebFault(p, fault)
|
||||
return self
|
||||
|
||||
|
||||
def replylist(self, rt, nodes):
|
||||
"""
|
||||
Construct a I{list} reply. This mehod is called when it has been detected
|
||||
that the reply is a list.
|
||||
@param rt: The return I{type}.
|
||||
@type rt: L{suds.xsd.sxbase.SchemaObject}
|
||||
@param nodes: A collection of XML nodes.
|
||||
@type nodes: [L{Element},...]
|
||||
@return: A list of I{unmarshalled} objects.
|
||||
@rtype: [L{Object},...]
|
||||
"""
|
||||
result = []
|
||||
resolved = rt.resolve(nobuiltin=True)
|
||||
unmarshaller = self.unmarshaller()
|
||||
for node in nodes:
|
||||
sobject = unmarshaller.process(node, resolved)
|
||||
result.append(sobject)
|
||||
return result
|
||||
|
||||
def replycomposite(self, rtypes, nodes):
|
||||
"""
|
||||
Construct a I{composite} reply. This method is called when it has been
|
||||
detected that the reply has multiple root nodes.
|
||||
@param rtypes: A list of known return I{types}.
|
||||
@type rtypes: [L{suds.xsd.sxbase.SchemaObject},...]
|
||||
@param nodes: A collection of XML nodes.
|
||||
@type nodes: [L{Element},...]
|
||||
@return: The I{unmarshalled} composite object.
|
||||
@rtype: L{Object},...
|
||||
"""
|
||||
dictionary = {}
|
||||
for rt in rtypes:
|
||||
dictionary[rt.name] = rt
|
||||
unmarshaller = self.unmarshaller()
|
||||
composite = Factory.object('reply')
|
||||
for node in nodes:
|
||||
tag = node.name
|
||||
rt = dictionary.get(tag, None)
|
||||
if rt is None:
|
||||
if node.get('id') is None:
|
||||
raise Exception('<%s/> not mapped to message part' % tag)
|
||||
else:
|
||||
continue
|
||||
resolved = rt.resolve(nobuiltin=True)
|
||||
sobject = unmarshaller.process(node, resolved)
|
||||
value = getattr(composite, tag, None)
|
||||
if value is None:
|
||||
if rt.unbounded():
|
||||
value = []
|
||||
setattr(composite, tag, value)
|
||||
value.append(sobject)
|
||||
else:
|
||||
setattr(composite, tag, sobject)
|
||||
else:
|
||||
if not isinstance(value, list):
|
||||
value = [value,]
|
||||
setattr(composite, tag, value)
|
||||
value.append(sobject)
|
||||
return composite
|
||||
|
||||
def get_fault(self, reply):
|
||||
"""
|
||||
Extract the fault from the specified soap reply. If I{faults} is True, an
|
||||
exception is raised. Otherwise, the I{unmarshalled} fault L{Object} is
|
||||
returned. This method is called when the server raises a I{web fault}.
|
||||
@param reply: A soap reply message.
|
||||
@type reply: str
|
||||
@return: A fault object.
|
||||
@rtype: tuple ( L{Element}, L{Object} )
|
||||
"""
|
||||
reply = self.replyfilter(reply)
|
||||
sax = Parser()
|
||||
faultroot = sax.parse(string=reply)
|
||||
soapenv = faultroot.getChild('Envelope')
|
||||
soapbody = soapenv.getChild('Body')
|
||||
fault = soapbody.getChild('Fault')
|
||||
unmarshaller = self.unmarshaller(False)
|
||||
p = unmarshaller.process(fault)
|
||||
if self.options().faults:
|
||||
raise WebFault(p, faultroot)
|
||||
return (faultroot, p.detail)
|
||||
|
||||
def mkparam(self, method, pdef, object):
|
||||
"""
|
||||
Builds a parameter for the specified I{method} using the parameter
|
||||
definition (pdef) and the specified value (object).
|
||||
@param method: A method name.
|
||||
@type method: str
|
||||
@param pdef: A parameter definition.
|
||||
@type pdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject})
|
||||
@param object: The parameter value.
|
||||
@type object: any
|
||||
@return: The parameter fragment.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
marshaller = self.marshaller()
|
||||
content = \
|
||||
Content(tag=pdef[0],
|
||||
value=object,
|
||||
type=pdef[1],
|
||||
real=pdef[1].resolve())
|
||||
return marshaller.process(content)
|
||||
|
||||
def mkheader(self, method, hdef, object):
|
||||
"""
|
||||
Builds a soapheader for the specified I{method} using the header
|
||||
definition (hdef) and the specified value (object).
|
||||
@param method: A method name.
|
||||
@type method: str
|
||||
@param hdef: A header definition.
|
||||
@type hdef: tuple: (I{name}, L{xsd.sxbase.SchemaObject})
|
||||
@param object: The header value.
|
||||
@type object: any
|
||||
@return: The parameter fragment.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
marshaller = self.marshaller()
|
||||
if isinstance(object, (list, tuple)):
|
||||
tags = []
|
||||
for item in object:
|
||||
tags.append(self.mkheader(method, hdef, item))
|
||||
return tags
|
||||
content = Content(tag=hdef[0], value=object, type=hdef[1])
|
||||
return marshaller.process(content)
|
||||
|
||||
def envelope(self, header, body):
|
||||
"""
|
||||
Build the B{<Envelope/>} for an soap outbound message.
|
||||
@param header: The soap message B{header}.
|
||||
@type header: L{Element}
|
||||
@param body: The soap message B{body}.
|
||||
@type body: L{Element}
|
||||
@return: The soap envelope containing the body and header.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
env = Element('Envelope', ns=envns)
|
||||
env.addPrefix(Namespace.xsins[0], Namespace.xsins[1])
|
||||
env.append(header)
|
||||
env.append(body)
|
||||
return env
|
||||
|
||||
def header(self, content):
|
||||
"""
|
||||
Build the B{<Body/>} for an soap outbound message.
|
||||
@param content: The header content.
|
||||
@type content: L{Element}
|
||||
@return: the soap body fragment.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
header = Element('Header', ns=envns)
|
||||
header.append(content)
|
||||
return header
|
||||
|
||||
def bodycontent(self, method, args, kwargs):
|
||||
"""
|
||||
Get the content for the soap I{body} node.
|
||||
@param method: A service method.
|
||||
@type method: I{service.Method}
|
||||
@param args: method parameter values
|
||||
@type args: list
|
||||
@param kwargs: Named (keyword) args for the method invoked.
|
||||
@type kwargs: dict
|
||||
@return: The xml content for the <body/>
|
||||
@rtype: [L{Element},..]
|
||||
"""
|
||||
raise Exception, 'not implemented'
|
||||
|
||||
def headercontent(self, method):
|
||||
"""
|
||||
Get the content for the soap I{Header} node.
|
||||
@param method: A service method.
|
||||
@type method: I{service.Method}
|
||||
@return: The xml content for the <body/>
|
||||
@rtype: [L{Element},..]
|
||||
"""
|
||||
n = 0
|
||||
content = []
|
||||
wsse = self.options().wsse
|
||||
if wsse is not None:
|
||||
content.append(wsse.xml())
|
||||
headers = self.options().soapheaders
|
||||
if not isinstance(headers, (tuple,list,dict)):
|
||||
headers = (headers,)
|
||||
if len(headers) == 0:
|
||||
return content
|
||||
pts = self.headpart_types(method)
|
||||
if isinstance(headers, (tuple,list)):
|
||||
for header in headers:
|
||||
if isinstance(header, Element):
|
||||
content.append(deepcopy(header))
|
||||
continue
|
||||
if len(pts) == n: break
|
||||
h = self.mkheader(method, pts[n], header)
|
||||
ns = pts[n][1].namespace('ns0')
|
||||
h.setPrefix(ns[0], ns[1])
|
||||
content.append(h)
|
||||
n += 1
|
||||
else:
|
||||
for pt in pts:
|
||||
header = headers.get(pt[0])
|
||||
if header is None:
|
||||
continue
|
||||
h = self.mkheader(method, pt, header)
|
||||
ns = pt[1].namespace('ns0')
|
||||
h.setPrefix(ns[0], ns[1])
|
||||
content.append(h)
|
||||
return content
|
||||
|
||||
def replycontent(self, method, body):
|
||||
"""
|
||||
Get the reply body content.
|
||||
@param method: A service method.
|
||||
@type method: I{service.Method}
|
||||
@param body: The soap body
|
||||
@type body: L{Element}
|
||||
@return: the body content
|
||||
@rtype: [L{Element},...]
|
||||
"""
|
||||
raise Exception, 'not implemented'
|
||||
|
||||
def body(self, content):
|
||||
"""
|
||||
Build the B{<Body/>} for an soap outbound message.
|
||||
@param content: The body content.
|
||||
@type content: L{Element}
|
||||
@return: the soap body fragment.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
body = Element('Body', ns=envns)
|
||||
body.append(content)
|
||||
return body
|
||||
|
||||
def bodypart_types(self, method, input=True):
|
||||
"""
|
||||
Get a list of I{parameter definitions} (pdef) defined for the specified method.
|
||||
Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject})
|
||||
@param method: A service method.
|
||||
@type method: I{service.Method}
|
||||
@param input: Defines input/output message.
|
||||
@type input: boolean
|
||||
@return: A list of parameter definitions
|
||||
@rtype: [I{pdef},]
|
||||
"""
|
||||
result = []
|
||||
if input:
|
||||
parts = method.soap.input.body.parts
|
||||
else:
|
||||
parts = method.soap.output.body.parts
|
||||
for p in parts:
|
||||
if p.element is not None:
|
||||
query = ElementQuery(p.element)
|
||||
else:
|
||||
query = TypeQuery(p.type)
|
||||
pt = query.execute(self.schema())
|
||||
if pt is None:
|
||||
raise TypeNotFound(query.ref)
|
||||
if p.type is not None:
|
||||
pt = PartElement(p.name, pt)
|
||||
if input:
|
||||
if pt.name is None:
|
||||
result.append((p.name, pt))
|
||||
else:
|
||||
result.append((pt.name, pt))
|
||||
else:
|
||||
result.append(pt)
|
||||
return result
|
||||
|
||||
def headpart_types(self, method, input=True):
|
||||
"""
|
||||
Get a list of I{parameter definitions} (pdef) defined for the specified method.
|
||||
Each I{pdef} is a tuple (I{name}, L{xsd.sxbase.SchemaObject})
|
||||
@param method: A service method.
|
||||
@type method: I{service.Method}
|
||||
@param input: Defines input/output message.
|
||||
@type input: boolean
|
||||
@return: A list of parameter definitions
|
||||
@rtype: [I{pdef},]
|
||||
"""
|
||||
result = []
|
||||
if input:
|
||||
headers = method.soap.input.headers
|
||||
else:
|
||||
headers = method.soap.output.headers
|
||||
for header in headers:
|
||||
part = header.part
|
||||
if part.element is not None:
|
||||
query = ElementQuery(part.element)
|
||||
else:
|
||||
query = TypeQuery(part.type)
|
||||
pt = query.execute(self.schema())
|
||||
if pt is None:
|
||||
raise TypeNotFound(query.ref)
|
||||
if part.type is not None:
|
||||
pt = PartElement(part.name, pt)
|
||||
if input:
|
||||
if pt.name is None:
|
||||
result.append((part.name, pt))
|
||||
else:
|
||||
result.append((pt.name, pt))
|
||||
else:
|
||||
result.append(pt)
|
||||
return result
|
||||
|
||||
def returned_types(self, method):
|
||||
"""
|
||||
Get the L{xsd.sxbase.SchemaObject} returned by the I{method}.
|
||||
@param method: A service method.
|
||||
@type method: I{service.Method}
|
||||
@return: The name of the type return by the method.
|
||||
@rtype: [I{rtype},..]
|
||||
"""
|
||||
result = []
|
||||
for rt in self.bodypart_types(method, input=False):
|
||||
result.append(rt)
|
||||
return result
|
||||
|
||||
|
||||
class PartElement(SchemaElement):
|
||||
"""
|
||||
A part used to represent a message part when the part
|
||||
references a schema type and thus assumes to be an element.
|
||||
@ivar resolved: The part type.
|
||||
@type resolved: L{suds.xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
|
||||
def __init__(self, name, resolved):
|
||||
"""
|
||||
@param name: The part name.
|
||||
@type name: str
|
||||
@param resolved: The part type.
|
||||
@type resolved: L{suds.xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
root = Element('element', ns=Namespace.xsdns)
|
||||
SchemaElement.__init__(self, resolved.schema, root)
|
||||
self.__resolved = resolved
|
||||
self.name = name
|
||||
self.form_qualified = False
|
||||
|
||||
def implany(self):
|
||||
return self
|
||||
|
||||
def optional(self):
|
||||
return True
|
||||
|
||||
def namespace(self, prefix=None):
|
||||
return Namespace.default
|
||||
|
||||
def resolve(self, nobuiltin=False):
|
||||
if nobuiltin and self.__resolved.builtin():
|
||||
return self
|
||||
else:
|
||||
return self.__resolved
|
||||
|
||||
160
awx/lib/site-packages/suds/bindings/document.py
Normal file
160
awx/lib/site-packages/suds/bindings/document.py
Normal file
@ -0,0 +1,160 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides classes for the (WS) SOAP I{document/literal}.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.bindings.binding import Binding
|
||||
from suds.sax.element import Element
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Document(Binding):
|
||||
"""
|
||||
The document/literal style. Literal is the only (@use) supported
|
||||
since document/encoded is pretty much dead.
|
||||
Although the soap specification supports multiple documents within the soap
|
||||
<body/>, it is very uncommon. As such, suds presents an I{RPC} view of
|
||||
service methods defined with a single document parameter. This is done so
|
||||
that the user can pass individual parameters instead of one, single document.
|
||||
To support the complete specification, service methods defined with multiple documents
|
||||
(multiple message parts), must present a I{document} view for that method.
|
||||
"""
|
||||
|
||||
def bodycontent(self, method, args, kwargs):
|
||||
#
|
||||
# The I{wrapped} vs I{bare} style is detected in 2 ways.
|
||||
# If there is 2+ parts in the message then it is I{bare}.
|
||||
# If there is only (1) part and that part resolves to a builtin then
|
||||
# it is I{bare}. Otherwise, it is I{wrapped}.
|
||||
#
|
||||
if not len(method.soap.input.body.parts):
|
||||
return ()
|
||||
wrapped = method.soap.input.body.wrapped
|
||||
if wrapped:
|
||||
pts = self.bodypart_types(method)
|
||||
root = self.document(pts[0])
|
||||
else:
|
||||
root = []
|
||||
n = 0
|
||||
for pd in self.param_defs(method):
|
||||
if n < len(args):
|
||||
value = args[n]
|
||||
else:
|
||||
value = kwargs.get(pd[0])
|
||||
n += 1
|
||||
p = self.mkparam(method, pd, value)
|
||||
if p is None:
|
||||
continue
|
||||
if not wrapped:
|
||||
ns = pd[1].namespace('ns0')
|
||||
p.setPrefix(ns[0], ns[1])
|
||||
root.append(p)
|
||||
return root
|
||||
|
||||
def replycontent(self, method, body):
|
||||
wrapped = method.soap.output.body.wrapped
|
||||
if wrapped:
|
||||
return body[0].children
|
||||
else:
|
||||
return body.children
|
||||
|
||||
def document(self, wrapper):
|
||||
"""
|
||||
Get the document root. For I{document/literal}, this is the
|
||||
name of the wrapper element qualifed by the schema tns.
|
||||
@param wrapper: The method name.
|
||||
@type wrapper: L{xsd.sxbase.SchemaObject}
|
||||
@return: A root element.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
tag = wrapper[1].name
|
||||
ns = wrapper[1].namespace('ns0')
|
||||
d = Element(tag, ns=ns)
|
||||
return d
|
||||
|
||||
def mkparam(self, method, pdef, object):
|
||||
#
|
||||
# Expand list parameters into individual parameters
|
||||
# each with the type information. This is because in document
|
||||
# arrays are simply unbounded elements.
|
||||
#
|
||||
if isinstance(object, (list, tuple)):
|
||||
tags = []
|
||||
for item in object:
|
||||
tags.append(self.mkparam(method, pdef, item))
|
||||
return tags
|
||||
else:
|
||||
return Binding.mkparam(self, method, pdef, object)
|
||||
|
||||
def param_defs(self, method):
|
||||
#
|
||||
# Get parameter definitions for document literal.
|
||||
# The I{wrapped} vs I{bare} style is detected in 2 ways.
|
||||
# If there is 2+ parts in the message then it is I{bare}.
|
||||
# If there is only (1) part and that part resolves to a builtin then
|
||||
# it is I{bare}. Otherwise, it is I{wrapped}.
|
||||
#
|
||||
pts = self.bodypart_types(method)
|
||||
wrapped = method.soap.input.body.wrapped
|
||||
if not wrapped:
|
||||
return pts
|
||||
result = []
|
||||
# wrapped
|
||||
for p in pts:
|
||||
resolved = p[1].resolve()
|
||||
for child, ancestry in resolved:
|
||||
if child.isattr():
|
||||
continue
|
||||
if self.bychoice(ancestry):
|
||||
log.debug(
|
||||
'%s\ncontained by <choice/>, excluded as param for %s()',
|
||||
child,
|
||||
method.name)
|
||||
continue
|
||||
result.append((child.name, child))
|
||||
return result
|
||||
|
||||
def returned_types(self, method):
|
||||
result = []
|
||||
wrapped = method.soap.output.body.wrapped
|
||||
rts = self.bodypart_types(method, input=False)
|
||||
if wrapped:
|
||||
for pt in rts:
|
||||
resolved = pt.resolve(nobuiltin=True)
|
||||
for child, ancestry in resolved:
|
||||
result.append(child)
|
||||
break
|
||||
else:
|
||||
result += rts
|
||||
return result
|
||||
|
||||
def bychoice(self, ancestry):
|
||||
"""
|
||||
The ancestry contains a <choice/>
|
||||
@param ancestry: A list of ancestors.
|
||||
@type ancestry: list
|
||||
@return: True if contains <choice/>
|
||||
@rtype: boolean
|
||||
"""
|
||||
for x in ancestry:
|
||||
if x.choice():
|
||||
return True
|
||||
return False
|
||||
126
awx/lib/site-packages/suds/bindings/multiref.py
Normal file
126
awx/lib/site-packages/suds/bindings/multiref.py
Normal file
@ -0,0 +1,126 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides classes for handling soap multirefs.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sax.element import Element
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
soapenc = (None, 'http://schemas.xmlsoap.org/soap/encoding/')
|
||||
|
||||
class MultiRef:
|
||||
"""
|
||||
Resolves and replaces multirefs.
|
||||
@ivar nodes: A list of non-multiref nodes.
|
||||
@type nodes: list
|
||||
@ivar catalog: A dictionary of multiref nodes by id.
|
||||
@type catalog: dict
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.nodes = []
|
||||
self.catalog = {}
|
||||
|
||||
def process(self, body):
|
||||
"""
|
||||
Process the specified soap envelope body and replace I{multiref} node
|
||||
references with the contents of the referenced node.
|
||||
@param body: A soap envelope body node.
|
||||
@type body: L{Element}
|
||||
@return: The processed I{body}
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
self.nodes = []
|
||||
self.catalog = {}
|
||||
self.build_catalog(body)
|
||||
self.update(body)
|
||||
body.children = self.nodes
|
||||
return body
|
||||
|
||||
def update(self, node):
|
||||
"""
|
||||
Update the specified I{node} by replacing the I{multiref} references with
|
||||
the contents of the referenced nodes and remove the I{href} attribute.
|
||||
@param node: A node to update.
|
||||
@type node: L{Element}
|
||||
@return: The updated node
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
self.replace_references(node)
|
||||
for c in node.children:
|
||||
self.update(c)
|
||||
return node
|
||||
|
||||
def replace_references(self, node):
|
||||
"""
|
||||
Replacing the I{multiref} references with the contents of the
|
||||
referenced nodes and remove the I{href} attribute. Warning: since
|
||||
the I{ref} is not cloned,
|
||||
@param node: A node to update.
|
||||
@type node: L{Element}
|
||||
"""
|
||||
href = node.getAttribute('href')
|
||||
if href is None:
|
||||
return
|
||||
id = href.getValue()
|
||||
ref = self.catalog.get(id)
|
||||
if ref is None:
|
||||
log.error('soap multiref: %s, not-resolved', id)
|
||||
return
|
||||
node.append(ref.children)
|
||||
node.setText(ref.getText())
|
||||
for a in ref.attributes:
|
||||
if a.name != 'id':
|
||||
node.append(a)
|
||||
node.remove(href)
|
||||
|
||||
def build_catalog(self, body):
|
||||
"""
|
||||
Create the I{catalog} of multiref nodes by id and the list of
|
||||
non-multiref nodes.
|
||||
@param body: A soap envelope body node.
|
||||
@type body: L{Element}
|
||||
"""
|
||||
for child in body.children:
|
||||
if self.soaproot(child):
|
||||
self.nodes.append(child)
|
||||
id = child.get('id')
|
||||
if id is None: continue
|
||||
key = '#%s' % id
|
||||
self.catalog[key] = child
|
||||
|
||||
def soaproot(self, node):
|
||||
"""
|
||||
Get whether the specified I{node} is a soap encoded root.
|
||||
This is determined by examining @soapenc:root='1'.
|
||||
The node is considered to be a root when the attribute
|
||||
is not specified.
|
||||
@param node: A node to evaluate.
|
||||
@type node: L{Element}
|
||||
@return: True if a soap encoded root.
|
||||
@rtype: bool
|
||||
"""
|
||||
root = node.getAttribute('root', ns=soapenc)
|
||||
if root is None:
|
||||
return True
|
||||
else:
|
||||
return ( root.value == '1' )
|
||||
|
||||
98
awx/lib/site-packages/suds/bindings/rpc.py
Normal file
98
awx/lib/site-packages/suds/bindings/rpc.py
Normal file
@ -0,0 +1,98 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides classes for the (WS) SOAP I{rpc/literal} and I{rpc/encoded} bindings.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.mx.encoded import Encoded as MxEncoded
|
||||
from suds.umx.encoded import Encoded as UmxEncoded
|
||||
from suds.bindings.binding import Binding, envns
|
||||
from suds.sax.element import Element
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
encns = ('SOAP-ENC', 'http://schemas.xmlsoap.org/soap/encoding/')
|
||||
|
||||
class RPC(Binding):
|
||||
"""
|
||||
RPC/Literal binding style.
|
||||
"""
|
||||
|
||||
def param_defs(self, method):
|
||||
return self.bodypart_types(method)
|
||||
|
||||
def envelope(self, header, body):
|
||||
env = Binding.envelope(self, header, body)
|
||||
env.addPrefix(encns[0], encns[1])
|
||||
env.set('%s:encodingStyle' % envns[0],
|
||||
'http://schemas.xmlsoap.org/soap/encoding/')
|
||||
return env
|
||||
|
||||
def bodycontent(self, method, args, kwargs):
|
||||
n = 0
|
||||
root = self.method(method)
|
||||
for pd in self.param_defs(method):
|
||||
if n < len(args):
|
||||
value = args[n]
|
||||
else:
|
||||
value = kwargs.get(pd[0])
|
||||
p = self.mkparam(method, pd, value)
|
||||
if p is not None:
|
||||
root.append(p)
|
||||
n += 1
|
||||
return root
|
||||
|
||||
def replycontent(self, method, body):
|
||||
return body[0].children
|
||||
|
||||
def method(self, method):
|
||||
"""
|
||||
Get the document root. For I{rpc/(literal|encoded)}, this is the
|
||||
name of the method qualifed by the schema tns.
|
||||
@param method: A service method.
|
||||
@type method: I{service.Method}
|
||||
@return: A root element.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
ns = method.soap.input.body.namespace
|
||||
if ns[0] is None:
|
||||
ns = ('ns0', ns[1])
|
||||
method = Element(method.name, ns=ns)
|
||||
return method
|
||||
|
||||
|
||||
class Encoded(RPC):
|
||||
"""
|
||||
RPC/Encoded (section 5) binding style.
|
||||
"""
|
||||
|
||||
def marshaller(self):
|
||||
return MxEncoded(self.schema())
|
||||
|
||||
def unmarshaller(self, typed=True):
|
||||
"""
|
||||
Get the appropriate XML decoder.
|
||||
@return: Either the (basic|typed) unmarshaller.
|
||||
@rtype: L{UmxTyped}
|
||||
"""
|
||||
if typed:
|
||||
return UmxEncoded(self.schema())
|
||||
else:
|
||||
return RPC.unmarshaller(self, typed)
|
||||
121
awx/lib/site-packages/suds/builder.py
Normal file
121
awx/lib/site-packages/suds/builder.py
Normal file
@ -0,0 +1,121 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{builder} module provides an wsdl/xsd defined types factory
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sudsobject import Factory
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Builder:
|
||||
""" Builder used to construct an object for types defined in the schema """
|
||||
|
||||
def __init__(self, resolver):
|
||||
"""
|
||||
@param resolver: A schema object name resolver.
|
||||
@type resolver: L{resolver.Resolver}
|
||||
"""
|
||||
self.resolver = resolver
|
||||
|
||||
def build(self, name):
|
||||
""" build a an object for the specified typename as defined in the schema """
|
||||
if isinstance(name, basestring):
|
||||
type = self.resolver.find(name)
|
||||
if type is None:
|
||||
raise TypeNotFound(name)
|
||||
else:
|
||||
type = name
|
||||
cls = type.name
|
||||
if type.mixed():
|
||||
data = Factory.property(cls)
|
||||
else:
|
||||
data = Factory.object(cls)
|
||||
resolved = type.resolve()
|
||||
md = data.__metadata__
|
||||
md.sxtype = resolved
|
||||
md.ordering = self.ordering(resolved)
|
||||
history = []
|
||||
self.add_attributes(data, resolved)
|
||||
for child, ancestry in type.children():
|
||||
if self.skip_child(child, ancestry):
|
||||
continue
|
||||
self.process(data, child, history[:])
|
||||
return data
|
||||
|
||||
def process(self, data, type, history):
|
||||
""" process the specified type then process its children """
|
||||
if type in history:
|
||||
return
|
||||
if type.enum():
|
||||
return
|
||||
history.append(type)
|
||||
resolved = type.resolve()
|
||||
value = None
|
||||
if type.unbounded():
|
||||
value = []
|
||||
else:
|
||||
if len(resolved) > 0:
|
||||
if resolved.mixed():
|
||||
value = Factory.property(resolved.name)
|
||||
md = value.__metadata__
|
||||
md.sxtype = resolved
|
||||
else:
|
||||
value = Factory.object(resolved.name)
|
||||
md = value.__metadata__
|
||||
md.sxtype = resolved
|
||||
md.ordering = self.ordering(resolved)
|
||||
setattr(data, type.name, value)
|
||||
if value is not None:
|
||||
data = value
|
||||
if not isinstance(data, list):
|
||||
self.add_attributes(data, resolved)
|
||||
for child, ancestry in resolved.children():
|
||||
if self.skip_child(child, ancestry):
|
||||
continue
|
||||
self.process(data, child, history[:])
|
||||
|
||||
def add_attributes(self, data, type):
|
||||
""" add required attributes """
|
||||
for attr, ancestry in type.attributes():
|
||||
name = '_%s' % attr.name
|
||||
value = attr.get_default()
|
||||
setattr(data, name, value)
|
||||
|
||||
def skip_child(self, child, ancestry):
|
||||
""" get whether or not to skip the specified child """
|
||||
if child.any(): return True
|
||||
for x in ancestry:
|
||||
if x.choice():
|
||||
return True
|
||||
return False
|
||||
|
||||
def ordering(self, type):
|
||||
""" get the ordering """
|
||||
result = []
|
||||
for child, ancestry in type.resolve():
|
||||
name = child.name
|
||||
if child.name is None:
|
||||
continue
|
||||
if child.isattr():
|
||||
name = '_%s' % child.name
|
||||
result.append(name)
|
||||
return result
|
||||
|
||||
337
awx/lib/site-packages/suds/cache.py
Normal file
337
awx/lib/site-packages/suds/cache.py
Normal file
@ -0,0 +1,337 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains basic caching classes.
|
||||
"""
|
||||
|
||||
import os
|
||||
import suds
|
||||
from tempfile import gettempdir as tmp
|
||||
from suds.transport import *
|
||||
from suds.sax.parser import Parser
|
||||
from suds.sax.element import Element
|
||||
from datetime import datetime as dt
|
||||
from datetime import timedelta
|
||||
from cStringIO import StringIO
|
||||
from logging import getLogger
|
||||
try:
|
||||
import cPickle as pickle
|
||||
except:
|
||||
import pickle
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Cache:
|
||||
"""
|
||||
An object object cache.
|
||||
"""
|
||||
|
||||
def get(self, id):
|
||||
"""
|
||||
Get a object from the cache by ID.
|
||||
@param id: The object ID.
|
||||
@type id: str
|
||||
@return: The object, else None
|
||||
@rtype: any
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
|
||||
def getf(self, id):
|
||||
"""
|
||||
Get a object from the cache by ID.
|
||||
@param id: The object ID.
|
||||
@type id: str
|
||||
@return: The object, else None
|
||||
@rtype: any
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
|
||||
def put(self, id, object):
|
||||
"""
|
||||
Put a object into the cache.
|
||||
@param id: The object ID.
|
||||
@type id: str
|
||||
@param object: The object to add.
|
||||
@type object: any
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
|
||||
def putf(self, id, fp):
|
||||
"""
|
||||
Write a fp into the cache.
|
||||
@param id: The object ID.
|
||||
@type id: str
|
||||
@param fp: File pointer.
|
||||
@type fp: file-like object.
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
|
||||
def purge(self, id):
|
||||
"""
|
||||
Purge a object from the cache by id.
|
||||
@param id: A object ID.
|
||||
@type id: str
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
|
||||
def clear(self):
|
||||
"""
|
||||
Clear all objects from the cache.
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
|
||||
|
||||
class NoCache(Cache):
|
||||
"""
|
||||
The passthru object cache.
|
||||
"""
|
||||
|
||||
def get(self, id):
|
||||
return None
|
||||
|
||||
def getf(self, id):
|
||||
return None
|
||||
|
||||
def put(self, id, object):
|
||||
pass
|
||||
|
||||
def putf(self, id, fp):
|
||||
pass
|
||||
|
||||
|
||||
class FileCache(Cache):
|
||||
"""
|
||||
A file-based URL cache.
|
||||
@cvar fnprefix: The file name prefix.
|
||||
@type fnsuffix: str
|
||||
@ivar duration: The cached file duration which defines how
|
||||
long the file will be cached.
|
||||
@type duration: (unit, value)
|
||||
@ivar location: The directory for the cached files.
|
||||
@type location: str
|
||||
"""
|
||||
fnprefix = 'suds'
|
||||
units = ('months', 'weeks', 'days', 'hours', 'minutes', 'seconds')
|
||||
|
||||
def __init__(self, location=None, **duration):
|
||||
"""
|
||||
@param location: The directory for the cached files.
|
||||
@type location: str
|
||||
@param duration: The cached file duration which defines how
|
||||
long the file will be cached. A duration=0 means forever.
|
||||
The duration may be: (months|weeks|days|hours|minutes|seconds).
|
||||
@type duration: {unit:value}
|
||||
"""
|
||||
if location is None:
|
||||
location = os.path.join(tmp(), 'suds')
|
||||
self.location = location
|
||||
self.duration = (None, 0)
|
||||
self.setduration(**duration)
|
||||
self.checkversion()
|
||||
|
||||
def fnsuffix(self):
|
||||
"""
|
||||
Get the file name suffix
|
||||
@return: The suffix
|
||||
@rtype: str
|
||||
"""
|
||||
return 'gcf'
|
||||
|
||||
def setduration(self, **duration):
|
||||
"""
|
||||
Set the caching duration which defines how long the
|
||||
file will be cached.
|
||||
@param duration: The cached file duration which defines how
|
||||
long the file will be cached. A duration=0 means forever.
|
||||
The duration may be: (months|weeks|days|hours|minutes|seconds).
|
||||
@type duration: {unit:value}
|
||||
"""
|
||||
if len(duration) == 1:
|
||||
arg = duration.items()[0]
|
||||
if not arg[0] in self.units:
|
||||
raise Exception('must be: %s' % str(self.units))
|
||||
self.duration = arg
|
||||
return self
|
||||
|
||||
def setlocation(self, location):
|
||||
"""
|
||||
Set the location (directory) for the cached files.
|
||||
@param location: The directory for the cached files.
|
||||
@type location: str
|
||||
"""
|
||||
self.location = location
|
||||
|
||||
def mktmp(self):
|
||||
"""
|
||||
Make the I{location} directory if it doesn't already exits.
|
||||
"""
|
||||
try:
|
||||
if not os.path.isdir(self.location):
|
||||
os.makedirs(self.location)
|
||||
except:
|
||||
log.debug(self.location, exc_info=1)
|
||||
return self
|
||||
|
||||
def put(self, id, bfr):
|
||||
try:
|
||||
fn = self.__fn(id)
|
||||
f = self.open(fn, 'w')
|
||||
f.write(bfr)
|
||||
f.close()
|
||||
return bfr
|
||||
except:
|
||||
log.debug(id, exc_info=1)
|
||||
return bfr
|
||||
|
||||
def putf(self, id, fp):
|
||||
try:
|
||||
fn = self.__fn(id)
|
||||
f = self.open(fn, 'w')
|
||||
f.write(fp.read())
|
||||
fp.close()
|
||||
f.close()
|
||||
return open(fn)
|
||||
except:
|
||||
log.debug(id, exc_info=1)
|
||||
return fp
|
||||
|
||||
def get(self, id):
|
||||
try:
|
||||
f = self.getf(id)
|
||||
bfr = f.read()
|
||||
f.close()
|
||||
return bfr
|
||||
except:
|
||||
pass
|
||||
|
||||
def getf(self, id):
|
||||
try:
|
||||
fn = self.__fn(id)
|
||||
self.validate(fn)
|
||||
return self.open(fn)
|
||||
except:
|
||||
pass
|
||||
|
||||
def validate(self, fn):
|
||||
"""
|
||||
Validate that the file has not expired based on the I{duration}.
|
||||
@param fn: The file name.
|
||||
@type fn: str
|
||||
"""
|
||||
if self.duration[1] < 1:
|
||||
return
|
||||
created = dt.fromtimestamp(os.path.getctime(fn))
|
||||
d = { self.duration[0]:self.duration[1] }
|
||||
expired = created+timedelta(**d)
|
||||
if expired < dt.now():
|
||||
log.debug('%s expired, deleted', fn)
|
||||
os.remove(fn)
|
||||
|
||||
def clear(self):
|
||||
for fn in os.listdir(self.location):
|
||||
if os.path.isdir(fn):
|
||||
continue
|
||||
if fn.startswith(self.fnprefix):
|
||||
log.debug('deleted: %s', fn)
|
||||
os.remove(os.path.join(self.location, fn))
|
||||
|
||||
def purge(self, id):
|
||||
fn = self.__fn(id)
|
||||
try:
|
||||
os.remove(fn)
|
||||
except:
|
||||
pass
|
||||
|
||||
def open(self, fn, *args):
|
||||
"""
|
||||
Open the cache file making sure the directory is created.
|
||||
"""
|
||||
self.mktmp()
|
||||
return open(fn, *args)
|
||||
|
||||
def checkversion(self):
|
||||
path = os.path.join(self.location, 'version')
|
||||
try:
|
||||
|
||||
f = self.open(path)
|
||||
version = f.read()
|
||||
f.close()
|
||||
if version != suds.__version__:
|
||||
raise Exception()
|
||||
except:
|
||||
self.clear()
|
||||
f = self.open(path, 'w')
|
||||
f.write(suds.__version__)
|
||||
f.close()
|
||||
|
||||
def __fn(self, id):
|
||||
name = id
|
||||
suffix = self.fnsuffix()
|
||||
fn = '%s-%s.%s' % (self.fnprefix, name, suffix)
|
||||
return os.path.join(self.location, fn)
|
||||
|
||||
|
||||
class DocumentCache(FileCache):
|
||||
"""
|
||||
Provides xml document caching.
|
||||
"""
|
||||
|
||||
def fnsuffix(self):
|
||||
return 'xml'
|
||||
|
||||
def get(self, id):
|
||||
try:
|
||||
fp = FileCache.getf(self, id)
|
||||
if fp is None:
|
||||
return None
|
||||
p = Parser()
|
||||
return p.parse(fp)
|
||||
except:
|
||||
FileCache.purge(self, id)
|
||||
|
||||
def put(self, id, object):
|
||||
if isinstance(object, Element):
|
||||
FileCache.put(self, id, str(object))
|
||||
return object
|
||||
|
||||
|
||||
class ObjectCache(FileCache):
|
||||
"""
|
||||
Provides pickled object caching.
|
||||
@cvar protocol: The pickling protocol.
|
||||
@type protocol: int
|
||||
"""
|
||||
protocol = 2
|
||||
|
||||
def fnsuffix(self):
|
||||
return 'px'
|
||||
|
||||
def get(self, id):
|
||||
try:
|
||||
fp = FileCache.getf(self, id)
|
||||
if fp is None:
|
||||
return None
|
||||
else:
|
||||
return pickle.load(fp)
|
||||
except:
|
||||
FileCache.purge(self, id)
|
||||
|
||||
def put(self, id, object):
|
||||
bfr = pickle.dumps(object, self.protocol)
|
||||
FileCache.put(self, id, bfr)
|
||||
return object
|
||||
785
awx/lib/site-packages/suds/client.py
Normal file
785
awx/lib/site-packages/suds/client.py
Normal file
@ -0,0 +1,785 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{2nd generation} service proxy provides access to web services.
|
||||
See I{README.txt}
|
||||
"""
|
||||
|
||||
import suds
|
||||
import suds.metrics as metrics
|
||||
from cookielib import CookieJar
|
||||
from suds import *
|
||||
from suds.reader import DefinitionsReader
|
||||
from suds.transport import TransportError, Request
|
||||
from suds.transport.https import HttpAuthenticated
|
||||
from suds.servicedefinition import ServiceDefinition
|
||||
from suds import sudsobject
|
||||
from sudsobject import Factory as InstFactory
|
||||
from sudsobject import Object
|
||||
from suds.resolver import PathResolver
|
||||
from suds.builder import Builder
|
||||
from suds.wsdl import Definitions
|
||||
from suds.cache import ObjectCache
|
||||
from suds.sax.document import Document
|
||||
from suds.sax.parser import Parser
|
||||
from suds.options import Options
|
||||
from suds.properties import Unskin
|
||||
from urlparse import urlparse
|
||||
from copy import deepcopy
|
||||
from suds.plugin import PluginContainer
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""
|
||||
A lightweight web services client.
|
||||
I{(2nd generation)} API.
|
||||
@ivar wsdl: The WSDL object.
|
||||
@type wsdl:L{Definitions}
|
||||
@ivar service: The service proxy used to invoke operations.
|
||||
@type service: L{Service}
|
||||
@ivar factory: The factory used to create objects.
|
||||
@type factory: L{Factory}
|
||||
@ivar sd: The service definition
|
||||
@type sd: L{ServiceDefinition}
|
||||
@ivar messages: The last sent/received messages.
|
||||
@type messages: str[2]
|
||||
"""
|
||||
@classmethod
|
||||
def items(cls, sobject):
|
||||
"""
|
||||
Extract the I{items} from a suds object much like the
|
||||
items() method works on I{dict}.
|
||||
@param sobject: A suds object
|
||||
@type sobject: L{Object}
|
||||
@return: A list of items contained in I{sobject}.
|
||||
@rtype: [(key, value),...]
|
||||
"""
|
||||
return sudsobject.items(sobject)
|
||||
|
||||
@classmethod
|
||||
def dict(cls, sobject):
|
||||
"""
|
||||
Convert a sudsobject into a dictionary.
|
||||
@param sobject: A suds object
|
||||
@type sobject: L{Object}
|
||||
@return: A python dictionary containing the
|
||||
items contained in I{sobject}.
|
||||
@rtype: dict
|
||||
"""
|
||||
return sudsobject.asdict(sobject)
|
||||
|
||||
@classmethod
|
||||
def metadata(cls, sobject):
|
||||
"""
|
||||
Extract the metadata from a suds object.
|
||||
@param sobject: A suds object
|
||||
@type sobject: L{Object}
|
||||
@return: The object's metadata
|
||||
@rtype: L{sudsobject.Metadata}
|
||||
"""
|
||||
return sobject.__metadata__
|
||||
|
||||
def __init__(self, url, **kwargs):
|
||||
"""
|
||||
@param url: The URL for the WSDL.
|
||||
@type url: str
|
||||
@param kwargs: keyword arguments.
|
||||
@see: L{Options}
|
||||
"""
|
||||
options = Options()
|
||||
options.transport = HttpAuthenticated()
|
||||
self.options = options
|
||||
options.cache = ObjectCache(days=1)
|
||||
self.set_options(**kwargs)
|
||||
reader = DefinitionsReader(options, Definitions)
|
||||
self.wsdl = reader.open(url)
|
||||
plugins = PluginContainer(options.plugins)
|
||||
plugins.init.initialized(wsdl=self.wsdl)
|
||||
self.factory = Factory(self.wsdl)
|
||||
self.service = ServiceSelector(self, self.wsdl.services)
|
||||
self.sd = []
|
||||
for s in self.wsdl.services:
|
||||
sd = ServiceDefinition(self.wsdl, s)
|
||||
self.sd.append(sd)
|
||||
self.messages = dict(tx=None, rx=None)
|
||||
|
||||
def set_options(self, **kwargs):
|
||||
"""
|
||||
Set options.
|
||||
@param kwargs: keyword arguments.
|
||||
@see: L{Options}
|
||||
"""
|
||||
p = Unskin(self.options)
|
||||
p.update(kwargs)
|
||||
|
||||
def add_prefix(self, prefix, uri):
|
||||
"""
|
||||
Add I{static} mapping of an XML namespace prefix to a namespace.
|
||||
This is useful for cases when a wsdl and referenced schemas make heavy
|
||||
use of namespaces and those namespaces are subject to changed.
|
||||
@param prefix: An XML namespace prefix.
|
||||
@type prefix: str
|
||||
@param uri: An XML namespace URI.
|
||||
@type uri: str
|
||||
@raise Exception: when prefix is already mapped.
|
||||
"""
|
||||
root = self.wsdl.root
|
||||
mapped = root.resolvePrefix(prefix, None)
|
||||
if mapped is None:
|
||||
root.addPrefix(prefix, uri)
|
||||
return
|
||||
if mapped[1] != uri:
|
||||
raise Exception('"%s" already mapped as "%s"' % (prefix, mapped))
|
||||
|
||||
def last_sent(self):
|
||||
"""
|
||||
Get last sent I{soap} message.
|
||||
@return: The last sent I{soap} message.
|
||||
@rtype: L{Document}
|
||||
"""
|
||||
return self.messages.get('tx')
|
||||
|
||||
def last_received(self):
|
||||
"""
|
||||
Get last received I{soap} message.
|
||||
@return: The last received I{soap} message.
|
||||
@rtype: L{Document}
|
||||
"""
|
||||
return self.messages.get('rx')
|
||||
|
||||
def clone(self):
|
||||
"""
|
||||
Get a shallow clone of this object.
|
||||
The clone only shares the WSDL. All other attributes are
|
||||
unique to the cloned object including options.
|
||||
@return: A shallow clone.
|
||||
@rtype: L{Client}
|
||||
"""
|
||||
class Uninitialized(Client):
|
||||
def __init__(self):
|
||||
pass
|
||||
clone = Uninitialized()
|
||||
clone.options = Options()
|
||||
cp = Unskin(clone.options)
|
||||
mp = Unskin(self.options)
|
||||
cp.update(deepcopy(mp))
|
||||
clone.wsdl = self.wsdl
|
||||
clone.factory = self.factory
|
||||
clone.service = ServiceSelector(clone, self.wsdl.services)
|
||||
clone.sd = self.sd
|
||||
clone.messages = dict(tx=None, rx=None)
|
||||
return clone
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self)
|
||||
|
||||
def __unicode__(self):
|
||||
s = ['\n']
|
||||
build = suds.__build__.split()
|
||||
s.append('Suds ( https://fedorahosted.org/suds/ )')
|
||||
s.append(' version: %s' % suds.__version__)
|
||||
s.append(' %s build: %s' % (build[0], build[1]))
|
||||
for sd in self.sd:
|
||||
s.append('\n\n%s' % unicode(sd))
|
||||
return ''.join(s)
|
||||
|
||||
|
||||
class Factory:
|
||||
"""
|
||||
A factory for instantiating types defined in the wsdl
|
||||
@ivar resolver: A schema type resolver.
|
||||
@type resolver: L{PathResolver}
|
||||
@ivar builder: A schema object builder.
|
||||
@type builder: L{Builder}
|
||||
"""
|
||||
|
||||
def __init__(self, wsdl):
|
||||
"""
|
||||
@param wsdl: A schema object.
|
||||
@type wsdl: L{wsdl.Definitions}
|
||||
"""
|
||||
self.wsdl = wsdl
|
||||
self.resolver = PathResolver(wsdl)
|
||||
self.builder = Builder(self.resolver)
|
||||
|
||||
def create(self, name):
|
||||
"""
|
||||
create a WSDL type by name
|
||||
@param name: The name of a type defined in the WSDL.
|
||||
@type name: str
|
||||
@return: The requested object.
|
||||
@rtype: L{Object}
|
||||
"""
|
||||
timer = metrics.Timer()
|
||||
timer.start()
|
||||
type = self.resolver.find(name)
|
||||
if type is None:
|
||||
raise TypeNotFound(name)
|
||||
if type.enum():
|
||||
result = InstFactory.object(name)
|
||||
for e, a in type.children():
|
||||
setattr(result, e.name, e.name)
|
||||
else:
|
||||
try:
|
||||
result = self.builder.build(type)
|
||||
except Exception, e:
|
||||
log.error("create '%s' failed", name, exc_info=True)
|
||||
raise BuildError(name, e)
|
||||
timer.stop()
|
||||
metrics.log.debug('%s created: %s', name, timer)
|
||||
return result
|
||||
|
||||
def separator(self, ps):
|
||||
"""
|
||||
Set the path separator.
|
||||
@param ps: The new path separator.
|
||||
@type ps: char
|
||||
"""
|
||||
self.resolver = PathResolver(self.wsdl, ps)
|
||||
|
||||
|
||||
class ServiceSelector:
|
||||
"""
|
||||
The B{service} selector is used to select a web service.
|
||||
In most cases, the wsdl only defines (1) service in which access
|
||||
by subscript is passed through to a L{PortSelector}. This is also the
|
||||
behavior when a I{default} service has been specified. In cases
|
||||
where multiple services have been defined and no default has been
|
||||
specified, the service is found by name (or index) and a L{PortSelector}
|
||||
for the service is returned. In all cases, attribute access is
|
||||
forwarded to the L{PortSelector} for either the I{first} service or the
|
||||
I{default} service (when specified).
|
||||
@ivar __client: A suds client.
|
||||
@type __client: L{Client}
|
||||
@ivar __services: A list of I{wsdl} services.
|
||||
@type __services: list
|
||||
"""
|
||||
def __init__(self, client, services):
|
||||
"""
|
||||
@param client: A suds client.
|
||||
@type client: L{Client}
|
||||
@param services: A list of I{wsdl} services.
|
||||
@type services: list
|
||||
"""
|
||||
self.__client = client
|
||||
self.__services = services
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
Request to access an attribute is forwarded to the
|
||||
L{PortSelector} for either the I{first} service or the
|
||||
I{default} service (when specified).
|
||||
@param name: The name of a method.
|
||||
@type name: str
|
||||
@return: A L{PortSelector}.
|
||||
@rtype: L{PortSelector}.
|
||||
"""
|
||||
default = self.__ds()
|
||||
if default is None:
|
||||
port = self.__find(0)
|
||||
else:
|
||||
port = default
|
||||
return getattr(port, name)
|
||||
|
||||
def __getitem__(self, name):
|
||||
"""
|
||||
Provides selection of the I{service} by name (string) or
|
||||
index (integer). In cases where only (1) service is defined
|
||||
or a I{default} has been specified, the request is forwarded
|
||||
to the L{PortSelector}.
|
||||
@param name: The name (or index) of a service.
|
||||
@type name: (int|str)
|
||||
@return: A L{PortSelector} for the specified service.
|
||||
@rtype: L{PortSelector}.
|
||||
"""
|
||||
if len(self.__services) == 1:
|
||||
port = self.__find(0)
|
||||
return port[name]
|
||||
default = self.__ds()
|
||||
if default is not None:
|
||||
port = default
|
||||
return port[name]
|
||||
return self.__find(name)
|
||||
|
||||
def __find(self, name):
|
||||
"""
|
||||
Find a I{service} by name (string) or index (integer).
|
||||
@param name: The name (or index) of a service.
|
||||
@type name: (int|str)
|
||||
@return: A L{PortSelector} for the found service.
|
||||
@rtype: L{PortSelector}.
|
||||
"""
|
||||
service = None
|
||||
if not len(self.__services):
|
||||
raise Exception, 'No services defined'
|
||||
if isinstance(name, int):
|
||||
try:
|
||||
service = self.__services[name]
|
||||
name = service.name
|
||||
except IndexError:
|
||||
raise ServiceNotFound, 'at [%d]' % name
|
||||
else:
|
||||
for s in self.__services:
|
||||
if name == s.name:
|
||||
service = s
|
||||
break
|
||||
if service is None:
|
||||
raise ServiceNotFound, name
|
||||
return PortSelector(self.__client, service.ports, name)
|
||||
|
||||
def __ds(self):
|
||||
"""
|
||||
Get the I{default} service if defined in the I{options}.
|
||||
@return: A L{PortSelector} for the I{default} service.
|
||||
@rtype: L{PortSelector}.
|
||||
"""
|
||||
ds = self.__client.options.service
|
||||
if ds is None:
|
||||
return None
|
||||
else:
|
||||
return self.__find(ds)
|
||||
|
||||
|
||||
class PortSelector:
|
||||
"""
|
||||
The B{port} selector is used to select a I{web service} B{port}.
|
||||
In cases where multiple ports have been defined and no default has been
|
||||
specified, the port is found by name (or index) and a L{MethodSelector}
|
||||
for the port is returned. In all cases, attribute access is
|
||||
forwarded to the L{MethodSelector} for either the I{first} port or the
|
||||
I{default} port (when specified).
|
||||
@ivar __client: A suds client.
|
||||
@type __client: L{Client}
|
||||
@ivar __ports: A list of I{service} ports.
|
||||
@type __ports: list
|
||||
@ivar __qn: The I{qualified} name of the port (used for logging).
|
||||
@type __qn: str
|
||||
"""
|
||||
def __init__(self, client, ports, qn):
|
||||
"""
|
||||
@param client: A suds client.
|
||||
@type client: L{Client}
|
||||
@param ports: A list of I{service} ports.
|
||||
@type ports: list
|
||||
@param qn: The name of the service.
|
||||
@type qn: str
|
||||
"""
|
||||
self.__client = client
|
||||
self.__ports = ports
|
||||
self.__qn = qn
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
Request to access an attribute is forwarded to the
|
||||
L{MethodSelector} for either the I{first} port or the
|
||||
I{default} port (when specified).
|
||||
@param name: The name of a method.
|
||||
@type name: str
|
||||
@return: A L{MethodSelector}.
|
||||
@rtype: L{MethodSelector}.
|
||||
"""
|
||||
default = self.__dp()
|
||||
if default is None:
|
||||
m = self.__find(0)
|
||||
else:
|
||||
m = default
|
||||
return getattr(m, name)
|
||||
|
||||
def __getitem__(self, name):
|
||||
"""
|
||||
Provides selection of the I{port} by name (string) or
|
||||
index (integer). In cases where only (1) port is defined
|
||||
or a I{default} has been specified, the request is forwarded
|
||||
to the L{MethodSelector}.
|
||||
@param name: The name (or index) of a port.
|
||||
@type name: (int|str)
|
||||
@return: A L{MethodSelector} for the specified port.
|
||||
@rtype: L{MethodSelector}.
|
||||
"""
|
||||
default = self.__dp()
|
||||
if default is None:
|
||||
return self.__find(name)
|
||||
else:
|
||||
return default
|
||||
|
||||
def __find(self, name):
|
||||
"""
|
||||
Find a I{port} by name (string) or index (integer).
|
||||
@param name: The name (or index) of a port.
|
||||
@type name: (int|str)
|
||||
@return: A L{MethodSelector} for the found port.
|
||||
@rtype: L{MethodSelector}.
|
||||
"""
|
||||
port = None
|
||||
if not len(self.__ports):
|
||||
raise Exception, 'No ports defined: %s' % self.__qn
|
||||
if isinstance(name, int):
|
||||
qn = '%s[%d]' % (self.__qn, name)
|
||||
try:
|
||||
port = self.__ports[name]
|
||||
except IndexError:
|
||||
raise PortNotFound, qn
|
||||
else:
|
||||
qn = '.'.join((self.__qn, name))
|
||||
for p in self.__ports:
|
||||
if name == p.name:
|
||||
port = p
|
||||
break
|
||||
if port is None:
|
||||
raise PortNotFound, qn
|
||||
qn = '.'.join((self.__qn, port.name))
|
||||
return MethodSelector(self.__client, port.methods, qn)
|
||||
|
||||
def __dp(self):
|
||||
"""
|
||||
Get the I{default} port if defined in the I{options}.
|
||||
@return: A L{MethodSelector} for the I{default} port.
|
||||
@rtype: L{MethodSelector}.
|
||||
"""
|
||||
dp = self.__client.options.port
|
||||
if dp is None:
|
||||
return None
|
||||
else:
|
||||
return self.__find(dp)
|
||||
|
||||
|
||||
class MethodSelector:
|
||||
"""
|
||||
The B{method} selector is used to select a B{method} by name.
|
||||
@ivar __client: A suds client.
|
||||
@type __client: L{Client}
|
||||
@ivar __methods: A dictionary of methods.
|
||||
@type __methods: dict
|
||||
@ivar __qn: The I{qualified} name of the method (used for logging).
|
||||
@type __qn: str
|
||||
"""
|
||||
def __init__(self, client, methods, qn):
|
||||
"""
|
||||
@param client: A suds client.
|
||||
@type client: L{Client}
|
||||
@param methods: A dictionary of methods.
|
||||
@type methods: dict
|
||||
@param qn: The I{qualified} name of the port.
|
||||
@type qn: str
|
||||
"""
|
||||
self.__client = client
|
||||
self.__methods = methods
|
||||
self.__qn = qn
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
Get a method by name and return it in an I{execution wrapper}.
|
||||
@param name: The name of a method.
|
||||
@type name: str
|
||||
@return: An I{execution wrapper} for the specified method name.
|
||||
@rtype: L{Method}
|
||||
"""
|
||||
return self[name]
|
||||
|
||||
def __getitem__(self, name):
|
||||
"""
|
||||
Get a method by name and return it in an I{execution wrapper}.
|
||||
@param name: The name of a method.
|
||||
@type name: str
|
||||
@return: An I{execution wrapper} for the specified method name.
|
||||
@rtype: L{Method}
|
||||
"""
|
||||
m = self.__methods.get(name)
|
||||
if m is None:
|
||||
qn = '.'.join((self.__qn, name))
|
||||
raise MethodNotFound, qn
|
||||
return Method(self.__client, m)
|
||||
|
||||
|
||||
class Method:
|
||||
"""
|
||||
The I{method} (namespace) object.
|
||||
@ivar client: A client object.
|
||||
@type client: L{Client}
|
||||
@ivar method: A I{wsdl} method.
|
||||
@type I{wsdl} Method.
|
||||
"""
|
||||
|
||||
def __init__(self, client, method):
|
||||
"""
|
||||
@param client: A client object.
|
||||
@type client: L{Client}
|
||||
@param method: A I{raw} method.
|
||||
@type I{raw} Method.
|
||||
"""
|
||||
self.client = client
|
||||
self.method = method
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
"""
|
||||
Invoke the method.
|
||||
"""
|
||||
clientclass = self.clientclass(kwargs)
|
||||
client = clientclass(self.client, self.method)
|
||||
if not self.faults():
|
||||
try:
|
||||
return client.invoke(args, kwargs)
|
||||
except WebFault, e:
|
||||
return (500, e)
|
||||
else:
|
||||
return client.invoke(args, kwargs)
|
||||
|
||||
def faults(self):
|
||||
""" get faults option """
|
||||
return self.client.options.faults
|
||||
|
||||
def clientclass(self, kwargs):
|
||||
""" get soap client class """
|
||||
if SimClient.simulation(kwargs):
|
||||
return SimClient
|
||||
else:
|
||||
return SoapClient
|
||||
|
||||
|
||||
class SoapClient:
|
||||
"""
|
||||
A lightweight soap based web client B{**not intended for external use}
|
||||
@ivar service: The target method.
|
||||
@type service: L{Service}
|
||||
@ivar method: A target method.
|
||||
@type method: L{Method}
|
||||
@ivar options: A dictonary of options.
|
||||
@type options: dict
|
||||
@ivar cookiejar: A cookie jar.
|
||||
@type cookiejar: libcookie.CookieJar
|
||||
"""
|
||||
|
||||
def __init__(self, client, method):
|
||||
"""
|
||||
@param client: A suds client.
|
||||
@type client: L{Client}
|
||||
@param method: A target method.
|
||||
@type method: L{Method}
|
||||
"""
|
||||
self.client = client
|
||||
self.method = method
|
||||
self.options = client.options
|
||||
self.cookiejar = CookieJar()
|
||||
|
||||
def invoke(self, args, kwargs):
|
||||
"""
|
||||
Send the required soap message to invoke the specified method
|
||||
@param args: A list of args for the method invoked.
|
||||
@type args: list
|
||||
@param kwargs: Named (keyword) args for the method invoked.
|
||||
@type kwargs: dict
|
||||
@return: The result of the method invocation.
|
||||
@rtype: I{builtin}|I{subclass of} L{Object}
|
||||
"""
|
||||
timer = metrics.Timer()
|
||||
timer.start()
|
||||
result = None
|
||||
binding = self.method.binding.input
|
||||
soapenv = binding.get_message(self.method, args, kwargs)
|
||||
timer.stop()
|
||||
metrics.log.debug(
|
||||
"message for '%s' created: %s",
|
||||
self.method.name,
|
||||
timer)
|
||||
timer.start()
|
||||
result = self.send(soapenv)
|
||||
timer.stop()
|
||||
metrics.log.debug(
|
||||
"method '%s' invoked: %s",
|
||||
self.method.name,
|
||||
timer)
|
||||
return result
|
||||
|
||||
def send(self, soapenv):
|
||||
"""
|
||||
Send soap message.
|
||||
@param soapenv: A soap envelope to send.
|
||||
@type soapenv: L{Document}
|
||||
@return: The reply to the sent message.
|
||||
@rtype: I{builtin} or I{subclass of} L{Object}
|
||||
"""
|
||||
result = None
|
||||
location = self.location()
|
||||
binding = self.method.binding.input
|
||||
transport = self.options.transport
|
||||
retxml = self.options.retxml
|
||||
prettyxml = self.options.prettyxml
|
||||
log.debug('sending to (%s)\nmessage:\n%s', location, soapenv)
|
||||
try:
|
||||
self.last_sent(soapenv)
|
||||
plugins = PluginContainer(self.options.plugins)
|
||||
plugins.message.marshalled(envelope=soapenv.root())
|
||||
if prettyxml:
|
||||
soapenv = soapenv.str()
|
||||
else:
|
||||
soapenv = soapenv.plain()
|
||||
soapenv = soapenv.encode('utf-8')
|
||||
plugins.message.sending(envelope=soapenv)
|
||||
request = Request(location, soapenv)
|
||||
request.headers = self.headers()
|
||||
reply = transport.send(request)
|
||||
ctx = plugins.message.received(reply=reply.message)
|
||||
reply.message = ctx.reply
|
||||
if retxml:
|
||||
result = reply.message
|
||||
else:
|
||||
result = self.succeeded(binding, reply.message)
|
||||
except TransportError, e:
|
||||
if e.httpcode in (202,204):
|
||||
result = None
|
||||
else:
|
||||
log.error(self.last_sent())
|
||||
result = self.failed(binding, e)
|
||||
return result
|
||||
|
||||
def headers(self):
|
||||
"""
|
||||
Get http headers or the http/https request.
|
||||
@return: A dictionary of header/values.
|
||||
@rtype: dict
|
||||
"""
|
||||
action = self.method.soap.action
|
||||
stock = { 'Content-Type' : 'text/xml; charset=utf-8', 'SOAPAction': action }
|
||||
result = dict(stock, **self.options.headers)
|
||||
log.debug('headers = %s', result)
|
||||
return result
|
||||
|
||||
def succeeded(self, binding, reply):
|
||||
"""
|
||||
Request succeeded, process the reply
|
||||
@param binding: The binding to be used to process the reply.
|
||||
@type binding: L{bindings.binding.Binding}
|
||||
@param reply: The raw reply text.
|
||||
@type reply: str
|
||||
@return: The method result.
|
||||
@rtype: I{builtin}, L{Object}
|
||||
@raise WebFault: On server.
|
||||
"""
|
||||
log.debug('http succeeded:\n%s', reply)
|
||||
plugins = PluginContainer(self.options.plugins)
|
||||
if len(reply) > 0:
|
||||
reply, result = binding.get_reply(self.method, reply)
|
||||
self.last_received(reply)
|
||||
else:
|
||||
result = None
|
||||
ctx = plugins.message.unmarshalled(reply=result)
|
||||
result = ctx.reply
|
||||
if self.options.faults:
|
||||
return result
|
||||
else:
|
||||
return (200, result)
|
||||
|
||||
def failed(self, binding, error):
|
||||
"""
|
||||
Request failed, process reply based on reason
|
||||
@param binding: The binding to be used to process the reply.
|
||||
@type binding: L{suds.bindings.binding.Binding}
|
||||
@param error: The http error message
|
||||
@type error: L{transport.TransportError}
|
||||
"""
|
||||
status, reason = (error.httpcode, tostr(error))
|
||||
reply = error.fp.read()
|
||||
log.debug('http failed:\n%s', reply)
|
||||
if status == 500:
|
||||
if len(reply) > 0:
|
||||
r, p = binding.get_fault(reply)
|
||||
self.last_received(r)
|
||||
return (status, p)
|
||||
else:
|
||||
return (status, None)
|
||||
if self.options.faults:
|
||||
raise Exception((status, reason))
|
||||
else:
|
||||
return (status, None)
|
||||
|
||||
def location(self):
|
||||
p = Unskin(self.options)
|
||||
return p.get('location', self.method.location)
|
||||
|
||||
def last_sent(self, d=None):
|
||||
key = 'tx'
|
||||
messages = self.client.messages
|
||||
if d is None:
|
||||
return messages.get(key)
|
||||
else:
|
||||
messages[key] = d
|
||||
|
||||
def last_received(self, d=None):
|
||||
key = 'rx'
|
||||
messages = self.client.messages
|
||||
if d is None:
|
||||
return messages.get(key)
|
||||
else:
|
||||
messages[key] = d
|
||||
|
||||
|
||||
class SimClient(SoapClient):
|
||||
"""
|
||||
Loopback client used for message/reply simulation.
|
||||
"""
|
||||
|
||||
injkey = '__inject'
|
||||
|
||||
@classmethod
|
||||
def simulation(cls, kwargs):
|
||||
""" get whether loopback has been specified in the I{kwargs}. """
|
||||
return kwargs.has_key(SimClient.injkey)
|
||||
|
||||
def invoke(self, args, kwargs):
|
||||
"""
|
||||
Send the required soap message to invoke the specified method
|
||||
@param args: A list of args for the method invoked.
|
||||
@type args: list
|
||||
@param kwargs: Named (keyword) args for the method invoked.
|
||||
@type kwargs: dict
|
||||
@return: The result of the method invocation.
|
||||
@rtype: I{builtin} or I{subclass of} L{Object}
|
||||
"""
|
||||
simulation = kwargs[self.injkey]
|
||||
msg = simulation.get('msg')
|
||||
reply = simulation.get('reply')
|
||||
fault = simulation.get('fault')
|
||||
if msg is None:
|
||||
if reply is not None:
|
||||
return self.__reply(reply, args, kwargs)
|
||||
if fault is not None:
|
||||
return self.__fault(fault)
|
||||
raise Exception('(reply|fault) expected when msg=None')
|
||||
sax = Parser()
|
||||
msg = sax.parse(string=msg)
|
||||
return self.send(msg)
|
||||
|
||||
def __reply(self, reply, args, kwargs):
|
||||
""" simulate the reply """
|
||||
binding = self.method.binding.input
|
||||
msg = binding.get_message(self.method, args, kwargs)
|
||||
log.debug('inject (simulated) send message:\n%s', msg)
|
||||
binding = self.method.binding.output
|
||||
return self.succeeded(binding, reply)
|
||||
|
||||
def __fault(self, reply):
|
||||
""" simulate the (fault) reply """
|
||||
binding = self.method.binding.output
|
||||
if self.options.faults:
|
||||
r, p = binding.get_fault(reply)
|
||||
self.last_received(r)
|
||||
return (500, p)
|
||||
else:
|
||||
return (500, None)
|
||||
62
awx/lib/site-packages/suds/metrics.py
Normal file
62
awx/lib/site-packages/suds/metrics.py
Normal file
@ -0,0 +1,62 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{metrics} module defines classes and other resources
|
||||
designed for collecting and reporting performance metrics.
|
||||
"""
|
||||
|
||||
import time
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from math import modf
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
class Timer:
|
||||
|
||||
def __init__(self):
|
||||
self.started = 0
|
||||
self.stopped = 0
|
||||
|
||||
def start(self):
|
||||
self.started = time.time()
|
||||
self.stopped = 0
|
||||
return self
|
||||
|
||||
def stop(self):
|
||||
if self.started > 0:
|
||||
self.stopped = time.time()
|
||||
return self
|
||||
|
||||
def duration(self):
|
||||
return ( self.stopped - self.started )
|
||||
|
||||
def __str__(self):
|
||||
if self.started == 0:
|
||||
return 'not-running'
|
||||
if self.started > 0 and self.stopped == 0:
|
||||
return 'started: %d (running)' % self.started
|
||||
duration = self.duration()
|
||||
jmod = ( lambda m : (m[1], m[0]*1000) )
|
||||
if duration < 1:
|
||||
ms = (duration*1000)
|
||||
return '%d (ms)' % ms
|
||||
if duration < 60:
|
||||
m = modf(duration)
|
||||
return '%d.%.3d (seconds)' % jmod(m)
|
||||
m = modf(duration/60)
|
||||
return '%d.%.3d (minutes)' % jmod(m)
|
||||
59
awx/lib/site-packages/suds/mx/__init__.py
Normal file
59
awx/lib/site-packages/suds/mx/__init__.py
Normal file
@ -0,0 +1,59 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides modules containing classes to support
|
||||
marshalling (XML).
|
||||
"""
|
||||
|
||||
from suds.sudsobject import Object
|
||||
|
||||
|
||||
class Content(Object):
|
||||
"""
|
||||
Marshaller Content.
|
||||
@ivar tag: The content tag.
|
||||
@type tag: str
|
||||
@ivar value: The content's value.
|
||||
@type value: I{any}
|
||||
"""
|
||||
|
||||
extensions = []
|
||||
|
||||
def __init__(self, tag=None, value=None, **kwargs):
|
||||
"""
|
||||
@param tag: The content tag.
|
||||
@type tag: str
|
||||
@param value: The content's value.
|
||||
@type value: I{any}
|
||||
"""
|
||||
Object.__init__(self)
|
||||
self.tag = tag
|
||||
self.value = value
|
||||
for k,v in kwargs.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name not in self.__dict__:
|
||||
if name in self.extensions:
|
||||
v = None
|
||||
setattr(self, name, v)
|
||||
else:
|
||||
raise AttributeError, \
|
||||
'Content has no attribute %s' % name
|
||||
else:
|
||||
v = self.__dict__[name]
|
||||
return v
|
||||
316
awx/lib/site-packages/suds/mx/appender.py
Normal file
316
awx/lib/site-packages/suds/mx/appender.py
Normal file
@ -0,0 +1,316 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides appender classes for I{marshalling}.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.mx import *
|
||||
from suds.sudsobject import footprint
|
||||
from suds.sudsobject import Object, Property
|
||||
from suds.sax.element import Element
|
||||
from suds.sax.text import Text
|
||||
from copy import deepcopy
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
class Matcher:
|
||||
"""
|
||||
Appender matcher.
|
||||
@ivar cls: A class object.
|
||||
@type cls: I{classobj}
|
||||
"""
|
||||
|
||||
def __init__(self, cls):
|
||||
"""
|
||||
@param cls: A class object.
|
||||
@type cls: I{classobj}
|
||||
"""
|
||||
self.cls = cls
|
||||
|
||||
def __eq__(self, x):
|
||||
if self.cls is None:
|
||||
return ( x is None )
|
||||
else:
|
||||
return isinstance(x, self.cls)
|
||||
|
||||
|
||||
class ContentAppender:
|
||||
"""
|
||||
Appender used to add content to marshalled objects.
|
||||
@ivar default: The default appender.
|
||||
@type default: L{Appender}
|
||||
@ivar appenders: A I{table} of appenders mapped by class.
|
||||
@type appenders: I{table}
|
||||
"""
|
||||
|
||||
def __init__(self, marshaller):
|
||||
"""
|
||||
@param marshaller: A marshaller.
|
||||
@type marshaller: L{suds.mx.core.Core}
|
||||
"""
|
||||
self.default = PrimativeAppender(marshaller)
|
||||
self.appenders = (
|
||||
(Matcher(None),
|
||||
NoneAppender(marshaller)),
|
||||
(Matcher(null),
|
||||
NoneAppender(marshaller)),
|
||||
(Matcher(Property),
|
||||
PropertyAppender(marshaller)),
|
||||
(Matcher(Object),
|
||||
ObjectAppender(marshaller)),
|
||||
(Matcher(Element),
|
||||
ElementAppender(marshaller)),
|
||||
(Matcher(Text),
|
||||
TextAppender(marshaller)),
|
||||
(Matcher(list),
|
||||
ListAppender(marshaller)),
|
||||
(Matcher(tuple),
|
||||
ListAppender(marshaller)),
|
||||
(Matcher(dict),
|
||||
DictAppender(marshaller)),
|
||||
)
|
||||
|
||||
def append(self, parent, content):
|
||||
"""
|
||||
Select an appender and append the content to parent.
|
||||
@param parent: A parent node.
|
||||
@type parent: L{Element}
|
||||
@param content: The content to append.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
appender = self.default
|
||||
for a in self.appenders:
|
||||
if a[0] == content.value:
|
||||
appender = a[1]
|
||||
break
|
||||
appender.append(parent, content)
|
||||
|
||||
|
||||
class Appender:
|
||||
"""
|
||||
An appender used by the marshaller to append content.
|
||||
@ivar marshaller: A marshaller.
|
||||
@type marshaller: L{suds.mx.core.Core}
|
||||
"""
|
||||
|
||||
def __init__(self, marshaller):
|
||||
"""
|
||||
@param marshaller: A marshaller.
|
||||
@type marshaller: L{suds.mx.core.Core}
|
||||
"""
|
||||
self.marshaller = marshaller
|
||||
|
||||
def node(self, content):
|
||||
"""
|
||||
Create and return an XML node that is qualified
|
||||
using the I{type}. Also, make sure all referenced namespace
|
||||
prefixes are declared.
|
||||
@param content: The content for which proccessing has ended.
|
||||
@type content: L{Object}
|
||||
@return: A new node.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
return self.marshaller.node(content)
|
||||
|
||||
def setnil(self, node, content):
|
||||
"""
|
||||
Set the value of the I{node} to nill.
|
||||
@param node: A I{nil} node.
|
||||
@type node: L{Element}
|
||||
@param content: The content for which proccessing has ended.
|
||||
@type content: L{Object}
|
||||
"""
|
||||
self.marshaller.setnil(node, content)
|
||||
|
||||
def setdefault(self, node, content):
|
||||
"""
|
||||
Set the value of the I{node} to a default value.
|
||||
@param node: A I{nil} node.
|
||||
@type node: L{Element}
|
||||
@param content: The content for which proccessing has ended.
|
||||
@type content: L{Object}
|
||||
@return: The default.
|
||||
"""
|
||||
return self.marshaller.setdefault(node, content)
|
||||
|
||||
def optional(self, content):
|
||||
"""
|
||||
Get whether the specified content is optional.
|
||||
@param content: The content which to check.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
return self.marshaller.optional(content)
|
||||
|
||||
def suspend(self, content):
|
||||
"""
|
||||
Notify I{marshaller} that appending this content has suspended.
|
||||
@param content: The content for which proccessing has been suspended.
|
||||
@type content: L{Object}
|
||||
"""
|
||||
self.marshaller.suspend(content)
|
||||
|
||||
def resume(self, content):
|
||||
"""
|
||||
Notify I{marshaller} that appending this content has resumed.
|
||||
@param content: The content for which proccessing has been resumed.
|
||||
@type content: L{Object}
|
||||
"""
|
||||
self.marshaller.resume(content)
|
||||
|
||||
def append(self, parent, content):
|
||||
"""
|
||||
Append the specified L{content} to the I{parent}.
|
||||
@param content: The content to append.
|
||||
@type content: L{Object}
|
||||
"""
|
||||
self.marshaller.append(parent, content)
|
||||
|
||||
|
||||
class PrimativeAppender(Appender):
|
||||
"""
|
||||
An appender for python I{primative} types.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
if content.tag.startswith('_'):
|
||||
attr = content.tag[1:]
|
||||
value = tostr(content.value)
|
||||
if value:
|
||||
parent.set(attr, value)
|
||||
else:
|
||||
child = self.node(content)
|
||||
child.setText(tostr(content.value))
|
||||
parent.append(child)
|
||||
|
||||
|
||||
class NoneAppender(Appender):
|
||||
"""
|
||||
An appender for I{None} values.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
child = self.node(content)
|
||||
default = self.setdefault(child, content)
|
||||
if default is None:
|
||||
self.setnil(child, content)
|
||||
parent.append(child)
|
||||
|
||||
|
||||
class PropertyAppender(Appender):
|
||||
"""
|
||||
A L{Property} appender.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
p = content.value
|
||||
child = self.node(content)
|
||||
child.setText(p.get())
|
||||
parent.append(child)
|
||||
for item in p.items():
|
||||
cont = Content(tag=item[0], value=item[1])
|
||||
Appender.append(self, child, cont)
|
||||
|
||||
|
||||
class ObjectAppender(Appender):
|
||||
"""
|
||||
An L{Object} appender.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
object = content.value
|
||||
if self.optional(content) and footprint(object) == 0:
|
||||
return
|
||||
child = self.node(content)
|
||||
parent.append(child)
|
||||
for item in object:
|
||||
cont = Content(tag=item[0], value=item[1])
|
||||
Appender.append(self, child, cont)
|
||||
|
||||
|
||||
class DictAppender(Appender):
|
||||
"""
|
||||
An python I{dict} appender.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
d = content.value
|
||||
if self.optional(content) and len(d) == 0:
|
||||
return
|
||||
child = self.node(content)
|
||||
parent.append(child)
|
||||
for item in d.items():
|
||||
cont = Content(tag=item[0], value=item[1])
|
||||
Appender.append(self, child, cont)
|
||||
|
||||
|
||||
class ElementWrapper(Element):
|
||||
"""
|
||||
Element wrapper.
|
||||
"""
|
||||
|
||||
def __init__(self, content):
|
||||
Element.__init__(self, content.name, content.parent)
|
||||
self.__content = content
|
||||
|
||||
def str(self, indent=0):
|
||||
return self.__content.str(indent)
|
||||
|
||||
|
||||
class ElementAppender(Appender):
|
||||
"""
|
||||
An appender for I{Element} types.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
if content.tag.startswith('_'):
|
||||
raise Exception('raw XML not valid as attribute value')
|
||||
child = ElementWrapper(content.value)
|
||||
parent.append(child)
|
||||
|
||||
|
||||
class ListAppender(Appender):
|
||||
"""
|
||||
A list/tuple appender.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
collection = content.value
|
||||
if len(collection):
|
||||
self.suspend(content)
|
||||
for item in collection:
|
||||
cont = Content(tag=content.tag, value=item)
|
||||
Appender.append(self, parent, cont)
|
||||
self.resume(content)
|
||||
|
||||
|
||||
class TextAppender(Appender):
|
||||
"""
|
||||
An appender for I{Text} values.
|
||||
"""
|
||||
|
||||
def append(self, parent, content):
|
||||
if content.tag.startswith('_'):
|
||||
attr = content.tag[1:]
|
||||
value = tostr(content.value)
|
||||
if value:
|
||||
parent.set(attr, value)
|
||||
else:
|
||||
child = self.node(content)
|
||||
child.setText(content.value)
|
||||
parent.append(child)
|
||||
48
awx/lib/site-packages/suds/mx/basic.py
Normal file
48
awx/lib/site-packages/suds/mx/basic.py
Normal file
@ -0,0 +1,48 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides basic I{marshaller} classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.mx import *
|
||||
from suds.mx.core import Core
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Basic(Core):
|
||||
"""
|
||||
A I{basic} (untyped) marshaller.
|
||||
"""
|
||||
|
||||
def process(self, value, tag=None):
|
||||
"""
|
||||
Process (marshal) the tag with the specified value using the
|
||||
optional type information.
|
||||
@param value: The value (content) of the XML node.
|
||||
@type value: (L{Object}|any)
|
||||
@param tag: The (optional) tag name for the value. The default is
|
||||
value.__class__.__name__
|
||||
@type tag: str
|
||||
@return: An xml node.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
content = Content(tag=tag, value=value)
|
||||
result = Core.process(self, content)
|
||||
return result
|
||||
158
awx/lib/site-packages/suds/mx/core.py
Normal file
158
awx/lib/site-packages/suds/mx/core.py
Normal file
@ -0,0 +1,158 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides I{marshaller} core classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.mx import *
|
||||
from suds.mx.appender import ContentAppender
|
||||
from suds.sax.element import Element
|
||||
from suds.sax.document import Document
|
||||
from suds.sudsobject import Property
|
||||
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Core:
|
||||
"""
|
||||
An I{abstract} marshaller. This class implement the core
|
||||
functionality of the marshaller.
|
||||
@ivar appender: A content appender.
|
||||
@type appender: L{ContentAppender}
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
"""
|
||||
self.appender = ContentAppender(self)
|
||||
|
||||
def process(self, content):
|
||||
"""
|
||||
Process (marshal) the tag with the specified value using the
|
||||
optional type information.
|
||||
@param content: The content to process.
|
||||
@type content: L{Object}
|
||||
"""
|
||||
log.debug('processing:\n%s', content)
|
||||
self.reset()
|
||||
if content.tag is None:
|
||||
content.tag = content.value.__class__.__name__
|
||||
document = Document()
|
||||
if isinstance(content.value, Property):
|
||||
root = self.node(content)
|
||||
self.append(document, content)
|
||||
else:
|
||||
self.append(document, content)
|
||||
return document.root()
|
||||
|
||||
def append(self, parent, content):
|
||||
"""
|
||||
Append the specified L{content} to the I{parent}.
|
||||
@param parent: The parent node to append to.
|
||||
@type parent: L{Element}
|
||||
@param content: The content to append.
|
||||
@type content: L{Object}
|
||||
"""
|
||||
log.debug('appending parent:\n%s\ncontent:\n%s', parent, content)
|
||||
if self.start(content):
|
||||
self.appender.append(parent, content)
|
||||
self.end(parent, content)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the marshaller.
|
||||
"""
|
||||
pass
|
||||
|
||||
def node(self, content):
|
||||
"""
|
||||
Create and return an XML node.
|
||||
@param content: The content for which proccessing has been suspended.
|
||||
@type content: L{Object}
|
||||
@return: An element.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
return Element(content.tag)
|
||||
|
||||
def start(self, content):
|
||||
"""
|
||||
Appending this content has started.
|
||||
@param content: The content for which proccessing has started.
|
||||
@type content: L{Content}
|
||||
@return: True to continue appending
|
||||
@rtype: boolean
|
||||
"""
|
||||
return True
|
||||
|
||||
def suspend(self, content):
|
||||
"""
|
||||
Appending this content has suspended.
|
||||
@param content: The content for which proccessing has been suspended.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
pass
|
||||
|
||||
def resume(self, content):
|
||||
"""
|
||||
Appending this content has resumed.
|
||||
@param content: The content for which proccessing has been resumed.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
pass
|
||||
|
||||
def end(self, parent, content):
|
||||
"""
|
||||
Appending this content has ended.
|
||||
@param parent: The parent node ending.
|
||||
@type parent: L{Element}
|
||||
@param content: The content for which proccessing has ended.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
pass
|
||||
|
||||
def setnil(self, node, content):
|
||||
"""
|
||||
Set the value of the I{node} to nill.
|
||||
@param node: A I{nil} node.
|
||||
@type node: L{Element}
|
||||
@param content: The content to set nil.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
pass
|
||||
|
||||
def setdefault(self, node, content):
|
||||
"""
|
||||
Set the value of the I{node} to a default value.
|
||||
@param node: A I{nil} node.
|
||||
@type node: L{Element}
|
||||
@param content: The content to set the default value.
|
||||
@type content: L{Content}
|
||||
@return: The default.
|
||||
"""
|
||||
pass
|
||||
|
||||
def optional(self, content):
|
||||
"""
|
||||
Get whether the specified content is optional.
|
||||
@param content: The content which to check.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
return False
|
||||
|
||||
133
awx/lib/site-packages/suds/mx/encoded.py
Normal file
133
awx/lib/site-packages/suds/mx/encoded.py
Normal file
@ -0,0 +1,133 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides encoded I{marshaller} classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.mx import *
|
||||
from suds.mx.literal import Literal
|
||||
from suds.mx.typer import Typer
|
||||
from suds.sudsobject import Factory, Object
|
||||
from suds.xsd.query import TypeQuery
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
#
|
||||
# Add encoded extensions
|
||||
# aty = The soap (section 5) encoded array type.
|
||||
#
|
||||
Content.extensions.append('aty')
|
||||
|
||||
|
||||
class Encoded(Literal):
|
||||
"""
|
||||
A SOAP section (5) encoding marshaller.
|
||||
This marshaller supports rpc/encoded soap styles.
|
||||
"""
|
||||
|
||||
def start(self, content):
|
||||
#
|
||||
# For soap encoded arrays, the 'aty' (array type) information
|
||||
# is extracted and added to the 'content'. Then, the content.value
|
||||
# is replaced with an object containing an 'item=[]' attribute
|
||||
# containing values that are 'typed' suds objects.
|
||||
#
|
||||
start = Literal.start(self, content)
|
||||
if start and isinstance(content.value, (list,tuple)):
|
||||
resolved = content.type.resolve()
|
||||
for c in resolved:
|
||||
if hasattr(c[0], 'aty'):
|
||||
content.aty = (content.tag, c[0].aty)
|
||||
self.cast(content)
|
||||
break
|
||||
return start
|
||||
|
||||
def end(self, parent, content):
|
||||
#
|
||||
# For soap encoded arrays, the soapenc:arrayType attribute is
|
||||
# added with proper type and size information.
|
||||
# Eg: soapenc:arrayType="xs:int[3]"
|
||||
#
|
||||
Literal.end(self, parent, content)
|
||||
if content.aty is None:
|
||||
return
|
||||
tag, aty = content.aty
|
||||
ns0 = ('at0', aty[1])
|
||||
ns1 = ('at1', 'http://schemas.xmlsoap.org/soap/encoding/')
|
||||
array = content.value.item
|
||||
child = parent.getChild(tag)
|
||||
child.addPrefix(ns0[0], ns0[1])
|
||||
child.addPrefix(ns1[0], ns1[1])
|
||||
name = '%s:arrayType' % ns1[0]
|
||||
value = '%s:%s[%d]' % (ns0[0], aty[0], len(array))
|
||||
child.set(name, value)
|
||||
|
||||
def encode(self, node, content):
|
||||
if content.type.any():
|
||||
Typer.auto(node, content.value)
|
||||
return
|
||||
if content.real.any():
|
||||
Typer.auto(node, content.value)
|
||||
return
|
||||
ns = None
|
||||
name = content.real.name
|
||||
if self.xstq:
|
||||
ns = content.real.namespace()
|
||||
Typer.manual(node, name, ns)
|
||||
|
||||
def cast(self, content):
|
||||
"""
|
||||
Cast the I{untyped} list items found in content I{value}.
|
||||
Each items contained in the list is checked for XSD type information.
|
||||
Items (values) that are I{untyped}, are replaced with suds objects and
|
||||
type I{metadata} is added.
|
||||
@param content: The content holding the collection.
|
||||
@type content: L{Content}
|
||||
@return: self
|
||||
@rtype: L{Encoded}
|
||||
"""
|
||||
aty = content.aty[1]
|
||||
resolved = content.type.resolve()
|
||||
array = Factory.object(resolved.name)
|
||||
array.item = []
|
||||
query = TypeQuery(aty)
|
||||
ref = query.execute(self.schema)
|
||||
if ref is None:
|
||||
raise TypeNotFound(qref)
|
||||
for x in content.value:
|
||||
if isinstance(x, (list, tuple)):
|
||||
array.item.append(x)
|
||||
continue
|
||||
if isinstance(x, Object):
|
||||
md = x.__metadata__
|
||||
md.sxtype = ref
|
||||
array.item.append(x)
|
||||
continue
|
||||
if isinstance(x, dict):
|
||||
x = Factory.object(ref.name, x)
|
||||
md = x.__metadata__
|
||||
md.sxtype = ref
|
||||
array.item.append(x)
|
||||
continue
|
||||
x = Factory.property(ref.name, x)
|
||||
md = x.__metadata__
|
||||
md.sxtype = ref
|
||||
array.item.append(x)
|
||||
content.value = array
|
||||
return self
|
||||
291
awx/lib/site-packages/suds/mx/literal.py
Normal file
291
awx/lib/site-packages/suds/mx/literal.py
Normal file
@ -0,0 +1,291 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides literal I{marshaller} classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.mx import *
|
||||
from suds.mx.core import Core
|
||||
from suds.mx.typer import Typer
|
||||
from suds.resolver import GraphResolver, Frame
|
||||
from suds.sax.element import Element
|
||||
from suds.sudsobject import Factory
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
#
|
||||
# Add typed extensions
|
||||
# type = The expected xsd type
|
||||
# real = The 'true' XSD type
|
||||
# ancestry = The 'type' ancestry
|
||||
#
|
||||
Content.extensions.append('type')
|
||||
Content.extensions.append('real')
|
||||
Content.extensions.append('ancestry')
|
||||
|
||||
|
||||
|
||||
class Typed(Core):
|
||||
"""
|
||||
A I{typed} marshaller.
|
||||
This marshaller is semi-typed as needed to support both
|
||||
I{document/literal} and I{rpc/literal} soap message styles.
|
||||
@ivar schema: An xsd schema.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
@ivar resolver: A schema type resolver.
|
||||
@type resolver: L{GraphResolver}
|
||||
"""
|
||||
|
||||
def __init__(self, schema, xstq=True):
|
||||
"""
|
||||
@param schema: A schema object
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
@param xstq: The B{x}ml B{s}chema B{t}ype B{q}ualified flag indicates
|
||||
that the I{xsi:type} attribute values should be qualified by namespace.
|
||||
@type xstq: bool
|
||||
"""
|
||||
Core.__init__(self)
|
||||
self.schema = schema
|
||||
self.xstq = xstq
|
||||
self.resolver = GraphResolver(self.schema)
|
||||
|
||||
def reset(self):
|
||||
self.resolver.reset()
|
||||
|
||||
def start(self, content):
|
||||
#
|
||||
# Start marshalling the 'content' by ensuring that both the
|
||||
# 'content' _and_ the resolver are primed with the XSD type
|
||||
# information. The 'content' value is both translated and
|
||||
# sorted based on the XSD type. Only values that are objects
|
||||
# have their attributes sorted.
|
||||
#
|
||||
log.debug('starting content:\n%s', content)
|
||||
if content.type is None:
|
||||
name = content.tag
|
||||
if name.startswith('_'):
|
||||
name = '@'+name[1:]
|
||||
content.type = self.resolver.find(name, content.value)
|
||||
if content.type is None:
|
||||
raise TypeNotFound(content.tag)
|
||||
else:
|
||||
known = None
|
||||
if isinstance(content.value, Object):
|
||||
known = self.resolver.known(content.value)
|
||||
if known is None:
|
||||
log.debug('object has no type information', content.value)
|
||||
known = content.type
|
||||
frame = Frame(content.type, resolved=known)
|
||||
self.resolver.push(frame)
|
||||
frame = self.resolver.top()
|
||||
content.real = frame.resolved
|
||||
content.ancestry = frame.ancestry
|
||||
self.translate(content)
|
||||
self.sort(content)
|
||||
if self.skip(content):
|
||||
log.debug('skipping (optional) content:\n%s', content)
|
||||
self.resolver.pop()
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def suspend(self, content):
|
||||
#
|
||||
# Suspend to process a list content. Primarily, this
|
||||
# involves popping the 'list' content off the resolver's
|
||||
# stack so the list items can be marshalled.
|
||||
#
|
||||
self.resolver.pop()
|
||||
|
||||
def resume(self, content):
|
||||
#
|
||||
# Resume processing a list content. To do this, we
|
||||
# really need to simply push the 'list' content
|
||||
# back onto the resolver stack.
|
||||
#
|
||||
self.resolver.push(Frame(content.type))
|
||||
|
||||
def end(self, parent, content):
|
||||
#
|
||||
# End processing the content. Make sure the content
|
||||
# ending matches the top of the resolver stack since for
|
||||
# list processing we play games with the resolver stack.
|
||||
#
|
||||
log.debug('ending content:\n%s', content)
|
||||
current = self.resolver.top().type
|
||||
if current == content.type:
|
||||
self.resolver.pop()
|
||||
else:
|
||||
raise Exception, \
|
||||
'content (end) mismatch: top=(%s) cont=(%s)' % \
|
||||
(current, content)
|
||||
|
||||
def node(self, content):
|
||||
#
|
||||
# Create an XML node and namespace qualify as defined
|
||||
# by the schema (elementFormDefault).
|
||||
#
|
||||
ns = content.type.namespace()
|
||||
if content.type.form_qualified:
|
||||
node = Element(content.tag, ns=ns)
|
||||
node.addPrefix(ns[0], ns[1])
|
||||
else:
|
||||
node = Element(content.tag)
|
||||
self.encode(node, content)
|
||||
log.debug('created - node:\n%s', node)
|
||||
return node
|
||||
|
||||
def setnil(self, node, content):
|
||||
#
|
||||
# Set the 'node' nil only if the XSD type
|
||||
# specifies that it is permitted.
|
||||
#
|
||||
if content.type.nillable:
|
||||
node.setnil()
|
||||
|
||||
def setdefault(self, node, content):
|
||||
#
|
||||
# Set the node to the default value specified
|
||||
# by the XSD type.
|
||||
#
|
||||
default = content.type.default
|
||||
if default is None:
|
||||
pass
|
||||
else:
|
||||
node.setText(default)
|
||||
return default
|
||||
|
||||
def optional(self, content):
|
||||
if content.type.optional():
|
||||
return True
|
||||
for a in content.ancestry:
|
||||
if a.optional():
|
||||
return True
|
||||
return False
|
||||
|
||||
def encode(self, node, content):
|
||||
# Add (soap) encoding information only if the resolved
|
||||
# type is derived by extension. Further, the xsi:type values
|
||||
# is qualified by namespace only if the content (tag) and
|
||||
# referenced type are in different namespaces.
|
||||
if content.type.any():
|
||||
return
|
||||
if not content.real.extension():
|
||||
return
|
||||
if content.type.resolve() == content.real:
|
||||
return
|
||||
ns = None
|
||||
name = content.real.name
|
||||
if self.xstq:
|
||||
ns = content.real.namespace('ns1')
|
||||
Typer.manual(node, name, ns)
|
||||
|
||||
def skip(self, content):
|
||||
"""
|
||||
Get whether to skip this I{content}.
|
||||
Should be skipped when the content is optional
|
||||
and either the value=None or the value is an empty list.
|
||||
@param content: The content to skip.
|
||||
@type content: L{Object}
|
||||
@return: True if content is to be skipped.
|
||||
@rtype: bool
|
||||
"""
|
||||
if self.optional(content):
|
||||
v = content.value
|
||||
if v is None:
|
||||
return True
|
||||
if isinstance(v, (list,tuple)) and len(v) == 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def optional(self, content):
|
||||
if content.type.optional():
|
||||
return True
|
||||
for a in content.ancestry:
|
||||
if a.optional():
|
||||
return True
|
||||
return False
|
||||
|
||||
def translate(self, content):
|
||||
"""
|
||||
Translate using the XSD type information.
|
||||
Python I{dict} is translated to a suds object. Most
|
||||
importantly, primative values are translated from python
|
||||
types to XML types using the XSD type.
|
||||
@param content: The content to translate.
|
||||
@type content: L{Object}
|
||||
@return: self
|
||||
@rtype: L{Typed}
|
||||
"""
|
||||
v = content.value
|
||||
if v is None:
|
||||
return
|
||||
if isinstance(v, dict):
|
||||
cls = content.real.name
|
||||
content.value = Factory.object(cls, v)
|
||||
md = content.value.__metadata__
|
||||
md.sxtype = content.type
|
||||
return
|
||||
v = content.real.translate(v, False)
|
||||
content.value = v
|
||||
return self
|
||||
|
||||
def sort(self, content):
|
||||
"""
|
||||
Sort suds object attributes based on ordering defined
|
||||
in the XSD type information.
|
||||
@param content: The content to sort.
|
||||
@type content: L{Object}
|
||||
@return: self
|
||||
@rtype: L{Typed}
|
||||
"""
|
||||
v = content.value
|
||||
if isinstance(v, Object):
|
||||
md = v.__metadata__
|
||||
md.ordering = self.ordering(content.real)
|
||||
return self
|
||||
|
||||
def ordering(self, type):
|
||||
"""
|
||||
Get the attribute ordering defined in the specified
|
||||
XSD type information.
|
||||
@param type: An XSD type object.
|
||||
@type type: SchemaObject
|
||||
@return: An ordered list of attribute names.
|
||||
@rtype: list
|
||||
"""
|
||||
result = []
|
||||
for child, ancestry in type.resolve():
|
||||
name = child.name
|
||||
if child.name is None:
|
||||
continue
|
||||
if child.isattr():
|
||||
name = '_%s' % child.name
|
||||
result.append(name)
|
||||
return result
|
||||
|
||||
|
||||
class Literal(Typed):
|
||||
"""
|
||||
A I{literal} marshaller.
|
||||
This marshaller is semi-typed as needed to support both
|
||||
I{document/literal} and I{rpc/literal} soap message styles.
|
||||
"""
|
||||
pass
|
||||
123
awx/lib/site-packages/suds/mx/typer.py
Normal file
123
awx/lib/site-packages/suds/mx/typer.py
Normal file
@ -0,0 +1,123 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides sx typing classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.mx import *
|
||||
from suds.sax import Namespace as NS
|
||||
from suds.sax.text import Text
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Typer:
|
||||
"""
|
||||
Provides XML node typing as either automatic or manual.
|
||||
@cvar types: A dict of class to xs type mapping.
|
||||
@type types: dict
|
||||
"""
|
||||
|
||||
types = {
|
||||
int : ('int', NS.xsdns),
|
||||
long : ('long', NS.xsdns),
|
||||
float : ('float', NS.xsdns),
|
||||
str : ('string', NS.xsdns),
|
||||
unicode : ('string', NS.xsdns),
|
||||
Text : ('string', NS.xsdns),
|
||||
bool : ('boolean', NS.xsdns),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def auto(cls, node, value=None):
|
||||
"""
|
||||
Automatically set the node's xsi:type attribute based on either I{value}'s
|
||||
class or the class of the node's text. When I{value} is an unmapped class,
|
||||
the default type (xs:any) is set.
|
||||
@param node: An XML node
|
||||
@type node: L{sax.element.Element}
|
||||
@param value: An object that is or would be the node's text.
|
||||
@type value: I{any}
|
||||
@return: The specified node.
|
||||
@rtype: L{sax.element.Element}
|
||||
"""
|
||||
if value is None:
|
||||
value = node.getText()
|
||||
if isinstance(value, Object):
|
||||
known = cls.known(value)
|
||||
if known.name is None:
|
||||
return node
|
||||
tm = (known.name, known.namespace())
|
||||
else:
|
||||
tm = cls.types.get(value.__class__, cls.types.get(str))
|
||||
cls.manual(node, *tm)
|
||||
return node
|
||||
|
||||
@classmethod
|
||||
def manual(cls, node, tval, ns=None):
|
||||
"""
|
||||
Set the node's xsi:type attribute based on either I{value}'s
|
||||
class or the class of the node's text. Then adds the referenced
|
||||
prefix(s) to the node's prefix mapping.
|
||||
@param node: An XML node
|
||||
@type node: L{sax.element.Element}
|
||||
@param tval: The name of the schema type.
|
||||
@type tval: str
|
||||
@param ns: The XML namespace of I{tval}.
|
||||
@type ns: (prefix, uri)
|
||||
@return: The specified node.
|
||||
@rtype: L{sax.element.Element}
|
||||
"""
|
||||
xta = ':'.join((NS.xsins[0], 'type'))
|
||||
node.addPrefix(NS.xsins[0], NS.xsins[1])
|
||||
if ns is None:
|
||||
node.set(xta, tval)
|
||||
else:
|
||||
ns = cls.genprefix(node, ns)
|
||||
qname = ':'.join((ns[0], tval))
|
||||
node.set(xta, qname)
|
||||
node.addPrefix(ns[0], ns[1])
|
||||
return node
|
||||
|
||||
@classmethod
|
||||
def genprefix(cls, node, ns):
|
||||
"""
|
||||
Generate a prefix.
|
||||
@param node: An XML node on which the prefix will be used.
|
||||
@type node: L{sax.element.Element}
|
||||
@param ns: A namespace needing an unique prefix.
|
||||
@type ns: (prefix, uri)
|
||||
@return: The I{ns} with a new prefix.
|
||||
"""
|
||||
for n in range(1, 1024):
|
||||
p = 'ns%d' % n
|
||||
u = node.resolvePrefix(p, default=None)
|
||||
if u is None or u == ns[1]:
|
||||
return (p, ns[1])
|
||||
raise Exception('auto prefix, exhausted')
|
||||
|
||||
@classmethod
|
||||
def known(cls, object):
|
||||
try:
|
||||
md = object.__metadata__
|
||||
known = md.sxtype
|
||||
return known
|
||||
except:
|
||||
pass
|
||||
|
||||
123
awx/lib/site-packages/suds/options.py
Normal file
123
awx/lib/site-packages/suds/options.py
Normal file
@ -0,0 +1,123 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Suds basic options classes.
|
||||
"""
|
||||
|
||||
from suds.properties import *
|
||||
from suds.wsse import Security
|
||||
from suds.xsd.doctor import Doctor
|
||||
from suds.transport import Transport
|
||||
from suds.cache import Cache, NoCache
|
||||
|
||||
|
||||
class TpLinker(AutoLinker):
|
||||
"""
|
||||
Transport (auto) linker used to manage linkage between
|
||||
transport objects Properties and those Properties that contain them.
|
||||
"""
|
||||
|
||||
def updated(self, properties, prev, next):
|
||||
if isinstance(prev, Transport):
|
||||
tp = Unskin(prev.options)
|
||||
properties.unlink(tp)
|
||||
if isinstance(next, Transport):
|
||||
tp = Unskin(next.options)
|
||||
properties.link(tp)
|
||||
|
||||
|
||||
class Options(Skin):
|
||||
"""
|
||||
Options:
|
||||
- B{cache} - The XML document cache. May be set (None) for no caching.
|
||||
- type: L{Cache}
|
||||
- default: L{NoCache}
|
||||
- B{faults} - Raise faults raised by server,
|
||||
else return tuple from service method invocation as (httpcode, object).
|
||||
- type: I{bool}
|
||||
- default: True
|
||||
- B{service} - The default service name.
|
||||
- type: I{str}
|
||||
- default: None
|
||||
- B{port} - The default service port name, not tcp port.
|
||||
- type: I{str}
|
||||
- default: None
|
||||
- B{location} - This overrides the service port address I{URL} defined
|
||||
in the WSDL.
|
||||
- type: I{str}
|
||||
- default: None
|
||||
- B{transport} - The message transport.
|
||||
- type: L{Transport}
|
||||
- default: None
|
||||
- B{soapheaders} - The soap headers to be included in the soap message.
|
||||
- type: I{any}
|
||||
- default: None
|
||||
- B{wsse} - The web services I{security} provider object.
|
||||
- type: L{Security}
|
||||
- default: None
|
||||
- B{doctor} - A schema I{doctor} object.
|
||||
- type: L{Doctor}
|
||||
- default: None
|
||||
- B{xstq} - The B{x}ml B{s}chema B{t}ype B{q}ualified flag indicates
|
||||
that the I{xsi:type} attribute values should be qualified by namespace.
|
||||
- type: I{bool}
|
||||
- default: True
|
||||
- B{prefixes} - Elements of the soap message should be qualified (when needed)
|
||||
using XML prefixes as opposed to xmlns="" syntax.
|
||||
- type: I{bool}
|
||||
- default: True
|
||||
- B{retxml} - Flag that causes the I{raw} soap envelope to be returned instead
|
||||
of the python object graph.
|
||||
- type: I{bool}
|
||||
- default: False
|
||||
- B{prettyxml} - Flag that causes I{pretty} xml to be rendered when generating
|
||||
the outbound soap envelope.
|
||||
- type: I{bool}
|
||||
- default: False
|
||||
- B{autoblend} - Flag that ensures that the schema(s) defined within the
|
||||
WSDL import each other.
|
||||
- type: I{bool}
|
||||
- default: False
|
||||
- B{cachingpolicy} - The caching policy.
|
||||
- type: I{int}
|
||||
- 0 = Cache XML documents.
|
||||
- 1 = Cache WSDL (pickled) object.
|
||||
- default: 0
|
||||
- B{plugins} - A plugin container.
|
||||
- type: I{list}
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
domain = __name__
|
||||
definitions = [
|
||||
Definition('cache', Cache, NoCache()),
|
||||
Definition('faults', bool, True),
|
||||
Definition('transport', Transport, None, TpLinker()),
|
||||
Definition('service', (int, basestring), None),
|
||||
Definition('port', (int, basestring), None),
|
||||
Definition('location', basestring, None),
|
||||
Definition('soapheaders', (), ()),
|
||||
Definition('wsse', Security, None),
|
||||
Definition('doctor', Doctor, None),
|
||||
Definition('xstq', bool, True),
|
||||
Definition('prefixes', bool, True),
|
||||
Definition('retxml', bool, False),
|
||||
Definition('prettyxml', bool, False),
|
||||
Definition('autoblend', bool, False),
|
||||
Definition('cachingpolicy', int, 0),
|
||||
Definition('plugins', (list, tuple), []),
|
||||
]
|
||||
Skin.__init__(self, domain, definitions, kwargs)
|
||||
257
awx/lib/site-packages/suds/plugin.py
Normal file
257
awx/lib/site-packages/suds/plugin.py
Normal file
@ -0,0 +1,257 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The plugin module provides classes for implementation
|
||||
of suds plugins.
|
||||
"""
|
||||
|
||||
from suds import *
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Context(object):
|
||||
"""
|
||||
Plugin context.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class InitContext(Context):
|
||||
"""
|
||||
Init Context.
|
||||
@ivar wsdl: The wsdl.
|
||||
@type wsdl: L{wsdl.Definitions}
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DocumentContext(Context):
|
||||
"""
|
||||
The XML document load context.
|
||||
@ivar url: The URL.
|
||||
@type url: str
|
||||
@ivar document: Either the XML text or the B{parsed} document root.
|
||||
@type document: (str|L{sax.element.Element})
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MessageContext(Context):
|
||||
"""
|
||||
The context for sending the soap envelope.
|
||||
@ivar envelope: The soap envelope to be sent.
|
||||
@type envelope: (str|L{sax.element.Element})
|
||||
@ivar reply: The reply.
|
||||
@type reply: (str|L{sax.element.Element}|object)
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Plugin:
|
||||
"""
|
||||
Plugin base.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class InitPlugin(Plugin):
|
||||
"""
|
||||
The base class for suds I{init} plugins.
|
||||
"""
|
||||
|
||||
def initialized(self, context):
|
||||
"""
|
||||
Suds client initialization.
|
||||
Called after wsdl the has been loaded. Provides the plugin
|
||||
with the opportunity to inspect/modify the WSDL.
|
||||
@param context: The init context.
|
||||
@type context: L{InitContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class DocumentPlugin(Plugin):
|
||||
"""
|
||||
The base class for suds I{document} plugins.
|
||||
"""
|
||||
|
||||
def loaded(self, context):
|
||||
"""
|
||||
Suds has loaded a WSDL/XSD document. Provides the plugin
|
||||
with an opportunity to inspect/modify the unparsed document.
|
||||
Called after each WSDL/XSD document is loaded.
|
||||
@param context: The document context.
|
||||
@type context: L{DocumentContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
def parsed(self, context):
|
||||
"""
|
||||
Suds has parsed a WSDL/XSD document. Provides the plugin
|
||||
with an opportunity to inspect/modify the parsed document.
|
||||
Called after each WSDL/XSD document is parsed.
|
||||
@param context: The document context.
|
||||
@type context: L{DocumentContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class MessagePlugin(Plugin):
|
||||
"""
|
||||
The base class for suds I{soap message} plugins.
|
||||
"""
|
||||
|
||||
def marshalled(self, context):
|
||||
"""
|
||||
Suds will send the specified soap envelope.
|
||||
Provides the plugin with the opportunity to inspect/modify
|
||||
the envelope Document before it is sent.
|
||||
@param context: The send context.
|
||||
The I{envelope} is the envelope docuemnt.
|
||||
@type context: L{MessageContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
def sending(self, context):
|
||||
"""
|
||||
Suds will send the specified soap envelope.
|
||||
Provides the plugin with the opportunity to inspect/modify
|
||||
the message text it is sent.
|
||||
@param context: The send context.
|
||||
The I{envelope} is the envelope text.
|
||||
@type context: L{MessageContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
def received(self, context):
|
||||
"""
|
||||
Suds has received the specified reply.
|
||||
Provides the plugin with the opportunity to inspect/modify
|
||||
the received XML text before it is SAX parsed.
|
||||
@param context: The reply context.
|
||||
The I{reply} is the raw text.
|
||||
@type context: L{MessageContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
def parsed(self, context):
|
||||
"""
|
||||
Suds has sax parsed the received reply.
|
||||
Provides the plugin with the opportunity to inspect/modify
|
||||
the sax parsed DOM tree for the reply before it is unmarshalled.
|
||||
@param context: The reply context.
|
||||
The I{reply} is DOM tree.
|
||||
@type context: L{MessageContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
def unmarshalled(self, context):
|
||||
"""
|
||||
Suds has unmarshalled the received reply.
|
||||
Provides the plugin with the opportunity to inspect/modify
|
||||
the unmarshalled reply object before it is returned.
|
||||
@param context: The reply context.
|
||||
The I{reply} is unmarshalled suds object.
|
||||
@type context: L{MessageContext}
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class PluginContainer:
|
||||
"""
|
||||
Plugin container provides easy method invocation.
|
||||
@ivar plugins: A list of plugin objects.
|
||||
@type plugins: [L{Plugin},]
|
||||
@cvar ctxclass: A dict of plugin method / context classes.
|
||||
@type ctxclass: dict
|
||||
"""
|
||||
|
||||
domains = {\
|
||||
'init': (InitContext, InitPlugin),
|
||||
'document': (DocumentContext, DocumentPlugin),
|
||||
'message': (MessageContext, MessagePlugin ),
|
||||
}
|
||||
|
||||
def __init__(self, plugins):
|
||||
"""
|
||||
@param plugins: A list of plugin objects.
|
||||
@type plugins: [L{Plugin},]
|
||||
"""
|
||||
self.plugins = plugins
|
||||
|
||||
def __getattr__(self, name):
|
||||
domain = self.domains.get(name)
|
||||
if domain:
|
||||
plugins = []
|
||||
ctx, pclass = domain
|
||||
for p in self.plugins:
|
||||
if isinstance(p, pclass):
|
||||
plugins.append(p)
|
||||
return PluginDomain(ctx, plugins)
|
||||
else:
|
||||
raise Exception, 'plugin domain (%s), invalid' % name
|
||||
|
||||
|
||||
class PluginDomain:
|
||||
"""
|
||||
The plugin domain.
|
||||
@ivar ctx: A context.
|
||||
@type ctx: L{Context}
|
||||
@ivar plugins: A list of plugins (targets).
|
||||
@type plugins: list
|
||||
"""
|
||||
|
||||
def __init__(self, ctx, plugins):
|
||||
self.ctx = ctx
|
||||
self.plugins = plugins
|
||||
|
||||
def __getattr__(self, name):
|
||||
return Method(name, self)
|
||||
|
||||
|
||||
class Method:
|
||||
"""
|
||||
Plugin method.
|
||||
@ivar name: The method name.
|
||||
@type name: str
|
||||
@ivar domain: The plugin domain.
|
||||
@type domain: L{PluginDomain}
|
||||
"""
|
||||
|
||||
def __init__(self, name, domain):
|
||||
"""
|
||||
@param name: The method name.
|
||||
@type name: str
|
||||
@param domain: A plugin domain.
|
||||
@type domain: L{PluginDomain}
|
||||
"""
|
||||
self.name = name
|
||||
self.domain = domain
|
||||
|
||||
def __call__(self, **kwargs):
|
||||
ctx = self.domain.ctx()
|
||||
ctx.__dict__.update(kwargs)
|
||||
for plugin in self.domain.plugins:
|
||||
try:
|
||||
method = getattr(plugin, self.name, None)
|
||||
if method and callable(method):
|
||||
method(ctx)
|
||||
except Exception, pe:
|
||||
log.exception(pe)
|
||||
return ctx
|
||||
543
awx/lib/site-packages/suds/properties.py
Normal file
543
awx/lib/site-packages/suds/properties.py
Normal file
@ -0,0 +1,543 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Properties classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class AutoLinker(object):
|
||||
"""
|
||||
Base class, provides interface for I{automatic} link
|
||||
management between a L{Properties} object and the L{Properties}
|
||||
contained within I{values}.
|
||||
"""
|
||||
def updated(self, properties, prev, next):
|
||||
"""
|
||||
Notification that a values was updated and the linkage
|
||||
between the I{properties} contained with I{prev} need to
|
||||
be relinked to the L{Properties} contained within the
|
||||
I{next} value.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Link(object):
|
||||
"""
|
||||
Property link object.
|
||||
@ivar endpoints: A tuple of the (2) endpoints of the link.
|
||||
@type endpoints: tuple(2)
|
||||
"""
|
||||
def __init__(self, a, b):
|
||||
"""
|
||||
@param a: Property (A) to link.
|
||||
@type a: L{Property}
|
||||
@param b: Property (B) to link.
|
||||
@type b: L{Property}
|
||||
"""
|
||||
pA = Endpoint(self, a)
|
||||
pB = Endpoint(self, b)
|
||||
self.endpoints = (pA, pB)
|
||||
self.validate(a, b)
|
||||
a.links.append(pB)
|
||||
b.links.append(pA)
|
||||
|
||||
def validate(self, pA, pB):
|
||||
"""
|
||||
Validate that the two properties may be linked.
|
||||
@param pA: Endpoint (A) to link.
|
||||
@type pA: L{Endpoint}
|
||||
@param pB: Endpoint (B) to link.
|
||||
@type pB: L{Endpoint}
|
||||
@return: self
|
||||
@rtype: L{Link}
|
||||
"""
|
||||
if pA in pB.links or \
|
||||
pB in pA.links:
|
||||
raise Exception, 'Already linked'
|
||||
dA = pA.domains()
|
||||
dB = pB.domains()
|
||||
for d in dA:
|
||||
if d in dB:
|
||||
raise Exception, 'Duplicate domain "%s" found' % d
|
||||
for d in dB:
|
||||
if d in dA:
|
||||
raise Exception, 'Duplicate domain "%s" found' % d
|
||||
kA = pA.keys()
|
||||
kB = pB.keys()
|
||||
for k in kA:
|
||||
if k in kB:
|
||||
raise Exception, 'Duplicate key %s found' % k
|
||||
for k in kB:
|
||||
if k in kA:
|
||||
raise Exception, 'Duplicate key %s found' % k
|
||||
return self
|
||||
|
||||
def teardown(self):
|
||||
"""
|
||||
Teardown the link.
|
||||
Removes endpoints from properties I{links} collection.
|
||||
@return: self
|
||||
@rtype: L{Link}
|
||||
"""
|
||||
pA, pB = self.endpoints
|
||||
if pA in pB.links:
|
||||
pB.links.remove(pA)
|
||||
if pB in pA.links:
|
||||
pA.links.remove(pB)
|
||||
return self
|
||||
|
||||
|
||||
class Endpoint(object):
|
||||
"""
|
||||
Link endpoint (wrapper).
|
||||
@ivar link: The associated link.
|
||||
@type link: L{Link}
|
||||
@ivar target: The properties object.
|
||||
@type target: L{Property}
|
||||
"""
|
||||
def __init__(self, link, target):
|
||||
self.link = link
|
||||
self.target = target
|
||||
|
||||
def teardown(self):
|
||||
return self.link.teardown()
|
||||
|
||||
def __eq__(self, rhs):
|
||||
return ( self.target == rhs )
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.target)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.target, name)
|
||||
|
||||
|
||||
class Definition:
|
||||
"""
|
||||
Property definition.
|
||||
@ivar name: The property name.
|
||||
@type name: str
|
||||
@ivar classes: The (class) list of permitted values
|
||||
@type classes: tuple
|
||||
@ivar default: The default value.
|
||||
@ivar type: any
|
||||
"""
|
||||
def __init__(self, name, classes, default, linker=AutoLinker()):
|
||||
"""
|
||||
@param name: The property name.
|
||||
@type name: str
|
||||
@param classes: The (class) list of permitted values
|
||||
@type classes: tuple
|
||||
@param default: The default value.
|
||||
@type default: any
|
||||
"""
|
||||
if not isinstance(classes, (list, tuple)):
|
||||
classes = (classes,)
|
||||
self.name = name
|
||||
self.classes = classes
|
||||
self.default = default
|
||||
self.linker = linker
|
||||
|
||||
def nvl(self, value=None):
|
||||
"""
|
||||
Convert the I{value} into the default when I{None}.
|
||||
@param value: The proposed value.
|
||||
@type value: any
|
||||
@return: The I{default} when I{value} is I{None}, else I{value}.
|
||||
@rtype: any
|
||||
"""
|
||||
if value is None:
|
||||
return self.default
|
||||
else:
|
||||
return value
|
||||
|
||||
def validate(self, value):
|
||||
"""
|
||||
Validate the I{value} is of the correct class.
|
||||
@param value: The value to validate.
|
||||
@type value: any
|
||||
@raise AttributeError: When I{value} is invalid.
|
||||
"""
|
||||
if value is None:
|
||||
return
|
||||
if len(self.classes) and \
|
||||
not isinstance(value, self.classes):
|
||||
msg = '"%s" must be: %s' % (self.name, self.classes)
|
||||
raise AttributeError,msg
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return '%s: %s' % (self.name, str(self))
|
||||
|
||||
def __str__(self):
|
||||
s = []
|
||||
if len(self.classes):
|
||||
s.append('classes=%s' % str(self.classes))
|
||||
else:
|
||||
s.append('classes=*')
|
||||
s.append("default=%s" % str(self.default))
|
||||
return ', '.join(s)
|
||||
|
||||
|
||||
class Properties:
|
||||
"""
|
||||
Represents basic application properties.
|
||||
Provides basic type validation, default values and
|
||||
link/synchronization behavior.
|
||||
@ivar domain: The domain name.
|
||||
@type domain: str
|
||||
@ivar definitions: A table of property definitions.
|
||||
@type definitions: {name: L{Definition}}
|
||||
@ivar links: A list of linked property objects used to create
|
||||
a network of properties.
|
||||
@type links: [L{Property},..]
|
||||
@ivar defined: A dict of property values.
|
||||
@type defined: dict
|
||||
"""
|
||||
def __init__(self, domain, definitions, kwargs):
|
||||
"""
|
||||
@param domain: The property domain name.
|
||||
@type domain: str
|
||||
@param definitions: A table of property definitions.
|
||||
@type definitions: {name: L{Definition}}
|
||||
@param kwargs: A list of property name/values to set.
|
||||
@type kwargs: dict
|
||||
"""
|
||||
self.definitions = {}
|
||||
for d in definitions:
|
||||
self.definitions[d.name] = d
|
||||
self.domain = domain
|
||||
self.links = []
|
||||
self.defined = {}
|
||||
self.modified = set()
|
||||
self.prime()
|
||||
self.update(kwargs)
|
||||
|
||||
def definition(self, name):
|
||||
"""
|
||||
Get the definition for the property I{name}.
|
||||
@param name: The property I{name} to find the definition for.
|
||||
@type name: str
|
||||
@return: The property definition
|
||||
@rtype: L{Definition}
|
||||
@raise AttributeError: On not found.
|
||||
"""
|
||||
d = self.definitions.get(name)
|
||||
if d is None:
|
||||
raise AttributeError(name)
|
||||
return d
|
||||
|
||||
def update(self, other):
|
||||
"""
|
||||
Update the property values as specified by keyword/value.
|
||||
@param other: An object to update from.
|
||||
@type other: (dict|L{Properties})
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
if isinstance(other, Properties):
|
||||
other = other.defined
|
||||
for n,v in other.items():
|
||||
self.set(n, v)
|
||||
return self
|
||||
|
||||
def notset(self, name):
|
||||
"""
|
||||
Get whether a property has never been set by I{name}.
|
||||
@param name: A property name.
|
||||
@type name: str
|
||||
@return: True if never been set.
|
||||
@rtype: bool
|
||||
"""
|
||||
self.provider(name).__notset(name)
|
||||
|
||||
def set(self, name, value):
|
||||
"""
|
||||
Set the I{value} of a property by I{name}.
|
||||
The value is validated against the definition and set
|
||||
to the default when I{value} is None.
|
||||
@param name: The property name.
|
||||
@type name: str
|
||||
@param value: The new property value.
|
||||
@type value: any
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
self.provider(name).__set(name, value)
|
||||
return self
|
||||
|
||||
def unset(self, name):
|
||||
"""
|
||||
Unset a property by I{name}.
|
||||
@param name: A property name.
|
||||
@type name: str
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
self.provider(name).__set(name, None)
|
||||
return self
|
||||
|
||||
def get(self, name, *df):
|
||||
"""
|
||||
Get the value of a property by I{name}.
|
||||
@param name: The property name.
|
||||
@type name: str
|
||||
@param df: An optional value to be returned when the value
|
||||
is not set
|
||||
@type df: [1].
|
||||
@return: The stored value, or I{df[0]} if not set.
|
||||
@rtype: any
|
||||
"""
|
||||
return self.provider(name).__get(name, *df)
|
||||
|
||||
def link(self, other):
|
||||
"""
|
||||
Link (associate) this object with anI{other} properties object
|
||||
to create a network of properties. Links are bidirectional.
|
||||
@param other: The object to link.
|
||||
@type other: L{Properties}
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
Link(self, other)
|
||||
return self
|
||||
|
||||
def unlink(self, *others):
|
||||
"""
|
||||
Unlink (disassociate) the specified properties object.
|
||||
@param others: The list object to unlink. Unspecified means unlink all.
|
||||
@type others: [L{Properties},..]
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
if not len(others):
|
||||
others = self.links[:]
|
||||
for p in self.links[:]:
|
||||
if p in others:
|
||||
p.teardown()
|
||||
return self
|
||||
|
||||
def provider(self, name, history=None):
|
||||
"""
|
||||
Find the provider of the property by I{name}.
|
||||
@param name: The property name.
|
||||
@type name: str
|
||||
@param history: A history of nodes checked to prevent
|
||||
circular hunting.
|
||||
@type history: [L{Properties},..]
|
||||
@return: The provider when found. Otherwise, None (when nested)
|
||||
and I{self} when not nested.
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
if history is None:
|
||||
history = []
|
||||
history.append(self)
|
||||
if name in self.definitions:
|
||||
return self
|
||||
for x in self.links:
|
||||
if x in history:
|
||||
continue
|
||||
provider = x.provider(name, history)
|
||||
if provider is not None:
|
||||
return provider
|
||||
history.remove(self)
|
||||
if len(history):
|
||||
return None
|
||||
return self
|
||||
|
||||
def keys(self, history=None):
|
||||
"""
|
||||
Get the set of I{all} property names.
|
||||
@param history: A history of nodes checked to prevent
|
||||
circular hunting.
|
||||
@type history: [L{Properties},..]
|
||||
@return: A set of property names.
|
||||
@rtype: list
|
||||
"""
|
||||
if history is None:
|
||||
history = []
|
||||
history.append(self)
|
||||
keys = set()
|
||||
keys.update(self.definitions.keys())
|
||||
for x in self.links:
|
||||
if x in history:
|
||||
continue
|
||||
keys.update(x.keys(history))
|
||||
history.remove(self)
|
||||
return keys
|
||||
|
||||
def domains(self, history=None):
|
||||
"""
|
||||
Get the set of I{all} domain names.
|
||||
@param history: A history of nodes checked to prevent
|
||||
circular hunting.
|
||||
@type history: [L{Properties},..]
|
||||
@return: A set of domain names.
|
||||
@rtype: list
|
||||
"""
|
||||
if history is None:
|
||||
history = []
|
||||
history.append(self)
|
||||
domains = set()
|
||||
domains.add(self.domain)
|
||||
for x in self.links:
|
||||
if x in history:
|
||||
continue
|
||||
domains.update(x.domains(history))
|
||||
history.remove(self)
|
||||
return domains
|
||||
|
||||
def prime(self):
|
||||
"""
|
||||
Prime the stored values based on default values
|
||||
found in property definitions.
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
for d in self.definitions.values():
|
||||
self.defined[d.name] = d.default
|
||||
return self
|
||||
|
||||
def __notset(self, name):
|
||||
return not (name in self.modified)
|
||||
|
||||
def __set(self, name, value):
|
||||
d = self.definition(name)
|
||||
d.validate(value)
|
||||
value = d.nvl(value)
|
||||
prev = self.defined[name]
|
||||
self.defined[name] = value
|
||||
self.modified.add(name)
|
||||
d.linker.updated(self, prev, value)
|
||||
|
||||
def __get(self, name, *df):
|
||||
d = self.definition(name)
|
||||
value = self.defined.get(name)
|
||||
if value == d.default and len(df):
|
||||
value = df[0]
|
||||
return value
|
||||
|
||||
def str(self, history):
|
||||
s = []
|
||||
s.append('Definitions:')
|
||||
for d in self.definitions.values():
|
||||
s.append('\t%s' % repr(d))
|
||||
s.append('Content:')
|
||||
for d in self.defined.items():
|
||||
s.append('\t%s' % str(d))
|
||||
if self not in history:
|
||||
history.append(self)
|
||||
s.append('Linked:')
|
||||
for x in self.links:
|
||||
s.append(x.str(history))
|
||||
history.remove(self)
|
||||
return '\n'.join(s)
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
def __str__(self):
|
||||
return self.str([])
|
||||
|
||||
|
||||
class Skin(object):
|
||||
"""
|
||||
The meta-programming I{skin} around the L{Properties} object.
|
||||
@ivar __pts__: The wrapped object.
|
||||
@type __pts__: L{Properties}.
|
||||
"""
|
||||
def __init__(self, domain, definitions, kwargs):
|
||||
self.__pts__ = Properties(domain, definitions, kwargs)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
builtin = name.startswith('__') and name.endswith('__')
|
||||
if builtin:
|
||||
self.__dict__[name] = value
|
||||
return
|
||||
self.__pts__.set(name, value)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self.__pts__.get(name)
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.__pts__)
|
||||
|
||||
|
||||
class Unskin(object):
|
||||
def __new__(self, *args, **kwargs):
|
||||
return args[0].__pts__
|
||||
|
||||
|
||||
class Inspector:
|
||||
"""
|
||||
Wrapper inspector.
|
||||
"""
|
||||
def __init__(self, options):
|
||||
self.properties = options.__pts__
|
||||
|
||||
def get(self, name, *df):
|
||||
"""
|
||||
Get the value of a property by I{name}.
|
||||
@param name: The property name.
|
||||
@type name: str
|
||||
@param df: An optional value to be returned when the value
|
||||
is not set
|
||||
@type df: [1].
|
||||
@return: The stored value, or I{df[0]} if not set.
|
||||
@rtype: any
|
||||
"""
|
||||
return self.properties.get(name, *df)
|
||||
|
||||
def update(self, **kwargs):
|
||||
"""
|
||||
Update the property values as specified by keyword/value.
|
||||
@param kwargs: A list of property name/values to set.
|
||||
@type kwargs: dict
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
return self.properties.update(**kwargs)
|
||||
|
||||
def link(self, other):
|
||||
"""
|
||||
Link (associate) this object with anI{other} properties object
|
||||
to create a network of properties. Links are bidirectional.
|
||||
@param other: The object to link.
|
||||
@type other: L{Properties}
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
p = other.__pts__
|
||||
return self.properties.link(p)
|
||||
|
||||
def unlink(self, other):
|
||||
"""
|
||||
Unlink (disassociate) the specified properties object.
|
||||
@param other: The object to unlink.
|
||||
@type other: L{Properties}
|
||||
@return: self
|
||||
@rtype: L{Properties}
|
||||
"""
|
||||
p = other.__pts__
|
||||
return self.properties.unlink(p)
|
||||
169
awx/lib/site-packages/suds/reader.py
Normal file
169
awx/lib/site-packages/suds/reader.py
Normal file
@ -0,0 +1,169 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains xml document reader classes.
|
||||
"""
|
||||
|
||||
|
||||
from suds.sax.parser import Parser
|
||||
from suds.transport import Request
|
||||
from suds.cache import Cache, NoCache
|
||||
from suds.store import DocumentStore
|
||||
from suds.plugin import PluginContainer
|
||||
from logging import getLogger
|
||||
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Reader:
|
||||
"""
|
||||
The reader provides integration with cache.
|
||||
@ivar options: An options object.
|
||||
@type options: I{Options}
|
||||
"""
|
||||
|
||||
def __init__(self, options):
|
||||
"""
|
||||
@param options: An options object.
|
||||
@type options: I{Options}
|
||||
"""
|
||||
self.options = options
|
||||
self.plugins = PluginContainer(options.plugins)
|
||||
|
||||
def mangle(self, name, x):
|
||||
"""
|
||||
Mangle the name by hashing the I{name} and appending I{x}.
|
||||
@return: the mangled name.
|
||||
"""
|
||||
h = abs(hash(name))
|
||||
return '%s-%s' % (h, x)
|
||||
|
||||
|
||||
class DocumentReader(Reader):
|
||||
"""
|
||||
The XML document reader provides an integration
|
||||
between the SAX L{Parser} and the document cache.
|
||||
"""
|
||||
|
||||
def open(self, url):
|
||||
"""
|
||||
Open an XML document at the specified I{url}.
|
||||
First, the document attempted to be retrieved from
|
||||
the I{object cache}. If not found, it is downloaded and
|
||||
parsed using the SAX parser. The result is added to the
|
||||
cache for the next open().
|
||||
@param url: A document url.
|
||||
@type url: str.
|
||||
@return: The specified XML document.
|
||||
@rtype: I{Document}
|
||||
"""
|
||||
cache = self.cache()
|
||||
id = self.mangle(url, 'document')
|
||||
d = cache.get(id)
|
||||
if d is None:
|
||||
d = self.download(url)
|
||||
cache.put(id, d)
|
||||
self.plugins.document.parsed(url=url, document=d.root())
|
||||
return d
|
||||
|
||||
def download(self, url):
|
||||
"""
|
||||
Download the docuemnt.
|
||||
@param url: A document url.
|
||||
@type url: str.
|
||||
@return: A file pointer to the docuemnt.
|
||||
@rtype: file-like
|
||||
"""
|
||||
store = DocumentStore()
|
||||
fp = store.open(url)
|
||||
if fp is None:
|
||||
fp = self.options.transport.open(Request(url))
|
||||
content = fp.read()
|
||||
fp.close()
|
||||
ctx = self.plugins.document.loaded(url=url, document=content)
|
||||
content = ctx.document
|
||||
sax = Parser()
|
||||
return sax.parse(string=content)
|
||||
|
||||
def cache(self):
|
||||
"""
|
||||
Get the cache.
|
||||
@return: The I{options} when I{cachingpolicy} = B{0}.
|
||||
@rtype: L{Cache}
|
||||
"""
|
||||
if self.options.cachingpolicy == 0:
|
||||
return self.options.cache
|
||||
else:
|
||||
return NoCache()
|
||||
|
||||
|
||||
class DefinitionsReader(Reader):
|
||||
"""
|
||||
The WSDL definitions reader provides an integration
|
||||
between the Definitions and the object cache.
|
||||
@ivar fn: A factory function (constructor) used to
|
||||
create the object not found in the cache.
|
||||
@type fn: I{Constructor}
|
||||
"""
|
||||
|
||||
def __init__(self, options, fn):
|
||||
"""
|
||||
@param options: An options object.
|
||||
@type options: I{Options}
|
||||
@param fn: A factory function (constructor) used to
|
||||
create the object not found in the cache.
|
||||
@type fn: I{Constructor}
|
||||
"""
|
||||
Reader.__init__(self, options)
|
||||
self.fn = fn
|
||||
|
||||
def open(self, url):
|
||||
"""
|
||||
Open a WSDL at the specified I{url}.
|
||||
First, the WSDL attempted to be retrieved from
|
||||
the I{object cache}. After unpickled from the cache, the
|
||||
I{options} attribute is restored.
|
||||
If not found, it is downloaded and instantiated using the
|
||||
I{fn} constructor and added to the cache for the next open().
|
||||
@param url: A WSDL url.
|
||||
@type url: str.
|
||||
@return: The WSDL object.
|
||||
@rtype: I{Definitions}
|
||||
"""
|
||||
cache = self.cache()
|
||||
id = self.mangle(url, 'wsdl')
|
||||
d = cache.get(id)
|
||||
if d is None:
|
||||
d = self.fn(url, self.options)
|
||||
cache.put(id, d)
|
||||
else:
|
||||
d.options = self.options
|
||||
for imp in d.imports:
|
||||
imp.imported.options = self.options
|
||||
return d
|
||||
|
||||
def cache(self):
|
||||
"""
|
||||
Get the cache.
|
||||
@return: The I{options} when I{cachingpolicy} = B{1}.
|
||||
@rtype: L{Cache}
|
||||
"""
|
||||
if self.options.cachingpolicy == 1:
|
||||
return self.options.cache
|
||||
else:
|
||||
return NoCache()
|
||||
496
awx/lib/site-packages/suds/resolver.py
Normal file
496
awx/lib/site-packages/suds/resolver.py
Normal file
@ -0,0 +1,496 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{resolver} module provides a collection of classes that
|
||||
provide wsdl/xsd named type resolution.
|
||||
"""
|
||||
|
||||
import re
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sax import splitPrefix, Namespace
|
||||
from suds.sudsobject import Object
|
||||
from suds.xsd.query import BlindQuery, TypeQuery, qualify
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Resolver:
|
||||
"""
|
||||
An I{abstract} schema-type resolver.
|
||||
@ivar schema: A schema object.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
"""
|
||||
|
||||
def __init__(self, schema):
|
||||
"""
|
||||
@param schema: A schema object.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
"""
|
||||
self.schema = schema
|
||||
|
||||
def find(self, name, resolved=True):
|
||||
"""
|
||||
Get the definition object for the schema object by name.
|
||||
@param name: The name of a schema object.
|
||||
@type name: basestring
|
||||
@param resolved: A flag indicating that the fully resolved type
|
||||
should be returned.
|
||||
@type resolved: boolean
|
||||
@return: The found schema I{type}
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
log.debug('searching schema for (%s)', name)
|
||||
qref = qualify(name, self.schema.root, self.schema.tns)
|
||||
query = BlindQuery(qref)
|
||||
result = query.execute(self.schema)
|
||||
if result is None:
|
||||
log.error('(%s) not-found', name)
|
||||
return None
|
||||
log.debug('found (%s) as (%s)', name, Repr(result))
|
||||
if resolved:
|
||||
result = result.resolve()
|
||||
return result
|
||||
|
||||
|
||||
class PathResolver(Resolver):
|
||||
"""
|
||||
Resolveds the definition object for the schema type located at the specified path.
|
||||
The path may contain (.) dot notation to specify nested types.
|
||||
@ivar wsdl: A wsdl object.
|
||||
@type wsdl: L{wsdl.Definitions}
|
||||
"""
|
||||
|
||||
def __init__(self, wsdl, ps='.'):
|
||||
"""
|
||||
@param wsdl: A schema object.
|
||||
@type wsdl: L{wsdl.Definitions}
|
||||
@param ps: The path separator character
|
||||
@type ps: char
|
||||
"""
|
||||
Resolver.__init__(self, wsdl.schema)
|
||||
self.wsdl = wsdl
|
||||
self.altp = re.compile('({)(.+)(})(.+)')
|
||||
self.splitp = re.compile('({.+})*[^\%s]+' % ps[0])
|
||||
|
||||
def find(self, path, resolved=True):
|
||||
"""
|
||||
Get the definition object for the schema type located at the specified path.
|
||||
The path may contain (.) dot notation to specify nested types.
|
||||
Actually, the path separator is usually a (.) but can be redefined
|
||||
during contruction.
|
||||
@param path: A (.) separated path to a schema type.
|
||||
@type path: basestring
|
||||
@param resolved: A flag indicating that the fully resolved type
|
||||
should be returned.
|
||||
@type resolved: boolean
|
||||
@return: The found schema I{type}
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
result = None
|
||||
parts = self.split(path)
|
||||
try:
|
||||
result = self.root(parts)
|
||||
if len(parts) > 1:
|
||||
result = result.resolve(nobuiltin=True)
|
||||
result = self.branch(result, parts)
|
||||
result = self.leaf(result, parts)
|
||||
if resolved:
|
||||
result = result.resolve(nobuiltin=True)
|
||||
except PathResolver.BadPath:
|
||||
log.error('path: "%s", not-found' % path)
|
||||
return result
|
||||
|
||||
def root(self, parts):
|
||||
"""
|
||||
Find the path root.
|
||||
@param parts: A list of path parts.
|
||||
@type parts: [str,..]
|
||||
@return: The root.
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
result = None
|
||||
name = parts[0]
|
||||
log.debug('searching schema for (%s)', name)
|
||||
qref = self.qualify(parts[0])
|
||||
query = BlindQuery(qref)
|
||||
result = query.execute(self.schema)
|
||||
if result is None:
|
||||
log.error('(%s) not-found', name)
|
||||
raise PathResolver.BadPath(name)
|
||||
else:
|
||||
log.debug('found (%s) as (%s)', name, Repr(result))
|
||||
return result
|
||||
|
||||
def branch(self, root, parts):
|
||||
"""
|
||||
Traverse the path until the leaf is reached.
|
||||
@param parts: A list of path parts.
|
||||
@type parts: [str,..]
|
||||
@param root: The root.
|
||||
@type root: L{xsd.sxbase.SchemaObject}
|
||||
@return: The end of the branch.
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
result = root
|
||||
for part in parts[1:-1]:
|
||||
name = splitPrefix(part)[1]
|
||||
log.debug('searching parent (%s) for (%s)', Repr(result), name)
|
||||
result, ancestry = result.get_child(name)
|
||||
if result is None:
|
||||
log.error('(%s) not-found', name)
|
||||
raise PathResolver.BadPath(name)
|
||||
else:
|
||||
result = result.resolve(nobuiltin=True)
|
||||
log.debug('found (%s) as (%s)', name, Repr(result))
|
||||
return result
|
||||
|
||||
def leaf(self, parent, parts):
|
||||
"""
|
||||
Find the leaf.
|
||||
@param parts: A list of path parts.
|
||||
@type parts: [str,..]
|
||||
@param parent: The leaf's parent.
|
||||
@type parent: L{xsd.sxbase.SchemaObject}
|
||||
@return: The leaf.
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
name = splitPrefix(parts[-1])[1]
|
||||
if name.startswith('@'):
|
||||
result, path = parent.get_attribute(name[1:])
|
||||
else:
|
||||
result, ancestry = parent.get_child(name)
|
||||
if result is None:
|
||||
raise PathResolver.BadPath(name)
|
||||
return result
|
||||
|
||||
def qualify(self, name):
|
||||
"""
|
||||
Qualify the name as either:
|
||||
- plain name
|
||||
- ns prefixed name (eg: ns0:Person)
|
||||
- fully ns qualified name (eg: {http://myns-uri}Person)
|
||||
@param name: The name of an object in the schema.
|
||||
@type name: str
|
||||
@return: A qualifed name.
|
||||
@rtype: qname
|
||||
"""
|
||||
m = self.altp.match(name)
|
||||
if m is None:
|
||||
return qualify(name, self.wsdl.root, self.wsdl.tns)
|
||||
else:
|
||||
return (m.group(4), m.group(2))
|
||||
|
||||
def split(self, s):
|
||||
"""
|
||||
Split the string on (.) while preserving any (.) inside the
|
||||
'{}' alternalte syntax for full ns qualification.
|
||||
@param s: A plain or qualifed name.
|
||||
@type s: str
|
||||
@return: A list of the name's parts.
|
||||
@rtype: [str,..]
|
||||
"""
|
||||
parts = []
|
||||
b = 0
|
||||
while 1:
|
||||
m = self.splitp.match(s, b)
|
||||
if m is None:
|
||||
break
|
||||
b,e = m.span()
|
||||
parts.append(s[b:e])
|
||||
b = e+1
|
||||
return parts
|
||||
|
||||
class BadPath(Exception): pass
|
||||
|
||||
|
||||
class TreeResolver(Resolver):
|
||||
"""
|
||||
The tree resolver is a I{stateful} tree resolver
|
||||
used to resolve each node in a tree. As such, it mirrors
|
||||
the tree structure to ensure that nodes are resolved in
|
||||
context.
|
||||
@ivar stack: The context stack.
|
||||
@type stack: list
|
||||
"""
|
||||
|
||||
def __init__(self, schema):
|
||||
"""
|
||||
@param schema: A schema object.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
"""
|
||||
Resolver.__init__(self, schema)
|
||||
self.stack = Stack()
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the resolver's state.
|
||||
"""
|
||||
self.stack = Stack()
|
||||
|
||||
def push(self, x):
|
||||
"""
|
||||
Push an I{object} onto the stack.
|
||||
@param x: An object to push.
|
||||
@type x: L{Frame}
|
||||
@return: The pushed frame.
|
||||
@rtype: L{Frame}
|
||||
"""
|
||||
if isinstance(x, Frame):
|
||||
frame = x
|
||||
else:
|
||||
frame = Frame(x)
|
||||
self.stack.append(frame)
|
||||
log.debug('push: (%s)\n%s', Repr(frame), Repr(self.stack))
|
||||
return frame
|
||||
|
||||
def top(self):
|
||||
"""
|
||||
Get the I{frame} at the top of the stack.
|
||||
@return: The top I{frame}, else None.
|
||||
@rtype: L{Frame}
|
||||
"""
|
||||
if len(self.stack):
|
||||
return self.stack[-1]
|
||||
else:
|
||||
return Frame.Empty()
|
||||
|
||||
def pop(self):
|
||||
"""
|
||||
Pop the frame at the top of the stack.
|
||||
@return: The popped frame, else None.
|
||||
@rtype: L{Frame}
|
||||
"""
|
||||
if len(self.stack):
|
||||
popped = self.stack.pop()
|
||||
log.debug('pop: (%s)\n%s', Repr(popped), Repr(self.stack))
|
||||
return popped
|
||||
else:
|
||||
log.debug('stack empty, not-popped')
|
||||
return None
|
||||
|
||||
def depth(self):
|
||||
"""
|
||||
Get the current stack depth.
|
||||
@return: The current stack depth.
|
||||
@rtype: int
|
||||
"""
|
||||
return len(self.stack)
|
||||
|
||||
def getchild(self, name, parent):
|
||||
""" get a child by name """
|
||||
log.debug('searching parent (%s) for (%s)', Repr(parent), name)
|
||||
if name.startswith('@'):
|
||||
return parent.get_attribute(name[1:])
|
||||
else:
|
||||
return parent.get_child(name)
|
||||
|
||||
|
||||
class NodeResolver(TreeResolver):
|
||||
"""
|
||||
The node resolver is a I{stateful} XML document resolver
|
||||
used to resolve each node in a tree. As such, it mirrors
|
||||
the tree structure to ensure that nodes are resolved in
|
||||
context.
|
||||
"""
|
||||
|
||||
def __init__(self, schema):
|
||||
"""
|
||||
@param schema: A schema object.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
"""
|
||||
TreeResolver.__init__(self, schema)
|
||||
|
||||
def find(self, node, resolved=False, push=True):
|
||||
"""
|
||||
@param node: An xml node to be resolved.
|
||||
@type node: L{sax.element.Element}
|
||||
@param resolved: A flag indicating that the fully resolved type should be
|
||||
returned.
|
||||
@type resolved: boolean
|
||||
@param push: Indicates that the resolved type should be
|
||||
pushed onto the stack.
|
||||
@type push: boolean
|
||||
@return: The found schema I{type}
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
name = node.name
|
||||
parent = self.top().resolved
|
||||
if parent is None:
|
||||
result, ancestry = self.query(name, node)
|
||||
else:
|
||||
result, ancestry = self.getchild(name, parent)
|
||||
known = self.known(node)
|
||||
if result is None:
|
||||
return result
|
||||
if push:
|
||||
frame = Frame(result, resolved=known, ancestry=ancestry)
|
||||
pushed = self.push(frame)
|
||||
if resolved:
|
||||
result = result.resolve()
|
||||
return result
|
||||
|
||||
def findattr(self, name, resolved=True):
|
||||
"""
|
||||
Find an attribute type definition.
|
||||
@param name: An attribute name.
|
||||
@type name: basestring
|
||||
@param resolved: A flag indicating that the fully resolved type should be
|
||||
returned.
|
||||
@type resolved: boolean
|
||||
@return: The found schema I{type}
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
name = '@%s'%name
|
||||
parent = self.top().resolved
|
||||
if parent is None:
|
||||
result, ancestry = self.query(name, node)
|
||||
else:
|
||||
result, ancestry = self.getchild(name, parent)
|
||||
if result is None:
|
||||
return result
|
||||
if resolved:
|
||||
result = result.resolve()
|
||||
return result
|
||||
|
||||
def query(self, name, node):
|
||||
""" blindly query the schema by name """
|
||||
log.debug('searching schema for (%s)', name)
|
||||
qref = qualify(name, node, node.namespace())
|
||||
query = BlindQuery(qref)
|
||||
result = query.execute(self.schema)
|
||||
return (result, [])
|
||||
|
||||
def known(self, node):
|
||||
""" resolve type referenced by @xsi:type """
|
||||
ref = node.get('type', Namespace.xsins)
|
||||
if ref is None:
|
||||
return None
|
||||
qref = qualify(ref, node, node.namespace())
|
||||
query = BlindQuery(qref)
|
||||
return query.execute(self.schema)
|
||||
|
||||
|
||||
class GraphResolver(TreeResolver):
|
||||
"""
|
||||
The graph resolver is a I{stateful} L{Object} graph resolver
|
||||
used to resolve each node in a tree. As such, it mirrors
|
||||
the tree structure to ensure that nodes are resolved in
|
||||
context.
|
||||
"""
|
||||
|
||||
def __init__(self, schema):
|
||||
"""
|
||||
@param schema: A schema object.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
"""
|
||||
TreeResolver.__init__(self, schema)
|
||||
|
||||
def find(self, name, object, resolved=False, push=True):
|
||||
"""
|
||||
@param name: The name of the object to be resolved.
|
||||
@type name: basestring
|
||||
@param object: The name's value.
|
||||
@type object: (any|L{Object})
|
||||
@param resolved: A flag indicating that the fully resolved type
|
||||
should be returned.
|
||||
@type resolved: boolean
|
||||
@param push: Indicates that the resolved type should be
|
||||
pushed onto the stack.
|
||||
@type push: boolean
|
||||
@return: The found schema I{type}
|
||||
@rtype: L{xsd.sxbase.SchemaObject}
|
||||
"""
|
||||
known = None
|
||||
parent = self.top().resolved
|
||||
if parent is None:
|
||||
result, ancestry = self.query(name)
|
||||
else:
|
||||
result, ancestry = self.getchild(name, parent)
|
||||
if result is None:
|
||||
return None
|
||||
if isinstance(object, Object):
|
||||
known = self.known(object)
|
||||
if push:
|
||||
frame = Frame(result, resolved=known, ancestry=ancestry)
|
||||
pushed = self.push(frame)
|
||||
if resolved:
|
||||
if known is None:
|
||||
result = result.resolve()
|
||||
else:
|
||||
result = known
|
||||
return result
|
||||
|
||||
def query(self, name):
|
||||
""" blindly query the schema by name """
|
||||
log.debug('searching schema for (%s)', name)
|
||||
schema = self.schema
|
||||
wsdl = self.wsdl()
|
||||
if wsdl is None:
|
||||
qref = qualify(name, schema.root, schema.tns)
|
||||
else:
|
||||
qref = qualify(name, wsdl.root, wsdl.tns)
|
||||
query = BlindQuery(qref)
|
||||
result = query.execute(schema)
|
||||
return (result, [])
|
||||
|
||||
def wsdl(self):
|
||||
""" get the wsdl """
|
||||
container = self.schema.container
|
||||
if container is None:
|
||||
return None
|
||||
else:
|
||||
return container.wsdl
|
||||
|
||||
def known(self, object):
|
||||
""" get the type specified in the object's metadata """
|
||||
try:
|
||||
md = object.__metadata__
|
||||
known = md.sxtype
|
||||
return known
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class Frame:
|
||||
def __init__(self, type, resolved=None, ancestry=()):
|
||||
self.type = type
|
||||
if resolved is None:
|
||||
resolved = type.resolve()
|
||||
self.resolved = resolved.resolve()
|
||||
self.ancestry = ancestry
|
||||
|
||||
def __str__(self):
|
||||
return '%s\n%s\n%s' % \
|
||||
(Repr(self.type),
|
||||
Repr(self.resolved),
|
||||
[Repr(t) for t in self.ancestry])
|
||||
|
||||
class Empty:
|
||||
def __getattr__(self, name):
|
||||
if name == 'ancestry':
|
||||
return ()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class Stack(list):
|
||||
def __repr__(self):
|
||||
result = []
|
||||
for item in self:
|
||||
result.append(repr(item))
|
||||
return '\n'.join(result)
|
||||
109
awx/lib/site-packages/suds/sax/__init__.py
Normal file
109
awx/lib/site-packages/suds/sax/__init__.py
Normal file
@ -0,0 +1,109 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The sax module contains a collection of classes that provide a
|
||||
(D)ocument (O)bject (M)odel representation of an XML document.
|
||||
The goal is to provide an easy, intuative interface for managing XML
|
||||
documents. Although, the term, DOM, is used above, this model is
|
||||
B{far} better.
|
||||
|
||||
XML namespaces in suds are represented using a (2) element tuple
|
||||
containing the prefix and the URI. Eg: I{('tns', 'http://myns')}
|
||||
|
||||
@var encoder: A I{pluggable} XML special character processor used to
|
||||
encode/decode strings.
|
||||
@type encoder: L{Encoder}
|
||||
"""
|
||||
|
||||
from suds.sax.enc import Encoder
|
||||
|
||||
#
|
||||
# pluggable XML special character encoder.
|
||||
#
|
||||
encoder = Encoder()
|
||||
|
||||
|
||||
def splitPrefix(name):
|
||||
"""
|
||||
Split the name into a tuple (I{prefix}, I{name}). The first element in
|
||||
the tuple is I{None} when the name does't have a prefix.
|
||||
@param name: A node name containing an optional prefix.
|
||||
@type name: basestring
|
||||
@return: A tuple containing the (2) parts of I{name}
|
||||
@rtype: (I{prefix}, I{name})
|
||||
"""
|
||||
if isinstance(name, basestring) \
|
||||
and ':' in name:
|
||||
return tuple(name.split(':', 1))
|
||||
else:
|
||||
return (None, name)
|
||||
|
||||
|
||||
class Namespace:
|
||||
"""
|
||||
The namespace class represents XML namespaces.
|
||||
"""
|
||||
|
||||
default = (None, None)
|
||||
xmlns = ('xml', 'http://www.w3.org/XML/1998/namespace')
|
||||
xsdns = ('xs', 'http://www.w3.org/2001/XMLSchema')
|
||||
xsins = ('xsi', 'http://www.w3.org/2001/XMLSchema-instance')
|
||||
all = (xsdns, xsins)
|
||||
|
||||
@classmethod
|
||||
def create(cls, p=None, u=None):
|
||||
return (p, u)
|
||||
|
||||
@classmethod
|
||||
def none(cls, ns):
|
||||
return ( ns == cls.default )
|
||||
|
||||
@classmethod
|
||||
def xsd(cls, ns):
|
||||
try:
|
||||
return cls.w3(ns) and ns[1].endswith('XMLSchema')
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def xsi(cls, ns):
|
||||
try:
|
||||
return cls.w3(ns) and ns[1].endswith('XMLSchema-instance')
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def xs(cls, ns):
|
||||
return ( cls.xsd(ns) or cls.xsi(ns) )
|
||||
|
||||
@classmethod
|
||||
def w3(cls, ns):
|
||||
try:
|
||||
return ns[1].startswith('http://www.w3.org')
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def isns(cls, ns):
|
||||
try:
|
||||
return isinstance(ns, tuple) and len(ns) == len(cls.default)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
181
awx/lib/site-packages/suds/sax/attribute.py
Normal file
181
awx/lib/site-packages/suds/sax/attribute.py
Normal file
@ -0,0 +1,181 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides XML I{attribute} classes.
|
||||
"""
|
||||
|
||||
import suds.sax
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sax import *
|
||||
from suds.sax.text import Text
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
class Attribute:
|
||||
"""
|
||||
An XML attribute object.
|
||||
@ivar parent: The node containing this attribute
|
||||
@type parent: L{element.Element}
|
||||
@ivar prefix: The I{optional} namespace prefix.
|
||||
@type prefix: basestring
|
||||
@ivar name: The I{unqualified} name of the attribute
|
||||
@type name: basestring
|
||||
@ivar value: The attribute's value
|
||||
@type value: basestring
|
||||
"""
|
||||
def __init__(self, name, value=None):
|
||||
"""
|
||||
@param name: The attribute's name with I{optional} namespace prefix.
|
||||
@type name: basestring
|
||||
@param value: The attribute's value
|
||||
@type value: basestring
|
||||
"""
|
||||
self.parent = None
|
||||
self.prefix, self.name = splitPrefix(name)
|
||||
self.setValue(value)
|
||||
|
||||
def clone(self, parent=None):
|
||||
"""
|
||||
Clone this object.
|
||||
@param parent: The parent for the clone.
|
||||
@type parent: L{element.Element}
|
||||
@return: A copy of this object assigned to the new parent.
|
||||
@rtype: L{Attribute}
|
||||
"""
|
||||
a = Attribute(self.qname(), self.value)
|
||||
a.parent = parent
|
||||
return a
|
||||
|
||||
def qname(self):
|
||||
"""
|
||||
Get the B{fully} qualified name of this attribute
|
||||
@return: The fully qualified name.
|
||||
@rtype: basestring
|
||||
"""
|
||||
if self.prefix is None:
|
||||
return self.name
|
||||
else:
|
||||
return ':'.join((self.prefix, self.name))
|
||||
|
||||
def setValue(self, value):
|
||||
"""
|
||||
Set the attributes value
|
||||
@param value: The new value (may be None)
|
||||
@type value: basestring
|
||||
@return: self
|
||||
@rtype: L{Attribute}
|
||||
"""
|
||||
if isinstance(value, Text):
|
||||
self.value = value
|
||||
else:
|
||||
self.value = Text(value)
|
||||
return self
|
||||
|
||||
def getValue(self, default=Text('')):
|
||||
"""
|
||||
Get the attributes value with optional default.
|
||||
@param default: An optional value to be return when the
|
||||
attribute's has not been set.
|
||||
@type default: basestring
|
||||
@return: The attribute's value, or I{default}
|
||||
@rtype: L{Text}
|
||||
"""
|
||||
if self.hasText():
|
||||
return self.value
|
||||
else:
|
||||
return default
|
||||
|
||||
def hasText(self):
|
||||
"""
|
||||
Get whether the attribute has I{text} and that it is not an empty
|
||||
(zero length) string.
|
||||
@return: True when has I{text}.
|
||||
@rtype: boolean
|
||||
"""
|
||||
return ( self.value is not None and len(self.value) )
|
||||
|
||||
def namespace(self):
|
||||
"""
|
||||
Get the attributes namespace. This may either be the namespace
|
||||
defined by an optional prefix, or its parent's namespace.
|
||||
@return: The attribute's namespace
|
||||
@rtype: (I{prefix}, I{name})
|
||||
"""
|
||||
if self.prefix is None:
|
||||
return Namespace.default
|
||||
else:
|
||||
return self.resolvePrefix(self.prefix)
|
||||
|
||||
def resolvePrefix(self, prefix):
|
||||
"""
|
||||
Resolve the specified prefix to a known namespace.
|
||||
@param prefix: A declared prefix
|
||||
@type prefix: basestring
|
||||
@return: The namespace that has been mapped to I{prefix}
|
||||
@rtype: (I{prefix}, I{name})
|
||||
"""
|
||||
ns = Namespace.default
|
||||
if self.parent is not None:
|
||||
ns = self.parent.resolvePrefix(prefix)
|
||||
return ns
|
||||
|
||||
def match(self, name=None, ns=None):
|
||||
"""
|
||||
Match by (optional) name and/or (optional) namespace.
|
||||
@param name: The optional attribute tag name.
|
||||
@type name: str
|
||||
@param ns: An optional namespace.
|
||||
@type ns: (I{prefix}, I{name})
|
||||
@return: True if matched.
|
||||
@rtype: boolean
|
||||
"""
|
||||
if name is None:
|
||||
byname = True
|
||||
else:
|
||||
byname = ( self.name == name )
|
||||
if ns is None:
|
||||
byns = True
|
||||
else:
|
||||
byns = ( self.namespace()[1] == ns[1] )
|
||||
return ( byname and byns )
|
||||
|
||||
def __eq__(self, rhs):
|
||||
""" equals operator """
|
||||
return rhs is not None and \
|
||||
isinstance(rhs, Attribute) and \
|
||||
self.prefix == rhs.name and \
|
||||
self.name == rhs.name
|
||||
|
||||
def __repr__(self):
|
||||
""" get a string representation """
|
||||
return \
|
||||
'attr (prefix=%s, name=%s, value=(%s))' %\
|
||||
(self.prefix, self.name, self.value)
|
||||
|
||||
def __str__(self):
|
||||
""" get an xml string representation """
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
""" get an xml string representation """
|
||||
n = self.qname()
|
||||
if self.hasText():
|
||||
v = self.value.escape()
|
||||
else:
|
||||
v = self.value
|
||||
return u'%s="%s"' % (n, v)
|
||||
378
awx/lib/site-packages/suds/sax/date.py
Normal file
378
awx/lib/site-packages/suds/sax/date.py
Normal file
@ -0,0 +1,378 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Nathan Van Gheem (vangheem@gmail.com)
|
||||
|
||||
"""
|
||||
The I{xdate} module provides classes for converstion
|
||||
between XML dates and python objects.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.xsd import *
|
||||
import time
|
||||
import datetime as dt
|
||||
import re
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Date:
|
||||
"""
|
||||
An XML date object.
|
||||
Supported formats:
|
||||
- YYYY-MM-DD
|
||||
- YYYY-MM-DD(z|Z)
|
||||
- YYYY-MM-DD+06:00
|
||||
- YYYY-MM-DD-06:00
|
||||
@ivar date: The object value.
|
||||
@type date: B{datetime}.I{date}
|
||||
"""
|
||||
def __init__(self, date):
|
||||
"""
|
||||
@param date: The value of the object.
|
||||
@type date: (date|str)
|
||||
@raise ValueError: When I{date} is invalid.
|
||||
"""
|
||||
if isinstance(date, dt.date):
|
||||
self.date = date
|
||||
return
|
||||
if isinstance(date, basestring):
|
||||
self.date = self.__parse(date)
|
||||
return
|
||||
raise ValueError, type(date)
|
||||
|
||||
def year(self):
|
||||
"""
|
||||
Get the I{year} component.
|
||||
@return: The year.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.date.year
|
||||
|
||||
def month(self):
|
||||
"""
|
||||
Get the I{month} component.
|
||||
@return: The month.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.date.month
|
||||
|
||||
def day(self):
|
||||
"""
|
||||
Get the I{day} component.
|
||||
@return: The day.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.date.day
|
||||
|
||||
def __parse(self, s):
|
||||
"""
|
||||
Parse the string date.
|
||||
Supported formats:
|
||||
- YYYY-MM-DD
|
||||
- YYYY-MM-DD(z|Z)
|
||||
- YYYY-MM-DD+06:00
|
||||
- YYYY-MM-DD-06:00
|
||||
Although, the TZ is ignored because it's meaningless
|
||||
without the time, right?
|
||||
@param s: A date string.
|
||||
@type s: str
|
||||
@return: A date object.
|
||||
@rtype: I{date}
|
||||
"""
|
||||
try:
|
||||
year, month, day = s[:10].split('-', 2)
|
||||
year = int(year)
|
||||
month = int(month)
|
||||
day = int(day)
|
||||
return dt.date(year, month, day)
|
||||
except:
|
||||
log.debug(s, exec_info=True)
|
||||
raise ValueError, 'Invalid format "%s"' % s
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.date.isoformat()
|
||||
|
||||
|
||||
class Time:
|
||||
"""
|
||||
An XML time object.
|
||||
Supported formats:
|
||||
- HH:MI:SS
|
||||
- HH:MI:SS(z|Z)
|
||||
- HH:MI:SS.ms
|
||||
- HH:MI:SS.ms(z|Z)
|
||||
- HH:MI:SS(+|-)06:00
|
||||
- HH:MI:SS.ms(+|-)06:00
|
||||
@ivar tz: The timezone
|
||||
@type tz: L{Timezone}
|
||||
@ivar date: The object value.
|
||||
@type date: B{datetime}.I{time}
|
||||
"""
|
||||
|
||||
def __init__(self, time, adjusted=True):
|
||||
"""
|
||||
@param time: The value of the object.
|
||||
@type time: (time|str)
|
||||
@param adjusted: Adjust for I{local} Timezone.
|
||||
@type adjusted: boolean
|
||||
@raise ValueError: When I{time} is invalid.
|
||||
"""
|
||||
self.tz = Timezone()
|
||||
if isinstance(time, dt.time):
|
||||
self.time = time
|
||||
return
|
||||
if isinstance(time, basestring):
|
||||
self.time = self.__parse(time)
|
||||
if adjusted:
|
||||
self.__adjust()
|
||||
return
|
||||
raise ValueError, type(time)
|
||||
|
||||
def hour(self):
|
||||
"""
|
||||
Get the I{hour} component.
|
||||
@return: The hour.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.time.hour
|
||||
|
||||
def minute(self):
|
||||
"""
|
||||
Get the I{minute} component.
|
||||
@return: The minute.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.time.minute
|
||||
|
||||
def second(self):
|
||||
"""
|
||||
Get the I{seconds} component.
|
||||
@return: The seconds.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.time.second
|
||||
|
||||
def microsecond(self):
|
||||
"""
|
||||
Get the I{microsecond} component.
|
||||
@return: The microsecond.
|
||||
@rtype: int
|
||||
"""
|
||||
return self.time.microsecond
|
||||
|
||||
def __adjust(self):
|
||||
"""
|
||||
Adjust for TZ offset.
|
||||
"""
|
||||
if hasattr(self, 'offset'):
|
||||
today = dt.date.today()
|
||||
delta = self.tz.adjustment(self.offset)
|
||||
d = dt.datetime.combine(today, self.time)
|
||||
d = ( d + delta )
|
||||
self.time = d.time()
|
||||
|
||||
def __parse(self, s):
|
||||
"""
|
||||
Parse the string date.
|
||||
Patterns:
|
||||
- HH:MI:SS
|
||||
- HH:MI:SS(z|Z)
|
||||
- HH:MI:SS.ms
|
||||
- HH:MI:SS.ms(z|Z)
|
||||
- HH:MI:SS(+|-)06:00
|
||||
- HH:MI:SS.ms(+|-)06:00
|
||||
@param s: A time string.
|
||||
@type s: str
|
||||
@return: A time object.
|
||||
@rtype: B{datetime}.I{time}
|
||||
"""
|
||||
try:
|
||||
offset = None
|
||||
part = Timezone.split(s)
|
||||
hour, minute, second = part[0].split(':', 2)
|
||||
hour = int(hour)
|
||||
minute = int(minute)
|
||||
second, ms = self.__second(second)
|
||||
if len(part) == 2:
|
||||
self.offset = self.__offset(part[1])
|
||||
if ms is None:
|
||||
return dt.time(hour, minute, second)
|
||||
else:
|
||||
return dt.time(hour, minute, second, ms)
|
||||
except:
|
||||
log.debug(s, exec_info=True)
|
||||
raise ValueError, 'Invalid format "%s"' % s
|
||||
|
||||
def __second(self, s):
|
||||
"""
|
||||
Parse the seconds and microseconds.
|
||||
The microseconds are truncated to 999999 due to a restriction in
|
||||
the python datetime.datetime object.
|
||||
@param s: A string representation of the seconds.
|
||||
@type s: str
|
||||
@return: Tuple of (sec,ms)
|
||||
@rtype: tuple.
|
||||
"""
|
||||
part = s.split('.')
|
||||
if len(part) > 1:
|
||||
return (int(part[0]), int(part[1][:6]))
|
||||
else:
|
||||
return (int(part[0]), None)
|
||||
|
||||
def __offset(self, s):
|
||||
"""
|
||||
Parse the TZ offset.
|
||||
@param s: A string representation of the TZ offset.
|
||||
@type s: str
|
||||
@return: The signed offset in hours.
|
||||
@rtype: str
|
||||
"""
|
||||
if len(s) == len('-00:00'):
|
||||
return int(s[:3])
|
||||
if len(s) == 0:
|
||||
return self.tz.local
|
||||
if len(s) == 1:
|
||||
return 0
|
||||
raise Exception()
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self)
|
||||
|
||||
def __unicode__(self):
|
||||
time = self.time.isoformat()
|
||||
if self.tz.local:
|
||||
return '%s%+.2d:00' % (time, self.tz.local)
|
||||
else:
|
||||
return '%sZ' % time
|
||||
|
||||
|
||||
class DateTime(Date,Time):
|
||||
"""
|
||||
An XML time object.
|
||||
Supported formats:
|
||||
- YYYY-MM-DDB{T}HH:MI:SS
|
||||
- YYYY-MM-DDB{T}HH:MI:SS(z|Z)
|
||||
- YYYY-MM-DDB{T}HH:MI:SS.ms
|
||||
- YYYY-MM-DDB{T}HH:MI:SS.ms(z|Z)
|
||||
- YYYY-MM-DDB{T}HH:MI:SS(+|-)06:00
|
||||
- YYYY-MM-DDB{T}HH:MI:SS.ms(+|-)06:00
|
||||
@ivar datetime: The object value.
|
||||
@type datetime: B{datetime}.I{datedate}
|
||||
"""
|
||||
def __init__(self, date):
|
||||
"""
|
||||
@param date: The value of the object.
|
||||
@type date: (datetime|str)
|
||||
@raise ValueError: When I{tm} is invalid.
|
||||
"""
|
||||
if isinstance(date, dt.datetime):
|
||||
Date.__init__(self, date.date())
|
||||
Time.__init__(self, date.time())
|
||||
self.datetime = \
|
||||
dt.datetime.combine(self.date, self.time)
|
||||
return
|
||||
if isinstance(date, basestring):
|
||||
part = date.split('T')
|
||||
Date.__init__(self, part[0])
|
||||
Time.__init__(self, part[1], 0)
|
||||
self.datetime = \
|
||||
dt.datetime.combine(self.date, self.time)
|
||||
self.__adjust()
|
||||
return
|
||||
raise ValueError, type(date)
|
||||
|
||||
def __adjust(self):
|
||||
"""
|
||||
Adjust for TZ offset.
|
||||
"""
|
||||
if not hasattr(self, 'offset'):
|
||||
return
|
||||
delta = self.tz.adjustment(self.offset)
|
||||
try:
|
||||
d = ( self.datetime + delta )
|
||||
self.datetime = d
|
||||
self.date = d.date()
|
||||
self.time = d.time()
|
||||
except OverflowError:
|
||||
log.warn('"%s" caused overflow, not-adjusted', self.datetime)
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self)
|
||||
|
||||
def __unicode__(self):
|
||||
s = []
|
||||
s.append(Date.__unicode__(self))
|
||||
s.append(Time.__unicode__(self))
|
||||
return 'T'.join(s)
|
||||
|
||||
|
||||
class UTC(DateTime):
|
||||
"""
|
||||
Represents current UTC time.
|
||||
"""
|
||||
|
||||
def __init__(self, date=None):
|
||||
if date is None:
|
||||
date = dt.datetime.utcnow()
|
||||
DateTime.__init__(self, date)
|
||||
self.tz.local = 0
|
||||
|
||||
|
||||
class Timezone:
|
||||
"""
|
||||
Timezone object used to do TZ conversions
|
||||
@cvar local: The (A) local TZ offset.
|
||||
@type local: int
|
||||
@cvar patten: The regex patten to match TZ.
|
||||
@type patten: re.Pattern
|
||||
"""
|
||||
|
||||
pattern = re.compile('([zZ])|([\-\+][0-9]{2}:[0-9]{2})')
|
||||
|
||||
LOCAL = ( 0-time.timezone/60/60 )
|
||||
|
||||
def __init__(self, offset=None):
|
||||
if offset is None:
|
||||
offset = self.LOCAL
|
||||
self.local = offset
|
||||
|
||||
@classmethod
|
||||
def split(cls, s):
|
||||
"""
|
||||
Split the TZ from string.
|
||||
@param s: A string containing a timezone
|
||||
@type s: basestring
|
||||
@return: The split parts.
|
||||
@rtype: tuple
|
||||
"""
|
||||
m = cls.pattern.search(s)
|
||||
if m is None:
|
||||
return (s,)
|
||||
x = m.start(0)
|
||||
return (s[:x], s[x:])
|
||||
|
||||
def adjustment(self, offset):
|
||||
"""
|
||||
Get the adjustment to the I{local} TZ.
|
||||
@return: The delta between I{offset} and local TZ.
|
||||
@rtype: B{datetime}.I{timedelta}
|
||||
"""
|
||||
delta = ( self.local - offset )
|
||||
return dt.timedelta(hours=delta)
|
||||
61
awx/lib/site-packages/suds/sax/document.py
Normal file
61
awx/lib/site-packages/suds/sax/document.py
Normal file
@ -0,0 +1,61 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides XML I{document} classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sax import *
|
||||
from suds.sax.element import Element
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
class Document(Element):
|
||||
""" simple document """
|
||||
|
||||
DECL = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
|
||||
def __init__(self, root=None):
|
||||
Element.__init__(self, 'document')
|
||||
if root is not None:
|
||||
self.append(root)
|
||||
|
||||
def root(self):
|
||||
if len(self.children):
|
||||
return self.children[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def str(self):
|
||||
s = []
|
||||
s.append(self.DECL)
|
||||
s.append('\n')
|
||||
s.append(self.root().str())
|
||||
return ''.join(s)
|
||||
|
||||
def plain(self):
|
||||
s = []
|
||||
s.append(self.DECL)
|
||||
s.append(self.root().plain())
|
||||
return ''.join(s)
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.str()
|
||||
1147
awx/lib/site-packages/suds/sax/element.py
Normal file
1147
awx/lib/site-packages/suds/sax/element.py
Normal file
File diff suppressed because it is too large
Load Diff
79
awx/lib/site-packages/suds/sax/enc.py
Normal file
79
awx/lib/site-packages/suds/sax/enc.py
Normal file
@ -0,0 +1,79 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides XML I{special character} encoder classes.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
class Encoder:
|
||||
"""
|
||||
An XML special character encoder/decoder.
|
||||
@cvar encodings: A mapping of special characters encoding.
|
||||
@type encodings: [(str,str)]
|
||||
@cvar decodings: A mapping of special characters decoding.
|
||||
@type decodings: [(str,str)]
|
||||
@cvar special: A list of special characters
|
||||
@type special: [char]
|
||||
"""
|
||||
|
||||
encodings = \
|
||||
(( '&(?!(amp|lt|gt|quot|apos);)', '&' ),( '<', '<' ),( '>', '>' ),( '"', '"' ),("'", ''' ))
|
||||
decodings = \
|
||||
(( '<', '<' ),( '>', '>' ),( '"', '"' ),( ''', "'" ),( '&', '&' ))
|
||||
special = \
|
||||
('&', '<', '>', '"', "'")
|
||||
|
||||
def needsEncoding(self, s):
|
||||
"""
|
||||
Get whether string I{s} contains special characters.
|
||||
@param s: A string to check.
|
||||
@type s: str
|
||||
@return: True if needs encoding.
|
||||
@rtype: boolean
|
||||
"""
|
||||
if isinstance(s, basestring):
|
||||
for c in self.special:
|
||||
if c in s:
|
||||
return True
|
||||
return False
|
||||
|
||||
def encode(self, s):
|
||||
"""
|
||||
Encode special characters found in string I{s}.
|
||||
@param s: A string to encode.
|
||||
@type s: str
|
||||
@return: The encoded string.
|
||||
@rtype: str
|
||||
"""
|
||||
if isinstance(s, basestring) and self.needsEncoding(s):
|
||||
for x in self.encodings:
|
||||
s = re.sub(x[0], x[1], s)
|
||||
return s
|
||||
|
||||
def decode(self, s):
|
||||
"""
|
||||
Decode special characters encodings found in string I{s}.
|
||||
@param s: A string to decode.
|
||||
@type s: str
|
||||
@return: The decoded string.
|
||||
@rtype: str
|
||||
"""
|
||||
if isinstance(s, basestring) and '&' in s:
|
||||
for x in self.decodings:
|
||||
s = s.replace(x[0], x[1])
|
||||
return s
|
||||
139
awx/lib/site-packages/suds/sax/parser.py
Normal file
139
awx/lib/site-packages/suds/sax/parser.py
Normal file
@ -0,0 +1,139 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The sax module contains a collection of classes that provide a
|
||||
(D)ocument (O)bject (M)odel representation of an XML document.
|
||||
The goal is to provide an easy, intuative interface for managing XML
|
||||
documents. Although, the term, DOM, is used above, this model is
|
||||
B{far} better.
|
||||
|
||||
XML namespaces in suds are represented using a (2) element tuple
|
||||
containing the prefix and the URI. Eg: I{('tns', 'http://myns')}
|
||||
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
import suds.metrics
|
||||
from suds import *
|
||||
from suds.sax import *
|
||||
from suds.sax.document import Document
|
||||
from suds.sax.element import Element
|
||||
from suds.sax.text import Text
|
||||
from suds.sax.attribute import Attribute
|
||||
from xml.sax import make_parser, InputSource, ContentHandler
|
||||
from xml.sax.handler import feature_external_ges
|
||||
from cStringIO import StringIO
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Handler(ContentHandler):
|
||||
""" sax hanlder """
|
||||
|
||||
def __init__(self):
|
||||
self.nodes = [Document()]
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
top = self.top()
|
||||
node = Element(unicode(name), parent=top)
|
||||
for a in attrs.getNames():
|
||||
n = unicode(a)
|
||||
v = unicode(attrs.getValue(a))
|
||||
attribute = Attribute(n,v)
|
||||
if self.mapPrefix(node, attribute):
|
||||
continue
|
||||
node.append(attribute)
|
||||
node.charbuffer = []
|
||||
top.append(node)
|
||||
self.push(node)
|
||||
|
||||
def mapPrefix(self, node, attribute):
|
||||
skip = False
|
||||
if attribute.name == 'xmlns':
|
||||
if len(attribute.value):
|
||||
node.expns = unicode(attribute.value)
|
||||
skip = True
|
||||
elif attribute.prefix == 'xmlns':
|
||||
prefix = attribute.name
|
||||
node.nsprefixes[prefix] = unicode(attribute.value)
|
||||
skip = True
|
||||
return skip
|
||||
|
||||
def endElement(self, name):
|
||||
name = unicode(name)
|
||||
current = self.top()
|
||||
if len(current.charbuffer):
|
||||
current.text = Text(u''.join(current.charbuffer))
|
||||
del current.charbuffer
|
||||
if len(current):
|
||||
current.trim()
|
||||
currentqname = current.qname()
|
||||
if name == currentqname:
|
||||
self.pop()
|
||||
else:
|
||||
raise Exception('malformed document')
|
||||
|
||||
def characters(self, content):
|
||||
text = unicode(content)
|
||||
node = self.top()
|
||||
node.charbuffer.append(text)
|
||||
|
||||
def push(self, node):
|
||||
self.nodes.append(node)
|
||||
return node
|
||||
|
||||
def pop(self):
|
||||
return self.nodes.pop()
|
||||
|
||||
def top(self):
|
||||
return self.nodes[len(self.nodes)-1]
|
||||
|
||||
|
||||
class Parser:
|
||||
""" SAX Parser """
|
||||
|
||||
@classmethod
|
||||
def saxparser(cls):
|
||||
p = make_parser()
|
||||
p.setFeature(feature_external_ges, 0)
|
||||
h = Handler()
|
||||
p.setContentHandler(h)
|
||||
return (p, h)
|
||||
|
||||
def parse(self, file=None, string=None):
|
||||
"""
|
||||
SAX parse XML text.
|
||||
@param file: Parse a python I{file-like} object.
|
||||
@type file: I{file-like} object.
|
||||
@param string: Parse string XML.
|
||||
@type string: str
|
||||
"""
|
||||
timer = metrics.Timer()
|
||||
timer.start()
|
||||
sax, handler = self.saxparser()
|
||||
if file is not None:
|
||||
sax.parse(file)
|
||||
timer.stop()
|
||||
metrics.log.debug('sax (%s) duration: %s', file, timer)
|
||||
return handler.nodes[0]
|
||||
if string is not None:
|
||||
source = InputSource(None)
|
||||
source.setByteStream(StringIO(string))
|
||||
sax.parse(source)
|
||||
timer.stop()
|
||||
metrics.log.debug('%s\nsax duration: %s', string, timer)
|
||||
return handler.nodes[0]
|
||||
116
awx/lib/site-packages/suds/sax/text.py
Normal file
116
awx/lib/site-packages/suds/sax/text.py
Normal file
@ -0,0 +1,116 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains XML text classes.
|
||||
"""
|
||||
|
||||
from suds import *
|
||||
from suds.sax import *
|
||||
|
||||
|
||||
class Text(unicode):
|
||||
"""
|
||||
An XML text object used to represent text content.
|
||||
@ivar lang: The (optional) language flag.
|
||||
@type lang: bool
|
||||
@ivar escaped: The (optional) XML special character escaped flag.
|
||||
@type escaped: bool
|
||||
"""
|
||||
__slots__ = ('lang', 'escaped',)
|
||||
|
||||
@classmethod
|
||||
def __valid(cls, *args):
|
||||
return ( len(args) and args[0] is not None )
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls.__valid(*args):
|
||||
lang = kwargs.pop('lang', None)
|
||||
escaped = kwargs.pop('escaped', False)
|
||||
result = super(Text, cls).__new__(cls, *args, **kwargs)
|
||||
result.lang = lang
|
||||
result.escaped = escaped
|
||||
else:
|
||||
result = None
|
||||
return result
|
||||
|
||||
def escape(self):
|
||||
"""
|
||||
Encode (escape) special XML characters.
|
||||
@return: The text with XML special characters escaped.
|
||||
@rtype: L{Text}
|
||||
"""
|
||||
if not self.escaped:
|
||||
post = sax.encoder.encode(self)
|
||||
escaped = ( post != self )
|
||||
return Text(post, lang=self.lang, escaped=escaped)
|
||||
return self
|
||||
|
||||
def unescape(self):
|
||||
"""
|
||||
Decode (unescape) special XML characters.
|
||||
@return: The text with escaped XML special characters decoded.
|
||||
@rtype: L{Text}
|
||||
"""
|
||||
if self.escaped:
|
||||
post = sax.encoder.decode(self)
|
||||
return Text(post, lang=self.lang)
|
||||
return self
|
||||
|
||||
def trim(self):
|
||||
post = self.strip()
|
||||
return Text(post, lang=self.lang, escaped=self.escaped)
|
||||
|
||||
def __add__(self, other):
|
||||
joined = u''.join((self, other))
|
||||
result = Text(joined, lang=self.lang, escaped=self.escaped)
|
||||
if isinstance(other, Text):
|
||||
result.escaped = ( self.escaped or other.escaped )
|
||||
return result
|
||||
|
||||
def __repr__(self):
|
||||
s = [self]
|
||||
if self.lang is not None:
|
||||
s.append(' [%s]' % self.lang)
|
||||
if self.escaped:
|
||||
s.append(' <escaped>')
|
||||
return ''.join(s)
|
||||
|
||||
def __getstate__(self):
|
||||
state = {}
|
||||
for k in self.__slots__:
|
||||
state[k] = getattr(self, k)
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
for k in self.__slots__:
|
||||
setattr(self, k, state[k])
|
||||
|
||||
|
||||
class Raw(Text):
|
||||
"""
|
||||
Raw text which is not XML escaped.
|
||||
This may include I{string} XML.
|
||||
"""
|
||||
def escape(self):
|
||||
return self
|
||||
|
||||
def unescape(self):
|
||||
return self
|
||||
|
||||
def __add__(self, other):
|
||||
joined = u''.join((self, other))
|
||||
return Raw(joined, lang=self.lang)
|
||||
248
awx/lib/site-packages/suds/servicedefinition.py
Normal file
248
awx/lib/site-packages/suds/servicedefinition.py
Normal file
@ -0,0 +1,248 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{service definition} provides a textual representation of a service.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
import suds.metrics as metrics
|
||||
from suds.sax import Namespace
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
class ServiceDefinition:
|
||||
"""
|
||||
A service definition provides an object used to generate a textual description
|
||||
of a service.
|
||||
@ivar wsdl: A wsdl.
|
||||
@type wsdl: L{wsdl.Definitions}
|
||||
@ivar service: The service object.
|
||||
@type service: L{suds.wsdl.Service}
|
||||
@ivar ports: A list of port-tuple: (port, [(method-name, pdef)])
|
||||
@type ports: [port-tuple,..]
|
||||
@ivar prefixes: A list of remapped prefixes.
|
||||
@type prefixes: [(prefix,uri),..]
|
||||
@ivar types: A list of type definitions
|
||||
@type types: [I{Type},..]
|
||||
"""
|
||||
|
||||
def __init__(self, wsdl, service):
|
||||
"""
|
||||
@param wsdl: A wsdl object
|
||||
@type wsdl: L{Definitions}
|
||||
@param service: A service B{name}.
|
||||
@type service: str
|
||||
"""
|
||||
self.wsdl = wsdl
|
||||
self.service = service
|
||||
self.ports = []
|
||||
self.params = []
|
||||
self.types = []
|
||||
self.prefixes = []
|
||||
self.addports()
|
||||
self.paramtypes()
|
||||
self.publictypes()
|
||||
self.getprefixes()
|
||||
self.pushprefixes()
|
||||
|
||||
def pushprefixes(self):
|
||||
"""
|
||||
Add our prefixes to the wsdl so that when users invoke methods
|
||||
and reference the prefixes, the will resolve properly.
|
||||
"""
|
||||
for ns in self.prefixes:
|
||||
self.wsdl.root.addPrefix(ns[0], ns[1])
|
||||
|
||||
def addports(self):
|
||||
"""
|
||||
Look through the list of service ports and construct a list of tuples where
|
||||
each tuple is used to describe a port and it's list of methods as:
|
||||
(port, [method]). Each method is tuple: (name, [pdef,..] where each pdef is
|
||||
a tuple: (param-name, type).
|
||||
"""
|
||||
timer = metrics.Timer()
|
||||
timer.start()
|
||||
for port in self.service.ports:
|
||||
p = self.findport(port)
|
||||
for op in port.binding.operations.values():
|
||||
m = p[0].method(op.name)
|
||||
binding = m.binding.input
|
||||
method = (m.name, binding.param_defs(m))
|
||||
p[1].append(method)
|
||||
metrics.log.debug("method '%s' created: %s", m.name, timer)
|
||||
p[1].sort()
|
||||
timer.stop()
|
||||
|
||||
def findport(self, port):
|
||||
"""
|
||||
Find and return a port tuple for the specified port.
|
||||
Created and added when not found.
|
||||
@param port: A port.
|
||||
@type port: I{service.Port}
|
||||
@return: A port tuple.
|
||||
@rtype: (port, [method])
|
||||
"""
|
||||
for p in self.ports:
|
||||
if p[0] == p: return p
|
||||
p = (port, [])
|
||||
self.ports.append(p)
|
||||
return p
|
||||
|
||||
def getprefixes(self):
|
||||
"""
|
||||
Add prefixes foreach namespace referenced by parameter types.
|
||||
"""
|
||||
namespaces = []
|
||||
for l in (self.params, self.types):
|
||||
for t,r in l:
|
||||
ns = r.namespace()
|
||||
if ns[1] is None: continue
|
||||
if ns[1] in namespaces: continue
|
||||
if Namespace.xs(ns) or Namespace.xsd(ns):
|
||||
continue
|
||||
namespaces.append(ns[1])
|
||||
if t == r: continue
|
||||
ns = t.namespace()
|
||||
if ns[1] is None: continue
|
||||
if ns[1] in namespaces: continue
|
||||
namespaces.append(ns[1])
|
||||
i = 0
|
||||
namespaces.sort()
|
||||
for u in namespaces:
|
||||
p = self.nextprefix()
|
||||
ns = (p, u)
|
||||
self.prefixes.append(ns)
|
||||
|
||||
def paramtypes(self):
|
||||
""" get all parameter types """
|
||||
for m in [p[1] for p in self.ports]:
|
||||
for p in [p[1] for p in m]:
|
||||
for pd in p:
|
||||
if pd[1] in self.params: continue
|
||||
item = (pd[1], pd[1].resolve())
|
||||
self.params.append(item)
|
||||
|
||||
def publictypes(self):
|
||||
""" get all public types """
|
||||
for t in self.wsdl.schema.types.values():
|
||||
if t in self.params: continue
|
||||
if t in self.types: continue
|
||||
item = (t, t)
|
||||
self.types.append(item)
|
||||
tc = lambda x,y: cmp(x[0].name, y[0].name)
|
||||
self.types.sort(cmp=tc)
|
||||
|
||||
def nextprefix(self):
|
||||
"""
|
||||
Get the next available prefix. This means a prefix starting with 'ns' with
|
||||
a number appended as (ns0, ns1, ..) that is not already defined on the
|
||||
wsdl document.
|
||||
"""
|
||||
used = [ns[0] for ns in self.prefixes]
|
||||
used += [ns[0] for ns in self.wsdl.root.nsprefixes.items()]
|
||||
for n in range(0,1024):
|
||||
p = 'ns%d'%n
|
||||
if p not in used:
|
||||
return p
|
||||
raise Exception('prefixes exhausted')
|
||||
|
||||
def getprefix(self, u):
|
||||
"""
|
||||
Get the prefix for the specified namespace (uri)
|
||||
@param u: A namespace uri.
|
||||
@type u: str
|
||||
@return: The namspace.
|
||||
@rtype: (prefix, uri).
|
||||
"""
|
||||
for ns in Namespace.all:
|
||||
if u == ns[1]: return ns[0]
|
||||
for ns in self.prefixes:
|
||||
if u == ns[1]: return ns[0]
|
||||
raise Exception('ns (%s) not mapped' % u)
|
||||
|
||||
def xlate(self, type):
|
||||
"""
|
||||
Get a (namespace) translated I{qualified} name for specified type.
|
||||
@param type: A schema type.
|
||||
@type type: I{suds.xsd.sxbasic.SchemaObject}
|
||||
@return: A translated I{qualified} name.
|
||||
@rtype: str
|
||||
"""
|
||||
resolved = type.resolve()
|
||||
name = resolved.name
|
||||
if type.unbounded():
|
||||
name += '[]'
|
||||
ns = resolved.namespace()
|
||||
if ns[1] == self.wsdl.tns[1]:
|
||||
return name
|
||||
prefix = self.getprefix(ns[1])
|
||||
return ':'.join((prefix, name))
|
||||
|
||||
def description(self):
|
||||
"""
|
||||
Get a textual description of the service for which this object represents.
|
||||
@return: A textual description.
|
||||
@rtype: str
|
||||
"""
|
||||
s = []
|
||||
indent = (lambda n : '\n%*s'%(n*3,' '))
|
||||
s.append('Service ( %s ) tns="%s"' % (self.service.name, self.wsdl.tns[1]))
|
||||
s.append(indent(1))
|
||||
s.append('Prefixes (%d)' % len(self.prefixes))
|
||||
for p in self.prefixes:
|
||||
s.append(indent(2))
|
||||
s.append('%s = "%s"' % p)
|
||||
s.append(indent(1))
|
||||
s.append('Ports (%d):' % len(self.ports))
|
||||
for p in self.ports:
|
||||
s.append(indent(2))
|
||||
s.append('(%s)' % p[0].name)
|
||||
s.append(indent(3))
|
||||
s.append('Methods (%d):' % len(p[1]))
|
||||
for m in p[1]:
|
||||
sig = []
|
||||
s.append(indent(4))
|
||||
sig.append(m[0])
|
||||
sig.append('(')
|
||||
for p in m[1]:
|
||||
sig.append(self.xlate(p[1]))
|
||||
sig.append(' ')
|
||||
sig.append(p[0])
|
||||
sig.append(', ')
|
||||
sig.append(')')
|
||||
try:
|
||||
s.append(''.join(sig))
|
||||
except:
|
||||
pass
|
||||
s.append(indent(3))
|
||||
s.append('Types (%d):' % len(self.types))
|
||||
for t in self.types:
|
||||
s.append(indent(4))
|
||||
s.append(self.xlate(t[0]))
|
||||
s.append('\n\n')
|
||||
return ''.join(s)
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
try:
|
||||
return self.description()
|
||||
except Exception, e:
|
||||
log.exception(e)
|
||||
return tostr(e)
|
||||
86
awx/lib/site-packages/suds/serviceproxy.py
Normal file
86
awx/lib/site-packages/suds/serviceproxy.py
Normal file
@ -0,0 +1,86 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The service proxy provides access to web services.
|
||||
|
||||
Replaced by: L{client.Client}
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.client import Client
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class ServiceProxy(object):
|
||||
|
||||
"""
|
||||
A lightweight soap based web service proxy.
|
||||
@ivar __client__: A client.
|
||||
Everything is delegated to the 2nd generation API.
|
||||
@type __client__: L{Client}
|
||||
@note: Deprecated, replaced by L{Client}.
|
||||
"""
|
||||
|
||||
def __init__(self, url, **kwargs):
|
||||
"""
|
||||
@param url: The URL for the WSDL.
|
||||
@type url: str
|
||||
@param kwargs: keyword arguments.
|
||||
@keyword faults: Raise faults raised by server (default:True),
|
||||
else return tuple from service method invocation as (http code, object).
|
||||
@type faults: boolean
|
||||
@keyword proxy: An http proxy to be specified on requests (default:{}).
|
||||
The proxy is defined as {protocol:proxy,}
|
||||
@type proxy: dict
|
||||
"""
|
||||
client = Client(url, **kwargs)
|
||||
self.__client__ = client
|
||||
|
||||
def get_instance(self, name):
|
||||
"""
|
||||
Get an instance of a WSDL type by name
|
||||
@param name: The name of a type defined in the WSDL.
|
||||
@type name: str
|
||||
@return: An instance on success, else None
|
||||
@rtype: L{sudsobject.Object}
|
||||
"""
|
||||
return self.__client__.factory.create(name)
|
||||
|
||||
def get_enum(self, name):
|
||||
"""
|
||||
Get an instance of an enumeration defined in the WSDL by name.
|
||||
@param name: The name of a enumeration defined in the WSDL.
|
||||
@type name: str
|
||||
@return: An instance on success, else None
|
||||
@rtype: L{sudsobject.Object}
|
||||
"""
|
||||
return self.__client__.factory.create(name)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.__client__)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.__client__)
|
||||
|
||||
def __getattr__(self, name):
|
||||
builtin = name.startswith('__') and name.endswith('__')
|
||||
if builtin:
|
||||
return self.__dict__[name]
|
||||
else:
|
||||
return getattr(self.__client__.service, name)
|
||||
72
awx/lib/site-packages/suds/soaparray.py
Normal file
72
awx/lib/site-packages/suds/soaparray.py
Normal file
@ -0,0 +1,72 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{soaparray} module provides XSD extensions for handling
|
||||
soap (section 5) encoded arrays.
|
||||
"""
|
||||
|
||||
from suds import *
|
||||
from logging import getLogger
|
||||
from suds.xsd.sxbasic import Factory as SXFactory
|
||||
from suds.xsd.sxbasic import Attribute as SXAttribute
|
||||
|
||||
|
||||
class Attribute(SXAttribute):
|
||||
"""
|
||||
Represents an XSD <attribute/> that handles special
|
||||
attributes that are extensions for WSDLs.
|
||||
@ivar aty: Array type information.
|
||||
@type aty: The value of wsdl:arrayType.
|
||||
"""
|
||||
|
||||
def __init__(self, schema, root, aty):
|
||||
"""
|
||||
@param aty: Array type information.
|
||||
@type aty: The value of wsdl:arrayType.
|
||||
"""
|
||||
SXAttribute.__init__(self, schema, root)
|
||||
if aty.endswith('[]'):
|
||||
self.aty = aty[:-2]
|
||||
else:
|
||||
self.aty = aty
|
||||
|
||||
def autoqualified(self):
|
||||
aqs = SXAttribute.autoqualified(self)
|
||||
aqs.append('aty')
|
||||
return aqs
|
||||
|
||||
def description(self):
|
||||
d = SXAttribute.description(self)
|
||||
d = d+('aty',)
|
||||
return d
|
||||
|
||||
#
|
||||
# Builder function, only builds Attribute when arrayType
|
||||
# attribute is defined on root.
|
||||
#
|
||||
def __fn(x, y):
|
||||
ns = (None, "http://schemas.xmlsoap.org/wsdl/")
|
||||
aty = y.get('arrayType', ns=ns)
|
||||
if aty is None:
|
||||
return SXAttribute(x, y)
|
||||
else:
|
||||
return Attribute(x, y, aty)
|
||||
|
||||
#
|
||||
# Remap <xs:attrbute/> tags to __fn() builder.
|
||||
#
|
||||
SXFactory.maptag('attribute', __fn)
|
||||
594
awx/lib/site-packages/suds/store.py
Normal file
594
awx/lib/site-packages/suds/store.py
Normal file
@ -0,0 +1,594 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains XML text for documents to be distributed
|
||||
with the suds lib. Also, contains classes for accessing
|
||||
these documents.
|
||||
"""
|
||||
|
||||
from StringIO import StringIO
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
#
|
||||
# Soap section 5 encoding schema.
|
||||
#
|
||||
encoding = \
|
||||
"""<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://schemas.xmlsoap.org/soap/encoding/">
|
||||
|
||||
<xs:attribute name="root">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
'root' can be used to distinguish serialization roots from other
|
||||
elements that are present in a serialization but are not roots of
|
||||
a serialized value graph
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:boolean">
|
||||
<xs:pattern value="0|1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attributeGroup name="commonAttributes">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Attributes common to all elements that function as accessors or
|
||||
represent independent (multi-ref) values. The href attribute is
|
||||
intended to be used in a manner like CONREF. That is, the element
|
||||
content should be empty iff the href attribute appears
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="id" type="xs:ID"/>
|
||||
<xs:attribute name="href" type="xs:anyURI"/>
|
||||
<xs:anyAttribute namespace="##other" processContents="lax"/>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<!-- Global Attributes. The following attributes are intended to be usable via qualified attribute names on any complex type referencing them. -->
|
||||
|
||||
<!-- Array attributes. Needed to give the type and dimensions of an array's contents, and the offset for partially-transmitted arrays. -->
|
||||
|
||||
<xs:simpleType name="arrayCoordinate">
|
||||
<xs:restriction base="xs:string"/>
|
||||
</xs:simpleType>
|
||||
|
||||
<xs:attribute name="arrayType" type="xs:string"/>
|
||||
<xs:attribute name="offset" type="tns:arrayCoordinate"/>
|
||||
|
||||
<xs:attributeGroup name="arrayAttributes">
|
||||
<xs:attribute ref="tns:arrayType"/>
|
||||
<xs:attribute ref="tns:offset"/>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:attribute name="position" type="tns:arrayCoordinate"/>
|
||||
|
||||
<xs:attributeGroup name="arrayMemberAttributes">
|
||||
<xs:attribute ref="tns:position"/>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:group name="Array">
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
|
||||
</xs:sequence>
|
||||
</xs:group>
|
||||
|
||||
<xs:element name="Array" type="tns:Array"/>
|
||||
<xs:complexType name="Array">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
'Array' is a complex type for accessors identified by position
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:group ref="tns:Array" minOccurs="0"/>
|
||||
<xs:attributeGroup ref="tns:arrayAttributes"/>
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- 'Struct' is a complex type for accessors identified by name.
|
||||
Constraint: No element may be have the same name as any other,
|
||||
nor may any element have a maxOccurs > 1. -->
|
||||
|
||||
<xs:element name="Struct" type="tns:Struct"/>
|
||||
|
||||
<xs:group name="Struct">
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
|
||||
</xs:sequence>
|
||||
</xs:group>
|
||||
|
||||
<xs:complexType name="Struct">
|
||||
<xs:group ref="tns:Struct" minOccurs="0"/>
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- 'Base64' can be used to serialize binary data using base64 encoding
|
||||
as defined in RFC2045 but without the MIME line length limitation. -->
|
||||
|
||||
<xs:simpleType name="base64">
|
||||
<xs:restriction base="xs:base64Binary"/>
|
||||
</xs:simpleType>
|
||||
|
||||
<!-- Element declarations corresponding to each of the simple types in the
|
||||
XML Schemas Specification. -->
|
||||
|
||||
<xs:element name="duration" type="tns:duration"/>
|
||||
<xs:complexType name="duration">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:duration">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="dateTime" type="tns:dateTime"/>
|
||||
<xs:complexType name="dateTime">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:dateTime">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
|
||||
<xs:element name="NOTATION" type="tns:NOTATION"/>
|
||||
<xs:complexType name="NOTATION">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:QName">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
<xs:element name="time" type="tns:time"/>
|
||||
<xs:complexType name="time">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:time">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="date" type="tns:date"/>
|
||||
<xs:complexType name="date">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:date">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="gYearMonth" type="tns:gYearMonth"/>
|
||||
<xs:complexType name="gYearMonth">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:gYearMonth">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="gYear" type="tns:gYear"/>
|
||||
<xs:complexType name="gYear">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:gYear">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="gMonthDay" type="tns:gMonthDay"/>
|
||||
<xs:complexType name="gMonthDay">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:gMonthDay">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="gDay" type="tns:gDay"/>
|
||||
<xs:complexType name="gDay">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:gDay">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="gMonth" type="tns:gMonth"/>
|
||||
<xs:complexType name="gMonth">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:gMonth">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="boolean" type="tns:boolean"/>
|
||||
<xs:complexType name="boolean">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:boolean">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="base64Binary" type="tns:base64Binary"/>
|
||||
<xs:complexType name="base64Binary">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:base64Binary">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="hexBinary" type="tns:hexBinary"/>
|
||||
<xs:complexType name="hexBinary">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:hexBinary">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="float" type="tns:float"/>
|
||||
<xs:complexType name="float">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:float">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="double" type="tns:double"/>
|
||||
<xs:complexType name="double">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:double">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="anyURI" type="tns:anyURI"/>
|
||||
<xs:complexType name="anyURI">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:anyURI">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="QName" type="tns:QName"/>
|
||||
<xs:complexType name="QName">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:QName">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
<xs:element name="string" type="tns:string"/>
|
||||
<xs:complexType name="string">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="normalizedString" type="tns:normalizedString"/>
|
||||
<xs:complexType name="normalizedString">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:normalizedString">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="token" type="tns:token"/>
|
||||
<xs:complexType name="token">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:token">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="language" type="tns:language"/>
|
||||
<xs:complexType name="language">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:language">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="Name" type="tns:Name"/>
|
||||
<xs:complexType name="Name">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:Name">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="NMTOKEN" type="tns:NMTOKEN"/>
|
||||
<xs:complexType name="NMTOKEN">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:NMTOKEN">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="NCName" type="tns:NCName"/>
|
||||
<xs:complexType name="NCName">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:NCName">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="NMTOKENS" type="tns:NMTOKENS"/>
|
||||
<xs:complexType name="NMTOKENS">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:NMTOKENS">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="ID" type="tns:ID"/>
|
||||
<xs:complexType name="ID">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:ID">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="IDREF" type="tns:IDREF"/>
|
||||
<xs:complexType name="IDREF">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:IDREF">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="ENTITY" type="tns:ENTITY"/>
|
||||
<xs:complexType name="ENTITY">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:ENTITY">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="IDREFS" type="tns:IDREFS"/>
|
||||
<xs:complexType name="IDREFS">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:IDREFS">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="ENTITIES" type="tns:ENTITIES"/>
|
||||
<xs:complexType name="ENTITIES">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:ENTITIES">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="decimal" type="tns:decimal"/>
|
||||
<xs:complexType name="decimal">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:decimal">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="integer" type="tns:integer"/>
|
||||
<xs:complexType name="integer">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:integer">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="nonPositiveInteger" type="tns:nonPositiveInteger"/>
|
||||
<xs:complexType name="nonPositiveInteger">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:nonPositiveInteger">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="negativeInteger" type="tns:negativeInteger"/>
|
||||
<xs:complexType name="negativeInteger">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:negativeInteger">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="long" type="tns:long"/>
|
||||
<xs:complexType name="long">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:long">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="int" type="tns:int"/>
|
||||
<xs:complexType name="int">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:int">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="short" type="tns:short"/>
|
||||
<xs:complexType name="short">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:short">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="byte" type="tns:byte"/>
|
||||
<xs:complexType name="byte">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:byte">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="nonNegativeInteger" type="tns:nonNegativeInteger"/>
|
||||
<xs:complexType name="nonNegativeInteger">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:nonNegativeInteger">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="unsignedLong" type="tns:unsignedLong"/>
|
||||
<xs:complexType name="unsignedLong">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:unsignedLong">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="unsignedInt" type="tns:unsignedInt"/>
|
||||
<xs:complexType name="unsignedInt">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:unsignedInt">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="unsignedShort" type="tns:unsignedShort"/>
|
||||
<xs:complexType name="unsignedShort">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:unsignedShort">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="unsignedByte" type="tns:unsignedByte"/>
|
||||
<xs:complexType name="unsignedByte">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:unsignedByte">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="positiveInteger" type="tns:positiveInteger"/>
|
||||
<xs:complexType name="positiveInteger">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:positiveInteger">
|
||||
<xs:attributeGroup ref="tns:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:element name="anyType"/>
|
||||
</xs:schema>
|
||||
"""
|
||||
|
||||
|
||||
class DocumentStore:
|
||||
"""
|
||||
The I{suds} document store provides a local repository
|
||||
for xml documnts.
|
||||
@cvar protocol: The URL protocol for the store.
|
||||
@type protocol: str
|
||||
@cvar store: The mapping of URL location to documents.
|
||||
@type store: dict
|
||||
"""
|
||||
|
||||
protocol = 'suds'
|
||||
|
||||
store = {
|
||||
'schemas.xmlsoap.org/soap/encoding/' : encoding
|
||||
}
|
||||
|
||||
def open(self, url):
|
||||
"""
|
||||
Open a document at the specified url.
|
||||
@param url: A document URL.
|
||||
@type url: str
|
||||
@return: A file pointer to the document.
|
||||
@rtype: StringIO
|
||||
"""
|
||||
protocol, location = self.split(url)
|
||||
if protocol == self.protocol:
|
||||
return self.find(location)
|
||||
else:
|
||||
return None
|
||||
|
||||
def find(self, location):
|
||||
"""
|
||||
Find the specified location in the store.
|
||||
@param location: The I{location} part of a URL.
|
||||
@type location: str
|
||||
@return: An input stream to the document.
|
||||
@rtype: StringIO
|
||||
"""
|
||||
try:
|
||||
content = self.store[location]
|
||||
return StringIO(content)
|
||||
except:
|
||||
reason = 'location "%s" not in document store' % location
|
||||
raise Exception, reason
|
||||
|
||||
def split(self, url):
|
||||
"""
|
||||
Split the url into I{protocol} and I{location}
|
||||
@param url: A URL.
|
||||
@param url: str
|
||||
@return: (I{url}, I{location})
|
||||
@rtype: tuple
|
||||
"""
|
||||
parts = url.split('://', 1)
|
||||
if len(parts) == 2:
|
||||
return parts
|
||||
else:
|
||||
return (None, url)
|
||||
390
awx/lib/site-packages/suds/sudsobject.py
Normal file
390
awx/lib/site-packages/suds/sudsobject.py
Normal file
@ -0,0 +1,390 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{sudsobject} module provides a collection of suds objects
|
||||
that are primarily used for the highly dynamic interactions with
|
||||
wsdl/xsd defined types.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from new import classobj
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
def items(sobject):
|
||||
"""
|
||||
Extract the I{items} from a suds object much like the
|
||||
items() method works on I{dict}.
|
||||
@param sobject: A suds object
|
||||
@type sobject: L{Object}
|
||||
@return: A list of items contained in I{sobject}.
|
||||
@rtype: [(key, value),...]
|
||||
"""
|
||||
for item in sobject:
|
||||
yield item
|
||||
|
||||
|
||||
def asdict(sobject):
|
||||
"""
|
||||
Convert a sudsobject into a dictionary.
|
||||
@param sobject: A suds object
|
||||
@type sobject: L{Object}
|
||||
@return: A python dictionary containing the
|
||||
items contained in I{sobject}.
|
||||
@rtype: dict
|
||||
"""
|
||||
return dict(items(sobject))
|
||||
|
||||
def merge(a, b):
|
||||
"""
|
||||
Merge all attributes and metadata from I{a} to I{b}.
|
||||
@param a: A I{source} object
|
||||
@type a: L{Object}
|
||||
@param b: A I{destination} object
|
||||
@type b: L{Object}
|
||||
"""
|
||||
for item in a:
|
||||
setattr(b, item[0], item[1])
|
||||
b.__metadata__ = b.__metadata__
|
||||
return b
|
||||
|
||||
def footprint(sobject):
|
||||
"""
|
||||
Get the I{virtual footprint} of the object.
|
||||
This is really a count of the attributes in the branch with a significant value.
|
||||
@param sobject: A suds object.
|
||||
@type sobject: L{Object}
|
||||
@return: The branch footprint.
|
||||
@rtype: int
|
||||
"""
|
||||
n = 0
|
||||
for a in sobject.__keylist__:
|
||||
v = getattr(sobject, a)
|
||||
if v is None: continue
|
||||
if isinstance(v, Object):
|
||||
n += footprint(v)
|
||||
continue
|
||||
if hasattr(v, '__len__'):
|
||||
if len(v): n += 1
|
||||
continue
|
||||
n +=1
|
||||
return n
|
||||
|
||||
|
||||
class Factory:
|
||||
|
||||
cache = {}
|
||||
|
||||
@classmethod
|
||||
def subclass(cls, name, bases, dict={}):
|
||||
if not isinstance(bases, tuple):
|
||||
bases = (bases,)
|
||||
name = name.encode('utf-8')
|
||||
key = '.'.join((name, str(bases)))
|
||||
subclass = cls.cache.get(key)
|
||||
if subclass is None:
|
||||
subclass = classobj(name, bases, dict)
|
||||
cls.cache[key] = subclass
|
||||
return subclass
|
||||
|
||||
@classmethod
|
||||
def object(cls, classname=None, dict={}):
|
||||
if classname is not None:
|
||||
subclass = cls.subclass(classname, Object)
|
||||
inst = subclass()
|
||||
else:
|
||||
inst = Object()
|
||||
for a in dict.items():
|
||||
setattr(inst, a[0], a[1])
|
||||
return inst
|
||||
|
||||
@classmethod
|
||||
def metadata(cls):
|
||||
return Metadata()
|
||||
|
||||
@classmethod
|
||||
def property(cls, name, value=None):
|
||||
subclass = cls.subclass(name, Property)
|
||||
return subclass(value)
|
||||
|
||||
|
||||
class Object:
|
||||
|
||||
def __init__(self):
|
||||
self.__keylist__ = []
|
||||
self.__printer__ = Printer()
|
||||
self.__metadata__ = Metadata()
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
builtin = name.startswith('__') and name.endswith('__')
|
||||
if not builtin and \
|
||||
name not in self.__keylist__:
|
||||
self.__keylist__.append(name)
|
||||
self.__dict__[name] = value
|
||||
|
||||
def __delattr__(self, name):
|
||||
try:
|
||||
del self.__dict__[name]
|
||||
builtin = name.startswith('__') and name.endswith('__')
|
||||
if not builtin:
|
||||
self.__keylist__.remove(name)
|
||||
except:
|
||||
cls = self.__class__.__name__
|
||||
raise AttributeError, "%s has no attribute '%s'" % (cls, name)
|
||||
|
||||
def __getitem__(self, name):
|
||||
if isinstance(name, int):
|
||||
name = self.__keylist__[int(name)]
|
||||
return getattr(self, name)
|
||||
|
||||
def __setitem__(self, name, value):
|
||||
setattr(self, name, value)
|
||||
|
||||
def __iter__(self):
|
||||
return Iter(self)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.__keylist__)
|
||||
|
||||
def __contains__(self, name):
|
||||
return name in self.__keylist__
|
||||
|
||||
def __repr__(self):
|
||||
return str(self)
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.__printer__.tostr(self)
|
||||
|
||||
|
||||
class Iter:
|
||||
|
||||
def __init__(self, sobject):
|
||||
self.sobject = sobject
|
||||
self.keylist = self.__keylist(sobject)
|
||||
self.index = 0
|
||||
|
||||
def next(self):
|
||||
keylist = self.keylist
|
||||
nkeys = len(self.keylist)
|
||||
while self.index < nkeys:
|
||||
k = keylist[self.index]
|
||||
self.index += 1
|
||||
if hasattr(self.sobject, k):
|
||||
v = getattr(self.sobject, k)
|
||||
return (k, v)
|
||||
raise StopIteration()
|
||||
|
||||
def __keylist(self, sobject):
|
||||
keylist = sobject.__keylist__
|
||||
try:
|
||||
keyset = set(keylist)
|
||||
ordering = sobject.__metadata__.ordering
|
||||
ordered = set(ordering)
|
||||
if not ordered.issuperset(keyset):
|
||||
log.debug(
|
||||
'%s must be superset of %s, ordering ignored',
|
||||
keylist,
|
||||
ordering)
|
||||
raise KeyError()
|
||||
return ordering
|
||||
except:
|
||||
return keylist
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
|
||||
class Metadata(Object):
|
||||
def __init__(self):
|
||||
self.__keylist__ = []
|
||||
self.__printer__ = Printer()
|
||||
|
||||
|
||||
class Facade(Object):
|
||||
def __init__(self, name):
|
||||
Object.__init__(self)
|
||||
md = self.__metadata__
|
||||
md.facade = name
|
||||
|
||||
|
||||
class Property(Object):
|
||||
|
||||
def __init__(self, value):
|
||||
Object.__init__(self)
|
||||
self.value = value
|
||||
|
||||
def items(self):
|
||||
for item in self:
|
||||
if item[0] != 'value':
|
||||
yield item
|
||||
|
||||
def get(self):
|
||||
return self.value
|
||||
|
||||
def set(self, value):
|
||||
self.value = value
|
||||
return self
|
||||
|
||||
|
||||
class Printer:
|
||||
"""
|
||||
Pretty printing of a Object object.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def indent(cls, n): return '%*s'%(n*3,' ')
|
||||
|
||||
def tostr(self, object, indent=-2):
|
||||
""" get s string representation of object """
|
||||
history = []
|
||||
return self.process(object, history, indent)
|
||||
|
||||
def process(self, object, h, n=0, nl=False):
|
||||
""" print object using the specified indent (n) and newline (nl). """
|
||||
if object is None:
|
||||
return 'None'
|
||||
if isinstance(object, Object):
|
||||
if len(object) == 0:
|
||||
return '<empty>'
|
||||
else:
|
||||
return self.print_object(object, h, n+2, nl)
|
||||
if isinstance(object, dict):
|
||||
if len(object) == 0:
|
||||
return '<empty>'
|
||||
else:
|
||||
return self.print_dictionary(object, h, n+2, nl)
|
||||
if isinstance(object, (list,tuple)):
|
||||
if len(object) == 0:
|
||||
return '<empty>'
|
||||
else:
|
||||
return self.print_collection(object, h, n+2)
|
||||
if isinstance(object, basestring):
|
||||
return '"%s"' % tostr(object)
|
||||
return '%s' % tostr(object)
|
||||
|
||||
def print_object(self, d, h, n, nl=False):
|
||||
""" print complex using the specified indent (n) and newline (nl). """
|
||||
s = []
|
||||
cls = d.__class__
|
||||
md = d.__metadata__
|
||||
if d in h:
|
||||
s.append('(')
|
||||
s.append(cls.__name__)
|
||||
s.append(')')
|
||||
s.append('...')
|
||||
return ''.join(s)
|
||||
h.append(d)
|
||||
if nl:
|
||||
s.append('\n')
|
||||
s.append(self.indent(n))
|
||||
if cls != Object:
|
||||
s.append('(')
|
||||
if isinstance(d, Facade):
|
||||
s.append(md.facade)
|
||||
else:
|
||||
s.append(cls.__name__)
|
||||
s.append(')')
|
||||
s.append('{')
|
||||
for item in d:
|
||||
if self.exclude(d, item):
|
||||
continue
|
||||
item = self.unwrap(d, item)
|
||||
s.append('\n')
|
||||
s.append(self.indent(n+1))
|
||||
if isinstance(item[1], (list,tuple)):
|
||||
s.append(item[0])
|
||||
s.append('[]')
|
||||
else:
|
||||
s.append(item[0])
|
||||
s.append(' = ')
|
||||
s.append(self.process(item[1], h, n, True))
|
||||
s.append('\n')
|
||||
s.append(self.indent(n))
|
||||
s.append('}')
|
||||
h.pop()
|
||||
return ''.join(s)
|
||||
|
||||
def print_dictionary(self, d, h, n, nl=False):
|
||||
""" print complex using the specified indent (n) and newline (nl). """
|
||||
if d in h: return '{}...'
|
||||
h.append(d)
|
||||
s = []
|
||||
if nl:
|
||||
s.append('\n')
|
||||
s.append(self.indent(n))
|
||||
s.append('{')
|
||||
for item in d.items():
|
||||
s.append('\n')
|
||||
s.append(self.indent(n+1))
|
||||
if isinstance(item[1], (list,tuple)):
|
||||
s.append(tostr(item[0]))
|
||||
s.append('[]')
|
||||
else:
|
||||
s.append(tostr(item[0]))
|
||||
s.append(' = ')
|
||||
s.append(self.process(item[1], h, n, True))
|
||||
s.append('\n')
|
||||
s.append(self.indent(n))
|
||||
s.append('}')
|
||||
h.pop()
|
||||
return ''.join(s)
|
||||
|
||||
def print_collection(self, c, h, n):
|
||||
""" print collection using the specified indent (n) and newline (nl). """
|
||||
if c in h: return '[]...'
|
||||
h.append(c)
|
||||
s = []
|
||||
for item in c:
|
||||
s.append('\n')
|
||||
s.append(self.indent(n))
|
||||
s.append(self.process(item, h, n-2))
|
||||
s.append(',')
|
||||
h.pop()
|
||||
return ''.join(s)
|
||||
|
||||
def unwrap(self, d, item):
|
||||
""" translate (unwrap) using an optional wrapper function """
|
||||
nopt = ( lambda x: x )
|
||||
try:
|
||||
md = d.__metadata__
|
||||
pmd = getattr(md, '__print__', None)
|
||||
if pmd is None:
|
||||
return item
|
||||
wrappers = getattr(pmd, 'wrappers', {})
|
||||
fn = wrappers.get(item[0], nopt)
|
||||
return (item[0], fn(item[1]))
|
||||
except:
|
||||
pass
|
||||
return item
|
||||
|
||||
def exclude(self, d, item):
|
||||
""" check metadata for excluded items """
|
||||
try:
|
||||
md = d.__metadata__
|
||||
pmd = getattr(md, '__print__', None)
|
||||
if pmd is None:
|
||||
return False
|
||||
excludes = getattr(pmd, 'excludes', [])
|
||||
return ( item[0] in excludes )
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
130
awx/lib/site-packages/suds/transport/__init__.py
Normal file
130
awx/lib/site-packages/suds/transport/__init__.py
Normal file
@ -0,0 +1,130 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains transport interface (classes).
|
||||
"""
|
||||
|
||||
|
||||
class TransportError(Exception):
|
||||
def __init__(self, reason, httpcode, fp=None):
|
||||
Exception.__init__(self, reason)
|
||||
self.httpcode = httpcode
|
||||
self.fp = fp
|
||||
|
||||
class Request:
|
||||
"""
|
||||
A transport request
|
||||
@ivar url: The url for the request.
|
||||
@type url: str
|
||||
@ivar message: The message to be sent in a POST request.
|
||||
@type message: str
|
||||
@ivar headers: The http headers to be used for the request.
|
||||
@type headers: dict
|
||||
"""
|
||||
|
||||
def __init__(self, url, message=None):
|
||||
"""
|
||||
@param url: The url for the request.
|
||||
@type url: str
|
||||
@param message: The (optional) message to be send in the request.
|
||||
@type message: str
|
||||
"""
|
||||
self.url = url
|
||||
self.headers = {}
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
s = []
|
||||
s.append('URL:%s' % self.url)
|
||||
s.append('HEADERS: %s' % self.headers)
|
||||
s.append('MESSAGE:')
|
||||
s.append(self.message)
|
||||
return '\n'.join(s)
|
||||
|
||||
|
||||
class Reply:
|
||||
"""
|
||||
A transport reply
|
||||
@ivar code: The http code returned.
|
||||
@type code: int
|
||||
@ivar message: The message to be sent in a POST request.
|
||||
@type message: str
|
||||
@ivar headers: The http headers to be used for the request.
|
||||
@type headers: dict
|
||||
"""
|
||||
|
||||
def __init__(self, code, headers, message):
|
||||
"""
|
||||
@param code: The http code returned.
|
||||
@type code: int
|
||||
@param headers: The http returned headers.
|
||||
@type headers: dict
|
||||
@param message: The (optional) reply message received.
|
||||
@type message: str
|
||||
"""
|
||||
self.code = code
|
||||
self.headers = headers
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
s = []
|
||||
s.append('CODE: %s' % self.code)
|
||||
s.append('HEADERS: %s' % self.headers)
|
||||
s.append('MESSAGE:')
|
||||
s.append(self.message)
|
||||
return '\n'.join(s)
|
||||
|
||||
|
||||
class Transport:
|
||||
"""
|
||||
The transport I{interface}.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Constructor.
|
||||
"""
|
||||
from suds.transport.options import Options
|
||||
self.options = Options()
|
||||
del Options
|
||||
|
||||
def open(self, request):
|
||||
"""
|
||||
Open the url in the specified request.
|
||||
@param request: A transport request.
|
||||
@type request: L{Request}
|
||||
@return: An input stream.
|
||||
@rtype: stream
|
||||
@raise TransportError: On all transport errors.
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
|
||||
def send(self, request):
|
||||
"""
|
||||
Send soap message. Implementations are expected to handle:
|
||||
- proxies
|
||||
- I{http} headers
|
||||
- cookies
|
||||
- sending message
|
||||
- brokering exceptions into L{TransportError}
|
||||
@param request: A transport request.
|
||||
@type request: L{Request}
|
||||
@return: The reply
|
||||
@rtype: L{Reply}
|
||||
@raise TransportError: On all transport errors.
|
||||
"""
|
||||
raise Exception('not-implemented')
|
||||
187
awx/lib/site-packages/suds/transport/http.py
Normal file
187
awx/lib/site-packages/suds/transport/http.py
Normal file
@ -0,0 +1,187 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains classes for basic HTTP transport implementations.
|
||||
"""
|
||||
|
||||
import urllib2 as u2
|
||||
import base64
|
||||
import socket
|
||||
from suds.transport import *
|
||||
from suds.properties import Unskin
|
||||
from urlparse import urlparse
|
||||
from cookielib import CookieJar
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class HttpTransport(Transport):
|
||||
"""
|
||||
HTTP transport using urllib2. Provided basic http transport
|
||||
that provides for cookies, proxies but no authentication.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
@param kwargs: Keyword arguments.
|
||||
- B{proxy} - An http proxy to be specified on requests.
|
||||
The proxy is defined as {protocol:proxy,}
|
||||
- type: I{dict}
|
||||
- default: {}
|
||||
- B{timeout} - Set the url open timeout (seconds).
|
||||
- type: I{float}
|
||||
- default: 90
|
||||
"""
|
||||
Transport.__init__(self)
|
||||
Unskin(self.options).update(kwargs)
|
||||
self.cookiejar = CookieJar()
|
||||
self.proxy = {}
|
||||
self.urlopener = None
|
||||
|
||||
def open(self, request):
|
||||
try:
|
||||
url = request.url
|
||||
log.debug('opening (%s)', url)
|
||||
u2request = u2.Request(url)
|
||||
self.proxy = self.options.proxy
|
||||
return self.u2open(u2request)
|
||||
except u2.HTTPError, e:
|
||||
raise TransportError(str(e), e.code, e.fp)
|
||||
|
||||
def send(self, request):
|
||||
result = None
|
||||
url = request.url
|
||||
msg = request.message
|
||||
headers = request.headers
|
||||
try:
|
||||
u2request = u2.Request(url, msg, headers)
|
||||
self.addcookies(u2request)
|
||||
self.proxy = self.options.proxy
|
||||
request.headers.update(u2request.headers)
|
||||
log.debug('sending:\n%s', request)
|
||||
fp = self.u2open(u2request)
|
||||
self.getcookies(fp, u2request)
|
||||
result = Reply(200, fp.headers.dict, fp.read())
|
||||
log.debug('received:\n%s', result)
|
||||
except u2.HTTPError, e:
|
||||
if e.code in (202,204):
|
||||
result = None
|
||||
else:
|
||||
raise TransportError(e.msg, e.code, e.fp)
|
||||
return result
|
||||
|
||||
def addcookies(self, u2request):
|
||||
"""
|
||||
Add cookies in the cookiejar to the request.
|
||||
@param u2request: A urllib2 request.
|
||||
@rtype: u2request: urllib2.Requet.
|
||||
"""
|
||||
self.cookiejar.add_cookie_header(u2request)
|
||||
|
||||
def getcookies(self, fp, u2request):
|
||||
"""
|
||||
Add cookies in the request to the cookiejar.
|
||||
@param u2request: A urllib2 request.
|
||||
@rtype: u2request: urllib2.Requet.
|
||||
"""
|
||||
self.cookiejar.extract_cookies(fp, u2request)
|
||||
|
||||
def u2open(self, u2request):
|
||||
"""
|
||||
Open a connection.
|
||||
@param u2request: A urllib2 request.
|
||||
@type u2request: urllib2.Requet.
|
||||
@return: The opened file-like urllib2 object.
|
||||
@rtype: fp
|
||||
"""
|
||||
tm = self.options.timeout
|
||||
url = self.u2opener()
|
||||
if self.u2ver() < 2.6:
|
||||
socket.setdefaulttimeout(tm)
|
||||
return url.open(u2request)
|
||||
else:
|
||||
return url.open(u2request, timeout=tm)
|
||||
|
||||
def u2opener(self):
|
||||
"""
|
||||
Create a urllib opener.
|
||||
@return: An opener.
|
||||
@rtype: I{OpenerDirector}
|
||||
"""
|
||||
if self.urlopener is None:
|
||||
return u2.build_opener(*self.u2handlers())
|
||||
else:
|
||||
return self.urlopener
|
||||
|
||||
def u2handlers(self):
|
||||
"""
|
||||
Get a collection of urllib handlers.
|
||||
@return: A list of handlers to be installed in the opener.
|
||||
@rtype: [Handler,...]
|
||||
"""
|
||||
handlers = []
|
||||
handlers.append(u2.ProxyHandler(self.proxy))
|
||||
return handlers
|
||||
|
||||
def u2ver(self):
|
||||
"""
|
||||
Get the major/minor version of the urllib2 lib.
|
||||
@return: The urllib2 version.
|
||||
@rtype: float
|
||||
"""
|
||||
try:
|
||||
part = u2.__version__.split('.', 1)
|
||||
n = float('.'.join(part))
|
||||
return n
|
||||
except Exception, e:
|
||||
log.exception(e)
|
||||
return 0
|
||||
|
||||
def __deepcopy__(self, memo={}):
|
||||
clone = self.__class__()
|
||||
p = Unskin(self.options)
|
||||
cp = Unskin(clone.options)
|
||||
cp.update(p)
|
||||
return clone
|
||||
|
||||
|
||||
class HttpAuthenticated(HttpTransport):
|
||||
"""
|
||||
Provides basic http authentication for servers that don't follow
|
||||
the specified challenge / response model. This implementation
|
||||
appends the I{Authorization} http header with base64 encoded
|
||||
credentials on every http request.
|
||||
"""
|
||||
|
||||
def open(self, request):
|
||||
self.addcredentials(request)
|
||||
return HttpTransport.open(self, request)
|
||||
|
||||
def send(self, request):
|
||||
self.addcredentials(request)
|
||||
return HttpTransport.send(self, request)
|
||||
|
||||
def addcredentials(self, request):
|
||||
credentials = self.credentials()
|
||||
if not (None in credentials):
|
||||
encoded = base64.encodestring(':'.join(credentials))
|
||||
basic = 'Basic %s' % encoded[:-1]
|
||||
request.headers['Authorization'] = basic
|
||||
|
||||
def credentials(self):
|
||||
return (self.options.username, self.options.password)
|
||||
98
awx/lib/site-packages/suds/transport/https.py
Normal file
98
awx/lib/site-packages/suds/transport/https.py
Normal file
@ -0,0 +1,98 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains classes for basic HTTP (authenticated) transport implementations.
|
||||
"""
|
||||
|
||||
import urllib2 as u2
|
||||
from suds.transport import *
|
||||
from suds.transport.http import HttpTransport
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class HttpAuthenticated(HttpTransport):
|
||||
"""
|
||||
Provides basic http authentication that follows the RFC-2617 specification.
|
||||
As defined by specifications, credentials are provided to the server
|
||||
upon request (HTTP/1.0 401 Authorization Required) by the server only.
|
||||
@ivar pm: The password manager.
|
||||
@ivar handler: The authentication handler.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""
|
||||
@param kwargs: Keyword arguments.
|
||||
- B{proxy} - An http proxy to be specified on requests.
|
||||
The proxy is defined as {protocol:proxy,}
|
||||
- type: I{dict}
|
||||
- default: {}
|
||||
- B{timeout} - Set the url open timeout (seconds).
|
||||
- type: I{float}
|
||||
- default: 90
|
||||
- B{username} - The username used for http authentication.
|
||||
- type: I{str}
|
||||
- default: None
|
||||
- B{password} - The password used for http authentication.
|
||||
- type: I{str}
|
||||
- default: None
|
||||
"""
|
||||
HttpTransport.__init__(self, **kwargs)
|
||||
self.pm = u2.HTTPPasswordMgrWithDefaultRealm()
|
||||
|
||||
def open(self, request):
|
||||
self.addcredentials(request)
|
||||
return HttpTransport.open(self, request)
|
||||
|
||||
def send(self, request):
|
||||
self.addcredentials(request)
|
||||
return HttpTransport.send(self, request)
|
||||
|
||||
def addcredentials(self, request):
|
||||
credentials = self.credentials()
|
||||
if not (None in credentials):
|
||||
u = credentials[0]
|
||||
p = credentials[1]
|
||||
self.pm.add_password(None, request.url, u, p)
|
||||
|
||||
def credentials(self):
|
||||
return (self.options.username, self.options.password)
|
||||
|
||||
def u2handlers(self):
|
||||
handlers = HttpTransport.u2handlers(self)
|
||||
handlers.append(u2.HTTPBasicAuthHandler(self.pm))
|
||||
return handlers
|
||||
|
||||
|
||||
class WindowsHttpAuthenticated(HttpAuthenticated):
|
||||
"""
|
||||
Provides Windows (NTLM) http authentication.
|
||||
@ivar pm: The password manager.
|
||||
@ivar handler: The authentication handler.
|
||||
@author: Christopher Bess
|
||||
"""
|
||||
|
||||
def u2handlers(self):
|
||||
# try to import ntlm support
|
||||
try:
|
||||
from ntlm import HTTPNtlmAuthHandler
|
||||
except ImportError:
|
||||
raise Exception("Cannot import python-ntlm module")
|
||||
handlers = HttpTransport.u2handlers(self)
|
||||
handlers.append(HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(self.pm))
|
||||
return handlers
|
||||
57
awx/lib/site-packages/suds/transport/options.py
Normal file
57
awx/lib/site-packages/suds/transport/options.py
Normal file
@ -0,0 +1,57 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Contains classes for transport options.
|
||||
"""
|
||||
|
||||
|
||||
from suds.transport import *
|
||||
from suds.properties import *
|
||||
|
||||
|
||||
class Options(Skin):
|
||||
"""
|
||||
Options:
|
||||
- B{proxy} - An http proxy to be specified on requests.
|
||||
The proxy is defined as {protocol:proxy,}
|
||||
- type: I{dict}
|
||||
- default: {}
|
||||
- B{timeout} - Set the url open timeout (seconds).
|
||||
- type: I{float}
|
||||
- default: 90
|
||||
- B{headers} - Extra HTTP headers.
|
||||
- type: I{dict}
|
||||
- I{str} B{http} - The I{http} protocol proxy URL.
|
||||
- I{str} B{https} - The I{https} protocol proxy URL.
|
||||
- default: {}
|
||||
- B{username} - The username used for http authentication.
|
||||
- type: I{str}
|
||||
- default: None
|
||||
- B{password} - The password used for http authentication.
|
||||
- type: I{str}
|
||||
- default: None
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
domain = __name__
|
||||
definitions = [
|
||||
Definition('proxy', dict, {}),
|
||||
Definition('timeout', (int,float), 90),
|
||||
Definition('headers', dict, {}),
|
||||
Definition('username', basestring, None),
|
||||
Definition('password', basestring, None),
|
||||
]
|
||||
Skin.__init__(self, domain, definitions, kwargs)
|
||||
56
awx/lib/site-packages/suds/umx/__init__.py
Normal file
56
awx/lib/site-packages/suds/umx/__init__.py
Normal file
@ -0,0 +1,56 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides modules containing classes to support
|
||||
unmarshalling (XML).
|
||||
"""
|
||||
|
||||
from suds.sudsobject import Object
|
||||
|
||||
|
||||
|
||||
class Content(Object):
|
||||
"""
|
||||
@ivar node: The content source node.
|
||||
@type node: L{sax.element.Element}
|
||||
@ivar data: The (optional) content data.
|
||||
@type data: L{Object}
|
||||
@ivar text: The (optional) content (xml) text.
|
||||
@type text: basestring
|
||||
"""
|
||||
|
||||
extensions = []
|
||||
|
||||
def __init__(self, node, **kwargs):
|
||||
Object.__init__(self)
|
||||
self.node = node
|
||||
self.data = None
|
||||
self.text = None
|
||||
for k,v in kwargs.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name not in self.__dict__:
|
||||
if name in self.extensions:
|
||||
v = None
|
||||
setattr(self, name, v)
|
||||
else:
|
||||
raise AttributeError, \
|
||||
'Content has no attribute %s' % name
|
||||
else:
|
||||
v = self.__dict__[name]
|
||||
return v
|
||||
88
awx/lib/site-packages/suds/umx/attrlist.py
Normal file
88
awx/lib/site-packages/suds/umx/attrlist.py
Normal file
@ -0,0 +1,88 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides filtered attribute list classes.
|
||||
"""
|
||||
|
||||
from suds import *
|
||||
from suds.umx import *
|
||||
from suds.sax import Namespace
|
||||
|
||||
|
||||
class AttrList:
|
||||
"""
|
||||
A filtered attribute list.
|
||||
Items are included during iteration if they are in either the (xs) or
|
||||
(xml) namespaces.
|
||||
@ivar raw: The I{raw} attribute list.
|
||||
@type raw: list
|
||||
"""
|
||||
def __init__(self, attributes):
|
||||
"""
|
||||
@param attributes: A list of attributes
|
||||
@type attributes: list
|
||||
"""
|
||||
self.raw = attributes
|
||||
|
||||
def real(self):
|
||||
"""
|
||||
Get list of I{real} attributes which exclude xs and xml attributes.
|
||||
@return: A list of I{real} attributes.
|
||||
@rtype: I{generator}
|
||||
"""
|
||||
for a in self.raw:
|
||||
if self.skip(a): continue
|
||||
yield a
|
||||
|
||||
def rlen(self):
|
||||
"""
|
||||
Get the number of I{real} attributes which exclude xs and xml attributes.
|
||||
@return: A count of I{real} attributes.
|
||||
@rtype: L{int}
|
||||
"""
|
||||
n = 0
|
||||
for a in self.real():
|
||||
n += 1
|
||||
return n
|
||||
|
||||
def lang(self):
|
||||
"""
|
||||
Get list of I{filtered} attributes which exclude xs.
|
||||
@return: A list of I{filtered} attributes.
|
||||
@rtype: I{generator}
|
||||
"""
|
||||
for a in self.raw:
|
||||
if a.qname() == 'xml:lang':
|
||||
return a.value
|
||||
return None
|
||||
|
||||
def skip(self, attr):
|
||||
"""
|
||||
Get whether to skip (filter-out) the specified attribute.
|
||||
@param attr: An attribute.
|
||||
@type attr: I{Attribute}
|
||||
@return: True if should be skipped.
|
||||
@rtype: bool
|
||||
"""
|
||||
ns = attr.namespace()
|
||||
skip = (
|
||||
Namespace.xmlns[1],
|
||||
'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'http://www.w3.org/2003/05/soap-envelope',
|
||||
)
|
||||
return ( Namespace.xs(ns) or ns[1] in skip )
|
||||
41
awx/lib/site-packages/suds/umx/basic.py
Normal file
41
awx/lib/site-packages/suds/umx/basic.py
Normal file
@ -0,0 +1,41 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides basic unmarshaller classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.umx import *
|
||||
from suds.umx.core import Core
|
||||
|
||||
|
||||
class Basic(Core):
|
||||
"""
|
||||
A object builder (unmarshaller).
|
||||
"""
|
||||
|
||||
def process(self, node):
|
||||
"""
|
||||
Process an object graph representation of the xml I{node}.
|
||||
@param node: An XML tree.
|
||||
@type node: L{sax.element.Element}
|
||||
@return: A suds object.
|
||||
@rtype: L{Object}
|
||||
"""
|
||||
content = Content(node)
|
||||
return Core.process(self, content)
|
||||
216
awx/lib/site-packages/suds/umx/core.py
Normal file
216
awx/lib/site-packages/suds/umx/core.py
Normal file
@ -0,0 +1,216 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides base classes for XML->object I{unmarshalling}.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.umx import *
|
||||
from suds.umx.attrlist import AttrList
|
||||
from suds.sax.text import Text
|
||||
from suds.sudsobject import Factory, merge
|
||||
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
reserved = { 'class':'cls', 'def':'dfn', }
|
||||
|
||||
class Core:
|
||||
"""
|
||||
The abstract XML I{node} unmarshaller. This class provides the
|
||||
I{core} unmarshalling functionality.
|
||||
"""
|
||||
|
||||
def process(self, content):
|
||||
"""
|
||||
Process an object graph representation of the xml I{node}.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: A suds object.
|
||||
@rtype: L{Object}
|
||||
"""
|
||||
self.reset()
|
||||
return self.append(content)
|
||||
|
||||
def append(self, content):
|
||||
"""
|
||||
Process the specified node and convert the XML document into
|
||||
a I{suds} L{object}.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: A I{append-result} tuple as: (L{Object}, I{value})
|
||||
@rtype: I{append-result}
|
||||
@note: This is not the proper entry point.
|
||||
@see: L{process()}
|
||||
"""
|
||||
self.start(content)
|
||||
self.append_attributes(content)
|
||||
self.append_children(content)
|
||||
self.append_text(content)
|
||||
self.end(content)
|
||||
return self.postprocess(content)
|
||||
|
||||
def postprocess(self, content):
|
||||
"""
|
||||
Perform final processing of the resulting data structure as follows:
|
||||
- Mixed values (children and text) will have a result of the I{content.node}.
|
||||
- Simi-simple values (attributes, no-children and text) will have a result of a
|
||||
property object.
|
||||
- Simple values (no-attributes, no-children with text nodes) will have a string
|
||||
result equal to the value of the content.node.getText().
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: The post-processed result.
|
||||
@rtype: I{any}
|
||||
"""
|
||||
node = content.node
|
||||
if len(node.children) and node.hasText():
|
||||
return node
|
||||
attributes = AttrList(node.attributes)
|
||||
if attributes.rlen() and \
|
||||
not len(node.children) and \
|
||||
node.hasText():
|
||||
p = Factory.property(node.name, node.getText())
|
||||
return merge(content.data, p)
|
||||
if len(content.data):
|
||||
return content.data
|
||||
lang = attributes.lang()
|
||||
if content.node.isnil():
|
||||
return None
|
||||
if not len(node.children) and content.text is None:
|
||||
if self.nillable(content):
|
||||
return None
|
||||
else:
|
||||
return Text('', lang=lang)
|
||||
if isinstance(content.text, basestring):
|
||||
return Text(content.text, lang=lang)
|
||||
else:
|
||||
return content.text
|
||||
|
||||
def append_attributes(self, content):
|
||||
"""
|
||||
Append attribute nodes into L{Content.data}.
|
||||
Attributes in the I{schema} or I{xml} namespaces are skipped.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
attributes = AttrList(content.node.attributes)
|
||||
for attr in attributes.real():
|
||||
name = attr.name
|
||||
value = attr.value
|
||||
self.append_attribute(name, value, content)
|
||||
|
||||
def append_attribute(self, name, value, content):
|
||||
"""
|
||||
Append an attribute name/value into L{Content.data}.
|
||||
@param name: The attribute name
|
||||
@type name: basestring
|
||||
@param value: The attribute's value
|
||||
@type value: basestring
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
key = name
|
||||
key = '_%s' % reserved.get(key, key)
|
||||
setattr(content.data, key, value)
|
||||
|
||||
def append_children(self, content):
|
||||
"""
|
||||
Append child nodes into L{Content.data}
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
for child in content.node:
|
||||
cont = Content(child)
|
||||
cval = self.append(cont)
|
||||
key = reserved.get(child.name, child.name)
|
||||
if key in content.data:
|
||||
v = getattr(content.data, key)
|
||||
if isinstance(v, list):
|
||||
v.append(cval)
|
||||
else:
|
||||
setattr(content.data, key, [v, cval])
|
||||
continue
|
||||
if self.unbounded(cont):
|
||||
if cval is None:
|
||||
setattr(content.data, key, [])
|
||||
else:
|
||||
setattr(content.data, key, [cval,])
|
||||
else:
|
||||
setattr(content.data, key, cval)
|
||||
|
||||
def append_text(self, content):
|
||||
"""
|
||||
Append text nodes into L{Content.data}
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
if content.node.hasText():
|
||||
content.text = content.node.getText()
|
||||
|
||||
def reset(self):
|
||||
pass
|
||||
|
||||
def start(self, content):
|
||||
"""
|
||||
Processing on I{node} has started. Build and return
|
||||
the proper object.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: A subclass of Object.
|
||||
@rtype: L{Object}
|
||||
"""
|
||||
content.data = Factory.object(content.node.name)
|
||||
|
||||
def end(self, content):
|
||||
"""
|
||||
Processing on I{node} has ended.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
pass
|
||||
|
||||
def bounded(self, content):
|
||||
"""
|
||||
Get whether the content is bounded (not a list).
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: True if bounded, else False
|
||||
@rtype: boolean
|
||||
'"""
|
||||
return ( not self.unbounded(content) )
|
||||
|
||||
def unbounded(self, content):
|
||||
"""
|
||||
Get whether the object is unbounded (a list).
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: True if unbounded, else False
|
||||
@rtype: boolean
|
||||
'"""
|
||||
return False
|
||||
|
||||
def nillable(self, content):
|
||||
"""
|
||||
Get whether the object is nillable.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: True if nillable, else False
|
||||
@rtype: boolean
|
||||
'"""
|
||||
return False
|
||||
128
awx/lib/site-packages/suds/umx/encoded.py
Normal file
128
awx/lib/site-packages/suds/umx/encoded.py
Normal file
@ -0,0 +1,128 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides soap encoded unmarshaller classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.umx import *
|
||||
from suds.umx.typed import Typed
|
||||
from suds.sax import splitPrefix, Namespace
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
#
|
||||
# Add encoded extensions
|
||||
# aty = The soap (section 5) encoded array type.
|
||||
#
|
||||
Content.extensions.append('aty')
|
||||
|
||||
|
||||
class Encoded(Typed):
|
||||
"""
|
||||
A SOAP section (5) encoding unmarshaller.
|
||||
This marshaller supports rpc/encoded soap styles.
|
||||
"""
|
||||
|
||||
def start(self, content):
|
||||
#
|
||||
# Grab the array type and continue
|
||||
#
|
||||
self.setaty(content)
|
||||
Typed.start(self, content)
|
||||
|
||||
def end(self, content):
|
||||
#
|
||||
# Squash soap encoded arrays into python lists. This is
|
||||
# also where we insure that empty arrays are represented
|
||||
# as empty python lists.
|
||||
#
|
||||
aty = content.aty
|
||||
if aty is not None:
|
||||
self.promote(content)
|
||||
return Typed.end(self, content)
|
||||
|
||||
def postprocess(self, content):
|
||||
#
|
||||
# Ensure proper rendering of empty arrays.
|
||||
#
|
||||
if content.aty is None:
|
||||
return Typed.postprocess(self, content)
|
||||
else:
|
||||
return content.data
|
||||
|
||||
def setaty(self, content):
|
||||
"""
|
||||
Grab the (aty) soap-enc:arrayType and attach it to the
|
||||
content for proper array processing later in end().
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
@return: self
|
||||
@rtype: L{Encoded}
|
||||
"""
|
||||
name = 'arrayType'
|
||||
ns = (None, 'http://schemas.xmlsoap.org/soap/encoding/')
|
||||
aty = content.node.get(name, ns)
|
||||
if aty is not None:
|
||||
content.aty = aty
|
||||
parts = aty.split('[')
|
||||
ref = parts[0]
|
||||
if len(parts) == 2:
|
||||
self.applyaty(content, ref)
|
||||
else:
|
||||
pass # (2) dimensional array
|
||||
return self
|
||||
|
||||
def applyaty(self, content, xty):
|
||||
"""
|
||||
Apply the type referenced in the I{arrayType} to the content
|
||||
(child nodes) of the array. Each element (node) in the array
|
||||
that does not have an explicit xsi:type attribute is given one
|
||||
based on the I{arrayType}.
|
||||
@param content: An array content.
|
||||
@type content: L{Content}
|
||||
@param xty: The XSI type reference.
|
||||
@type xty: str
|
||||
@return: self
|
||||
@rtype: L{Encoded}
|
||||
"""
|
||||
name = 'type'
|
||||
ns = Namespace.xsins
|
||||
parent = content.node
|
||||
for child in parent.getChildren():
|
||||
ref = child.get(name, ns)
|
||||
if ref is None:
|
||||
parent.addPrefix(ns[0], ns[1])
|
||||
attr = ':'.join((ns[0], name))
|
||||
child.set(attr, xty)
|
||||
return self
|
||||
|
||||
def promote(self, content):
|
||||
"""
|
||||
Promote (replace) the content.data with the first attribute
|
||||
of the current content.data that is a I{list}. Note: the
|
||||
content.data may be empty or contain only _x attributes.
|
||||
In either case, the content.data is assigned an empty list.
|
||||
@param content: An array content.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
for n,v in content.data:
|
||||
if isinstance(v, list):
|
||||
content.data = v
|
||||
return
|
||||
content.data = []
|
||||
141
awx/lib/site-packages/suds/umx/typed.py
Normal file
141
awx/lib/site-packages/suds/umx/typed.py
Normal file
@ -0,0 +1,141 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
Provides typed unmarshaller classes.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.umx import *
|
||||
from suds.umx.core import Core
|
||||
from suds.resolver import NodeResolver, Frame
|
||||
from suds.sudsobject import Factory
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
#
|
||||
# Add typed extensions
|
||||
# type = The expected xsd type
|
||||
# real = The 'true' XSD type
|
||||
#
|
||||
Content.extensions.append('type')
|
||||
Content.extensions.append('real')
|
||||
|
||||
|
||||
class Typed(Core):
|
||||
"""
|
||||
A I{typed} XML unmarshaller
|
||||
@ivar resolver: A schema type resolver.
|
||||
@type resolver: L{NodeResolver}
|
||||
"""
|
||||
|
||||
def __init__(self, schema):
|
||||
"""
|
||||
@param schema: A schema object.
|
||||
@type schema: L{xsd.schema.Schema}
|
||||
"""
|
||||
self.resolver = NodeResolver(schema)
|
||||
|
||||
def process(self, node, type):
|
||||
"""
|
||||
Process an object graph representation of the xml L{node}.
|
||||
@param node: An XML tree.
|
||||
@type node: L{sax.element.Element}
|
||||
@param type: The I{optional} schema type.
|
||||
@type type: L{xsd.sxbase.SchemaObject}
|
||||
@return: A suds object.
|
||||
@rtype: L{Object}
|
||||
"""
|
||||
content = Content(node)
|
||||
content.type = type
|
||||
return Core.process(self, content)
|
||||
|
||||
def reset(self):
|
||||
log.debug('reset')
|
||||
self.resolver.reset()
|
||||
|
||||
def start(self, content):
|
||||
#
|
||||
# Resolve to the schema type; build an object and setup metadata.
|
||||
#
|
||||
if content.type is None:
|
||||
found = self.resolver.find(content.node)
|
||||
if found is None:
|
||||
log.error(self.resolver.schema)
|
||||
raise TypeNotFound(content.node.qname())
|
||||
content.type = found
|
||||
else:
|
||||
known = self.resolver.known(content.node)
|
||||
frame = Frame(content.type, resolved=known)
|
||||
self.resolver.push(frame)
|
||||
real = self.resolver.top().resolved
|
||||
content.real = real
|
||||
cls_name = real.name
|
||||
if cls_name is None:
|
||||
cls_name = content.node.name
|
||||
content.data = Factory.object(cls_name)
|
||||
md = content.data.__metadata__
|
||||
md.sxtype = real
|
||||
|
||||
def end(self, content):
|
||||
self.resolver.pop()
|
||||
|
||||
def unbounded(self, content):
|
||||
return content.type.unbounded()
|
||||
|
||||
def nillable(self, content):
|
||||
resolved = content.type.resolve()
|
||||
return ( content.type.nillable or \
|
||||
(resolved.builtin() and resolved.nillable ) )
|
||||
|
||||
def append_attribute(self, name, value, content):
|
||||
"""
|
||||
Append an attribute name/value into L{Content.data}.
|
||||
@param name: The attribute name
|
||||
@type name: basestring
|
||||
@param value: The attribute's value
|
||||
@type value: basestring
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
type = self.resolver.findattr(name)
|
||||
if type is None:
|
||||
log.warn('attribute (%s) type, not-found', name)
|
||||
else:
|
||||
value = self.translated(value, type)
|
||||
Core.append_attribute(self, name, value, content)
|
||||
|
||||
def append_text(self, content):
|
||||
"""
|
||||
Append text nodes into L{Content.data}
|
||||
Here is where the I{true} type is used to translate the value
|
||||
into the proper python type.
|
||||
@param content: The current content being unmarshalled.
|
||||
@type content: L{Content}
|
||||
"""
|
||||
Core.append_text(self, content)
|
||||
known = self.resolver.top().resolved
|
||||
content.text = self.translated(content.text, known)
|
||||
|
||||
def translated(self, value, type):
|
||||
""" translate using the schema type """
|
||||
if value is not None:
|
||||
resolved = type.resolve()
|
||||
return resolved.translate(value)
|
||||
else:
|
||||
return value
|
||||
922
awx/lib/site-packages/suds/wsdl.py
Normal file
922
awx/lib/site-packages/suds/wsdl.py
Normal file
@ -0,0 +1,922 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{wsdl} module provides an objectification of the WSDL.
|
||||
The primary class is I{Definitions} as it represends the root element
|
||||
found in the document.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sax import splitPrefix
|
||||
from suds.sax.element import Element
|
||||
from suds.bindings.document import Document
|
||||
from suds.bindings.rpc import RPC, Encoded
|
||||
from suds.xsd import qualify, Namespace
|
||||
from suds.xsd.schema import Schema, SchemaCollection
|
||||
from suds.xsd.query import ElementQuery
|
||||
from suds.sudsobject import Object, Facade, Metadata
|
||||
from suds.reader import DocumentReader, DefinitionsReader
|
||||
from urlparse import urljoin
|
||||
import re, soaparray
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
wsdlns = (None, "http://schemas.xmlsoap.org/wsdl/")
|
||||
soapns = (None, 'http://schemas.xmlsoap.org/wsdl/soap/')
|
||||
soap12ns = (None, 'http://schemas.xmlsoap.org/wsdl/soap12/')
|
||||
|
||||
|
||||
class WObject(Object):
|
||||
"""
|
||||
Base object for wsdl types.
|
||||
@ivar root: The XML I{root} element.
|
||||
@type root: L{Element}
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions=None):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
Object.__init__(self)
|
||||
self.root = root
|
||||
pmd = Metadata()
|
||||
pmd.excludes = ['root']
|
||||
pmd.wrappers = dict(qname=repr)
|
||||
self.__metadata__.__print__ = pmd
|
||||
|
||||
def resolve(self, definitions):
|
||||
"""
|
||||
Resolve named references to other WSDL objects.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class NamedObject(WObject):
|
||||
"""
|
||||
A B{named} WSDL object.
|
||||
@ivar name: The name of the object.
|
||||
@type name: str
|
||||
@ivar qname: The I{qualified} name of the object.
|
||||
@type qname: (name, I{namespace-uri}).
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
WObject.__init__(self, root, definitions)
|
||||
self.name = root.get('name')
|
||||
self.qname = (self.name, definitions.tns[1])
|
||||
pmd = self.__metadata__.__print__
|
||||
pmd.wrappers['qname'] = repr
|
||||
|
||||
|
||||
class Definitions(WObject):
|
||||
"""
|
||||
Represents the I{root} container of the WSDL objects as defined
|
||||
by <wsdl:definitions/>
|
||||
@ivar id: The object id.
|
||||
@type id: str
|
||||
@ivar options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
@ivar url: The URL used to load the object.
|
||||
@type url: str
|
||||
@ivar tns: The target namespace for the WSDL.
|
||||
@type tns: str
|
||||
@ivar schema: The collective WSDL schema object.
|
||||
@type schema: L{SchemaCollection}
|
||||
@ivar children: The raw list of child objects.
|
||||
@type children: [L{WObject},...]
|
||||
@ivar imports: The list of L{Import} children.
|
||||
@type imports: [L{Import},...]
|
||||
@ivar messages: The dictionary of L{Message} children key'd by I{qname}
|
||||
@type messages: [L{Message},...]
|
||||
@ivar port_types: The dictionary of L{PortType} children key'd by I{qname}
|
||||
@type port_types: [L{PortType},...]
|
||||
@ivar bindings: The dictionary of L{Binding} children key'd by I{qname}
|
||||
@type bindings: [L{Binding},...]
|
||||
@ivar service: The service object.
|
||||
@type service: L{Service}
|
||||
"""
|
||||
|
||||
Tag = 'definitions'
|
||||
|
||||
def __init__(self, url, options):
|
||||
"""
|
||||
@param url: A URL to the WSDL.
|
||||
@type url: str
|
||||
@param options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
"""
|
||||
log.debug('reading wsdl at: %s ...', url)
|
||||
reader = DocumentReader(options)
|
||||
d = reader.open(url)
|
||||
root = d.root()
|
||||
WObject.__init__(self, root)
|
||||
self.id = objid(self)
|
||||
self.options = options
|
||||
self.url = url
|
||||
self.tns = self.mktns(root)
|
||||
self.types = []
|
||||
self.schema = None
|
||||
self.children = []
|
||||
self.imports = []
|
||||
self.messages = {}
|
||||
self.port_types = {}
|
||||
self.bindings = {}
|
||||
self.services = []
|
||||
self.add_children(self.root)
|
||||
self.children.sort()
|
||||
pmd = self.__metadata__.__print__
|
||||
pmd.excludes.append('children')
|
||||
pmd.excludes.append('wsdl')
|
||||
pmd.wrappers['schema'] = repr
|
||||
self.open_imports()
|
||||
self.resolve()
|
||||
self.build_schema()
|
||||
self.set_wrapped()
|
||||
for s in self.services:
|
||||
self.add_methods(s)
|
||||
log.debug("wsdl at '%s' loaded:\n%s", url, self)
|
||||
|
||||
def mktns(self, root):
|
||||
""" Get/create the target namespace """
|
||||
tns = root.get('targetNamespace')
|
||||
prefix = root.findPrefix(tns)
|
||||
if prefix is None:
|
||||
log.debug('warning: tns (%s), not mapped to prefix', tns)
|
||||
prefix = 'tns'
|
||||
return (prefix, tns)
|
||||
|
||||
def add_children(self, root):
|
||||
""" Add child objects using the factory """
|
||||
for c in root.getChildren(ns=wsdlns):
|
||||
child = Factory.create(c, self)
|
||||
if child is None: continue
|
||||
self.children.append(child)
|
||||
if isinstance(child, Import):
|
||||
self.imports.append(child)
|
||||
continue
|
||||
if isinstance(child, Types):
|
||||
self.types.append(child)
|
||||
continue
|
||||
if isinstance(child, Message):
|
||||
self.messages[child.qname] = child
|
||||
continue
|
||||
if isinstance(child, PortType):
|
||||
self.port_types[child.qname] = child
|
||||
continue
|
||||
if isinstance(child, Binding):
|
||||
self.bindings[child.qname] = child
|
||||
continue
|
||||
if isinstance(child, Service):
|
||||
self.services.append(child)
|
||||
continue
|
||||
|
||||
def open_imports(self):
|
||||
""" Import the I{imported} WSDLs. """
|
||||
for imp in self.imports:
|
||||
imp.load(self)
|
||||
|
||||
def resolve(self):
|
||||
""" Tell all children to resolve themselves """
|
||||
for c in self.children:
|
||||
c.resolve(self)
|
||||
|
||||
def build_schema(self):
|
||||
""" Process L{Types} objects and create the schema collection """
|
||||
container = SchemaCollection(self)
|
||||
for t in [t for t in self.types if t.local()]:
|
||||
for root in t.contents():
|
||||
schema = Schema(root, self.url, self.options, container)
|
||||
container.add(schema)
|
||||
if not len(container): # empty
|
||||
root = Element.buildPath(self.root, 'types/schema')
|
||||
schema = Schema(root, self.url, self.options, container)
|
||||
container.add(schema)
|
||||
self.schema = container.load(self.options)
|
||||
for s in [t.schema() for t in self.types if t.imported()]:
|
||||
self.schema.merge(s)
|
||||
return self.schema
|
||||
|
||||
def add_methods(self, service):
|
||||
""" Build method view for service """
|
||||
bindings = {
|
||||
'document/literal' : Document(self),
|
||||
'rpc/literal' : RPC(self),
|
||||
'rpc/encoded' : Encoded(self)
|
||||
}
|
||||
for p in service.ports:
|
||||
binding = p.binding
|
||||
ptype = p.binding.type
|
||||
operations = p.binding.type.operations.values()
|
||||
for name in [op.name for op in operations]:
|
||||
m = Facade('Method')
|
||||
m.name = name
|
||||
m.location = p.location
|
||||
m.binding = Facade('binding')
|
||||
op = binding.operation(name)
|
||||
m.soap = op.soap
|
||||
key = '/'.join((op.soap.style, op.soap.input.body.use))
|
||||
m.binding.input = bindings.get(key)
|
||||
key = '/'.join((op.soap.style, op.soap.output.body.use))
|
||||
m.binding.output = bindings.get(key)
|
||||
op = ptype.operation(name)
|
||||
p.methods[name] = m
|
||||
|
||||
def set_wrapped(self):
|
||||
""" set (wrapped|bare) flag on messages """
|
||||
for b in self.bindings.values():
|
||||
for op in b.operations.values():
|
||||
for body in (op.soap.input.body, op.soap.output.body):
|
||||
body.wrapped = False
|
||||
if len(body.parts) != 1:
|
||||
continue
|
||||
for p in body.parts:
|
||||
if p.element is None:
|
||||
continue
|
||||
query = ElementQuery(p.element)
|
||||
pt = query.execute(self.schema)
|
||||
if pt is None:
|
||||
raise TypeNotFound(query.ref)
|
||||
resolved = pt.resolve()
|
||||
if resolved.builtin():
|
||||
continue
|
||||
body.wrapped = True
|
||||
|
||||
def __getstate__(self):
|
||||
nopickle = ('options',)
|
||||
state = self.__dict__.copy()
|
||||
for k in nopickle:
|
||||
if k in state:
|
||||
del state[k]
|
||||
return state
|
||||
|
||||
def __repr__(self):
|
||||
return 'Definitions (id=%s)' % self.id
|
||||
|
||||
|
||||
class Import(WObject):
|
||||
"""
|
||||
Represents the <wsdl:import/>.
|
||||
@ivar location: The value of the I{location} attribute.
|
||||
@type location: str
|
||||
@ivar ns: The value of the I{namespace} attribute.
|
||||
@type ns: str
|
||||
@ivar imported: The imported object.
|
||||
@type imported: L{Definitions}
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
WObject.__init__(self, root, definitions)
|
||||
self.location = root.get('location')
|
||||
self.ns = root.get('namespace')
|
||||
self.imported = None
|
||||
pmd = self.__metadata__.__print__
|
||||
pmd.wrappers['imported'] = repr
|
||||
|
||||
def load(self, definitions):
|
||||
""" Load the object by opening the URL """
|
||||
url = self.location
|
||||
log.debug('importing (%s)', url)
|
||||
if '://' not in url:
|
||||
url = urljoin(definitions.url, url)
|
||||
options = definitions.options
|
||||
d = Definitions(url, options)
|
||||
if d.root.match(Definitions.Tag, wsdlns):
|
||||
self.import_definitions(definitions, d)
|
||||
return
|
||||
if d.root.match(Schema.Tag, Namespace.xsdns):
|
||||
self.import_schema(definitions, d)
|
||||
return
|
||||
raise Exception('document at "%s" is unknown' % url)
|
||||
|
||||
def import_definitions(self, definitions, d):
|
||||
""" import/merge wsdl definitions """
|
||||
definitions.types += d.types
|
||||
definitions.messages.update(d.messages)
|
||||
definitions.port_types.update(d.port_types)
|
||||
definitions.bindings.update(d.bindings)
|
||||
self.imported = d
|
||||
log.debug('imported (WSDL):\n%s', d)
|
||||
|
||||
def import_schema(self, definitions, d):
|
||||
""" import schema as <types/> content """
|
||||
if not len(definitions.types):
|
||||
types = Types.create(definitions)
|
||||
definitions.types.append(types)
|
||||
else:
|
||||
types = definitions.types[-1]
|
||||
types.root.append(d.root)
|
||||
log.debug('imported (XSD):\n%s', d.root)
|
||||
|
||||
def __gt__(self, other):
|
||||
return False
|
||||
|
||||
|
||||
class Types(WObject):
|
||||
"""
|
||||
Represents <types><schema/></types>.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def create(cls, definitions):
|
||||
root = Element('types', ns=wsdlns)
|
||||
definitions.root.insert(root)
|
||||
return Types(root, definitions)
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
WObject.__init__(self, root, definitions)
|
||||
self.definitions = definitions
|
||||
|
||||
def contents(self):
|
||||
return self.root.getChildren('schema', Namespace.xsdns)
|
||||
|
||||
def schema(self):
|
||||
return self.definitions.schema
|
||||
|
||||
def local(self):
|
||||
return ( self.definitions.schema is None )
|
||||
|
||||
def imported(self):
|
||||
return ( not self.local() )
|
||||
|
||||
def __gt__(self, other):
|
||||
return isinstance(other, Import)
|
||||
|
||||
|
||||
class Part(NamedObject):
|
||||
"""
|
||||
Represents <message><part/></message>.
|
||||
@ivar element: The value of the {element} attribute.
|
||||
Stored as a I{qref} as converted by L{suds.xsd.qualify}.
|
||||
@type element: str
|
||||
@ivar type: The value of the {type} attribute.
|
||||
Stored as a I{qref} as converted by L{suds.xsd.qualify}.
|
||||
@type type: str
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
NamedObject.__init__(self, root, definitions)
|
||||
pmd = Metadata()
|
||||
pmd.wrappers = dict(element=repr, type=repr)
|
||||
self.__metadata__.__print__ = pmd
|
||||
tns = definitions.tns
|
||||
self.element = self.__getref('element', tns)
|
||||
self.type = self.__getref('type', tns)
|
||||
|
||||
def __getref(self, a, tns):
|
||||
""" Get the qualified value of attribute named 'a'."""
|
||||
s = self.root.get(a)
|
||||
if s is None:
|
||||
return s
|
||||
else:
|
||||
return qualify(s, self.root, tns)
|
||||
|
||||
|
||||
class Message(NamedObject):
|
||||
"""
|
||||
Represents <message/>.
|
||||
@ivar parts: A list of message parts.
|
||||
@type parts: [I{Part},...]
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
NamedObject.__init__(self, root, definitions)
|
||||
self.parts = []
|
||||
for p in root.getChildren('part'):
|
||||
part = Part(p, definitions)
|
||||
self.parts.append(part)
|
||||
|
||||
def __gt__(self, other):
|
||||
return isinstance(other, (Import, Types))
|
||||
|
||||
|
||||
class PortType(NamedObject):
|
||||
"""
|
||||
Represents <portType/>.
|
||||
@ivar operations: A list of contained operations.
|
||||
@type operations: list
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
NamedObject.__init__(self, root, definitions)
|
||||
self.operations = {}
|
||||
for c in root.getChildren('operation'):
|
||||
op = Facade('Operation')
|
||||
op.name = c.get('name')
|
||||
op.tns = definitions.tns
|
||||
input = c.getChild('input')
|
||||
if input is None:
|
||||
op.input = None
|
||||
else:
|
||||
op.input = input.get('message')
|
||||
output = c.getChild('output')
|
||||
if output is None:
|
||||
op.output = None
|
||||
else:
|
||||
op.output = output.get('message')
|
||||
faults = []
|
||||
for fault in c.getChildren('fault'):
|
||||
f = Facade('Fault')
|
||||
f.name = fault.get('name')
|
||||
f.message = fault.get('message')
|
||||
faults.append(f)
|
||||
op.faults = faults
|
||||
self.operations[op.name] = op
|
||||
|
||||
def resolve(self, definitions):
|
||||
"""
|
||||
Resolve named references to other WSDL objects.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
for op in self.operations.values():
|
||||
if op.input is None:
|
||||
op.input = Message(Element('no-input'), definitions)
|
||||
else:
|
||||
qref = qualify(op.input, self.root, definitions.tns)
|
||||
msg = definitions.messages.get(qref)
|
||||
if msg is None:
|
||||
raise Exception("msg '%s', not-found" % op.input)
|
||||
else:
|
||||
op.input = msg
|
||||
if op.output is None:
|
||||
op.output = Message(Element('no-output'), definitions)
|
||||
else:
|
||||
qref = qualify(op.output, self.root, definitions.tns)
|
||||
msg = definitions.messages.get(qref)
|
||||
if msg is None:
|
||||
raise Exception("msg '%s', not-found" % op.output)
|
||||
else:
|
||||
op.output = msg
|
||||
for f in op.faults:
|
||||
qref = qualify(f.message, self.root, definitions.tns)
|
||||
msg = definitions.messages.get(qref)
|
||||
if msg is None:
|
||||
raise Exception, "msg '%s', not-found" % f.message
|
||||
f.message = msg
|
||||
|
||||
def operation(self, name):
|
||||
"""
|
||||
Shortcut used to get a contained operation by name.
|
||||
@param name: An operation name.
|
||||
@type name: str
|
||||
@return: The named operation.
|
||||
@rtype: Operation
|
||||
@raise L{MethodNotFound}: When not found.
|
||||
"""
|
||||
try:
|
||||
return self.operations[name]
|
||||
except Exception, e:
|
||||
raise MethodNotFound(name)
|
||||
|
||||
def __gt__(self, other):
|
||||
return isinstance(other, (Import, Types, Message))
|
||||
|
||||
|
||||
class Binding(NamedObject):
|
||||
"""
|
||||
Represents <binding/>
|
||||
@ivar operations: A list of contained operations.
|
||||
@type operations: list
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
NamedObject.__init__(self, root, definitions)
|
||||
self.operations = {}
|
||||
self.type = root.get('type')
|
||||
sr = self.soaproot()
|
||||
if sr is None:
|
||||
self.soap = None
|
||||
log.debug('binding: "%s" not a soap binding', self.name)
|
||||
return
|
||||
soap = Facade('soap')
|
||||
self.soap = soap
|
||||
self.soap.style = sr.get('style', default='document')
|
||||
self.add_operations(self.root, definitions)
|
||||
|
||||
def soaproot(self):
|
||||
""" get the soap:binding """
|
||||
for ns in (soapns, soap12ns):
|
||||
sr = self.root.getChild('binding', ns=ns)
|
||||
if sr is not None:
|
||||
return sr
|
||||
return None
|
||||
|
||||
def add_operations(self, root, definitions):
|
||||
""" Add <operation/> children """
|
||||
dsop = Element('operation', ns=soapns)
|
||||
for c in root.getChildren('operation'):
|
||||
op = Facade('Operation')
|
||||
op.name = c.get('name')
|
||||
sop = c.getChild('operation', default=dsop)
|
||||
soap = Facade('soap')
|
||||
soap.action = '"%s"' % sop.get('soapAction', default='')
|
||||
soap.style = sop.get('style', default=self.soap.style)
|
||||
soap.input = Facade('Input')
|
||||
soap.input.body = Facade('Body')
|
||||
soap.input.headers = []
|
||||
soap.output = Facade('Output')
|
||||
soap.output.body = Facade('Body')
|
||||
soap.output.headers = []
|
||||
op.soap = soap
|
||||
input = c.getChild('input')
|
||||
if input is None:
|
||||
input = Element('input', ns=wsdlns)
|
||||
body = input.getChild('body')
|
||||
self.body(definitions, soap.input.body, body)
|
||||
for header in input.getChildren('header'):
|
||||
self.header(definitions, soap.input, header)
|
||||
output = c.getChild('output')
|
||||
if output is None:
|
||||
output = Element('output', ns=wsdlns)
|
||||
body = output.getChild('body')
|
||||
self.body(definitions, soap.output.body, body)
|
||||
for header in output.getChildren('header'):
|
||||
self.header(definitions, soap.output, header)
|
||||
faults = []
|
||||
for fault in c.getChildren('fault'):
|
||||
sf = fault.getChild('fault')
|
||||
if sf is None:
|
||||
continue
|
||||
fn = fault.get('name')
|
||||
f = Facade('Fault')
|
||||
f.name = sf.get('name', default=fn)
|
||||
f.use = sf.get('use', default='literal')
|
||||
faults.append(f)
|
||||
soap.faults = faults
|
||||
self.operations[op.name] = op
|
||||
|
||||
def body(self, definitions, body, root):
|
||||
""" add the input/output body properties """
|
||||
if root is None:
|
||||
body.use = 'literal'
|
||||
body.namespace = definitions.tns
|
||||
body.parts = ()
|
||||
return
|
||||
parts = root.get('parts')
|
||||
if parts is None:
|
||||
body.parts = ()
|
||||
else:
|
||||
body.parts = re.split('[\s,]', parts)
|
||||
body.use = root.get('use', default='literal')
|
||||
ns = root.get('namespace')
|
||||
if ns is None:
|
||||
body.namespace = definitions.tns
|
||||
else:
|
||||
prefix = root.findPrefix(ns, 'b0')
|
||||
body.namespace = (prefix, ns)
|
||||
|
||||
def header(self, definitions, parent, root):
|
||||
""" add the input/output header properties """
|
||||
if root is None:
|
||||
return
|
||||
header = Facade('Header')
|
||||
parent.headers.append(header)
|
||||
header.use = root.get('use', default='literal')
|
||||
ns = root.get('namespace')
|
||||
if ns is None:
|
||||
header.namespace = definitions.tns
|
||||
else:
|
||||
prefix = root.findPrefix(ns, 'h0')
|
||||
header.namespace = (prefix, ns)
|
||||
msg = root.get('message')
|
||||
if msg is not None:
|
||||
header.message = msg
|
||||
part = root.get('part')
|
||||
if part is not None:
|
||||
header.part = part
|
||||
|
||||
def resolve(self, definitions):
|
||||
"""
|
||||
Resolve named references to other WSDL objects. This includes
|
||||
cross-linking information (from) the portType (to) the I{soap}
|
||||
protocol information on the binding for each operation.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
self.resolveport(definitions)
|
||||
for op in self.operations.values():
|
||||
self.resolvesoapbody(definitions, op)
|
||||
self.resolveheaders(definitions, op)
|
||||
self.resolvefaults(definitions, op)
|
||||
|
||||
def resolveport(self, definitions):
|
||||
"""
|
||||
Resolve port_type reference.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
ref = qualify(self.type, self.root, definitions.tns)
|
||||
port_type = definitions.port_types.get(ref)
|
||||
if port_type is None:
|
||||
raise Exception("portType '%s', not-found" % self.type)
|
||||
else:
|
||||
self.type = port_type
|
||||
|
||||
def resolvesoapbody(self, definitions, op):
|
||||
"""
|
||||
Resolve soap body I{message} parts by
|
||||
cross-referencing with operation defined in port type.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
@param op: An I{operation} object.
|
||||
@type op: I{operation}
|
||||
"""
|
||||
ptop = self.type.operation(op.name)
|
||||
if ptop is None:
|
||||
raise Exception, \
|
||||
"operation '%s' not defined in portType" % op.name
|
||||
soap = op.soap
|
||||
parts = soap.input.body.parts
|
||||
if len(parts):
|
||||
pts = []
|
||||
for p in ptop.input.parts:
|
||||
if p.name in parts:
|
||||
pts.append(p)
|
||||
soap.input.body.parts = pts
|
||||
else:
|
||||
soap.input.body.parts = ptop.input.parts
|
||||
parts = soap.output.body.parts
|
||||
if len(parts):
|
||||
pts = []
|
||||
for p in ptop.output.parts:
|
||||
if p.name in parts:
|
||||
pts.append(p)
|
||||
soap.output.body.parts = pts
|
||||
else:
|
||||
soap.output.body.parts = ptop.output.parts
|
||||
|
||||
def resolveheaders(self, definitions, op):
|
||||
"""
|
||||
Resolve soap header I{message} references.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
@param op: An I{operation} object.
|
||||
@type op: I{operation}
|
||||
"""
|
||||
soap = op.soap
|
||||
headers = soap.input.headers + soap.output.headers
|
||||
for header in headers:
|
||||
mn = header.message
|
||||
ref = qualify(mn, self.root, definitions.tns)
|
||||
message = definitions.messages.get(ref)
|
||||
if message is None:
|
||||
raise Exception, "message'%s', not-found" % mn
|
||||
pn = header.part
|
||||
for p in message.parts:
|
||||
if p.name == pn:
|
||||
header.part = p
|
||||
break
|
||||
if pn == header.part:
|
||||
raise Exception, \
|
||||
"message '%s' has not part named '%s'" % (ref, pn)
|
||||
|
||||
def resolvefaults(self, definitions, op):
|
||||
"""
|
||||
Resolve soap fault I{message} references by
|
||||
cross-referencing with operation defined in port type.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
@param op: An I{operation} object.
|
||||
@type op: I{operation}
|
||||
"""
|
||||
ptop = self.type.operation(op.name)
|
||||
if ptop is None:
|
||||
raise Exception, \
|
||||
"operation '%s' not defined in portType" % op.name
|
||||
soap = op.soap
|
||||
for fault in soap.faults:
|
||||
for f in ptop.faults:
|
||||
if f.name == fault.name:
|
||||
fault.parts = f.message.parts
|
||||
continue
|
||||
if hasattr(fault, 'parts'):
|
||||
continue
|
||||
raise Exception, \
|
||||
"fault '%s' not defined in portType '%s'" % (fault.name, self.type.name)
|
||||
|
||||
def operation(self, name):
|
||||
"""
|
||||
Shortcut used to get a contained operation by name.
|
||||
@param name: An operation name.
|
||||
@type name: str
|
||||
@return: The named operation.
|
||||
@rtype: Operation
|
||||
@raise L{MethodNotFound}: When not found.
|
||||
"""
|
||||
try:
|
||||
return self.operations[name]
|
||||
except:
|
||||
raise MethodNotFound(name)
|
||||
|
||||
def __gt__(self, other):
|
||||
return ( not isinstance(other, Service) )
|
||||
|
||||
|
||||
class Port(NamedObject):
|
||||
"""
|
||||
Represents a service port.
|
||||
@ivar service: A service.
|
||||
@type service: L{Service}
|
||||
@ivar binding: A binding name.
|
||||
@type binding: str
|
||||
@ivar location: The service location (url).
|
||||
@type location: str
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions, service):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
@param service: A service object.
|
||||
@type service: L{Service}
|
||||
"""
|
||||
NamedObject.__init__(self, root, definitions)
|
||||
self.__service = service
|
||||
self.binding = root.get('binding')
|
||||
address = root.getChild('address')
|
||||
if address is None:
|
||||
self.location = None
|
||||
else:
|
||||
self.location = address.get('location').encode('utf-8')
|
||||
self.methods = {}
|
||||
|
||||
def method(self, name):
|
||||
"""
|
||||
Get a method defined in this portType by name.
|
||||
@param name: A method name.
|
||||
@type name: str
|
||||
@return: The requested method object.
|
||||
@rtype: I{Method}
|
||||
"""
|
||||
return self.methods.get(name)
|
||||
|
||||
|
||||
class Service(NamedObject):
|
||||
"""
|
||||
Represents <service/>.
|
||||
@ivar port: The contained ports.
|
||||
@type port: [Port,..]
|
||||
@ivar methods: The contained methods for all ports.
|
||||
@type methods: [Method,..]
|
||||
"""
|
||||
|
||||
def __init__(self, root, definitions):
|
||||
"""
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
NamedObject.__init__(self, root, definitions)
|
||||
self.ports = []
|
||||
for p in root.getChildren('port'):
|
||||
port = Port(p, definitions, self)
|
||||
self.ports.append(port)
|
||||
|
||||
def port(self, name):
|
||||
"""
|
||||
Locate a port by name.
|
||||
@param name: A port name.
|
||||
@type name: str
|
||||
@return: The port object.
|
||||
@rtype: L{Port}
|
||||
"""
|
||||
for p in self.ports:
|
||||
if p.name == name:
|
||||
return p
|
||||
return None
|
||||
|
||||
def setlocation(self, url, names=None):
|
||||
"""
|
||||
Override the invocation location (url) for service method.
|
||||
@param url: A url location.
|
||||
@type url: A url.
|
||||
@param names: A list of method names. None=ALL
|
||||
@type names: [str,..]
|
||||
"""
|
||||
for p in self.ports:
|
||||
for m in p.methods.values():
|
||||
if names is None or m.name in names:
|
||||
m.location = url
|
||||
|
||||
def resolve(self, definitions):
|
||||
"""
|
||||
Resolve named references to other WSDL objects.
|
||||
Ports without soap bindings are discarded.
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
"""
|
||||
filtered = []
|
||||
for p in self.ports:
|
||||
ref = qualify(p.binding, self.root, definitions.tns)
|
||||
binding = definitions.bindings.get(ref)
|
||||
if binding is None:
|
||||
raise Exception("binding '%s', not-found" % p.binding)
|
||||
if binding.soap is None:
|
||||
log.debug('binding "%s" - not a soap, discarded', binding.name)
|
||||
continue
|
||||
p.binding = binding
|
||||
filtered.append(p)
|
||||
self.ports = filtered
|
||||
|
||||
def __gt__(self, other):
|
||||
return True
|
||||
|
||||
|
||||
class Factory:
|
||||
"""
|
||||
Simple WSDL object factory.
|
||||
@cvar tags: Dictionary of tag->constructor mappings.
|
||||
@type tags: dict
|
||||
"""
|
||||
|
||||
tags =\
|
||||
{
|
||||
'import' : Import,
|
||||
'types' : Types,
|
||||
'message' : Message,
|
||||
'portType' : PortType,
|
||||
'binding' : Binding,
|
||||
'service' : Service,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def create(cls, root, definitions):
|
||||
"""
|
||||
Create an object based on the root tag name.
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param definitions: A definitions object.
|
||||
@type definitions: L{Definitions}
|
||||
@return: The created object.
|
||||
@rtype: L{WObject}
|
||||
"""
|
||||
fn = cls.tags.get(root.name)
|
||||
if fn is not None:
|
||||
return fn(root, definitions)
|
||||
else:
|
||||
return None
|
||||
212
awx/lib/site-packages/suds/wsse.py
Normal file
212
awx/lib/site-packages/suds/wsse.py
Normal file
@ -0,0 +1,212 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{wsse} module provides WS-Security.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sudsobject import Object
|
||||
from suds.sax.element import Element
|
||||
from suds.sax.date import UTC
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
# Python 2.4 compatibility
|
||||
from md5 import md5
|
||||
|
||||
|
||||
dsns = \
|
||||
('ds',
|
||||
'http://www.w3.org/2000/09/xmldsig#')
|
||||
wssens = \
|
||||
('wsse',
|
||||
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd')
|
||||
wsuns = \
|
||||
('wsu',
|
||||
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd')
|
||||
wsencns = \
|
||||
('wsenc',
|
||||
'http://www.w3.org/2001/04/xmlenc#')
|
||||
|
||||
|
||||
class Security(Object):
|
||||
"""
|
||||
WS-Security object.
|
||||
@ivar tokens: A list of security tokens
|
||||
@type tokens: [L{Token},...]
|
||||
@ivar signatures: A list of signatures.
|
||||
@type signatures: TBD
|
||||
@ivar references: A list of references.
|
||||
@type references: TBD
|
||||
@ivar keys: A list of encryption keys.
|
||||
@type keys: TBD
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
""" """
|
||||
Object.__init__(self)
|
||||
self.mustUnderstand = True
|
||||
self.tokens = []
|
||||
self.signatures = []
|
||||
self.references = []
|
||||
self.keys = []
|
||||
|
||||
def xml(self):
|
||||
"""
|
||||
Get xml representation of the object.
|
||||
@return: The root node.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
root = Element('Security', ns=wssens)
|
||||
root.set('mustUnderstand', str(self.mustUnderstand).lower())
|
||||
for t in self.tokens:
|
||||
root.append(t.xml())
|
||||
return root
|
||||
|
||||
|
||||
class Token(Object):
|
||||
""" I{Abstract} security token. """
|
||||
|
||||
@classmethod
|
||||
def now(cls):
|
||||
return datetime.now()
|
||||
|
||||
@classmethod
|
||||
def utc(cls):
|
||||
return datetime.utcnow()
|
||||
|
||||
@classmethod
|
||||
def sysdate(cls):
|
||||
utc = UTC()
|
||||
return str(utc)
|
||||
|
||||
def __init__(self):
|
||||
Object.__init__(self)
|
||||
|
||||
|
||||
class UsernameToken(Token):
|
||||
"""
|
||||
Represents a basic I{UsernameToken} WS-Secuirty token.
|
||||
@ivar username: A username.
|
||||
@type username: str
|
||||
@ivar password: A password.
|
||||
@type password: str
|
||||
@ivar nonce: A set of bytes to prevent reply attacks.
|
||||
@type nonce: str
|
||||
@ivar created: The token created.
|
||||
@type created: L{datetime}
|
||||
"""
|
||||
|
||||
def __init__(self, username=None, password=None):
|
||||
"""
|
||||
@param username: A username.
|
||||
@type username: str
|
||||
@param password: A password.
|
||||
@type password: str
|
||||
"""
|
||||
Token.__init__(self)
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.nonce = None
|
||||
self.created = None
|
||||
|
||||
def setnonce(self, text=None):
|
||||
"""
|
||||
Set I{nonce} which is arbitraty set of bytes to prevent
|
||||
reply attacks.
|
||||
@param text: The nonce text value.
|
||||
Generated when I{None}.
|
||||
@type text: str
|
||||
"""
|
||||
if text is None:
|
||||
s = []
|
||||
s.append(self.username)
|
||||
s.append(self.password)
|
||||
s.append(Token.sysdate())
|
||||
m = md5()
|
||||
m.update(':'.join(s))
|
||||
self.nonce = m.hexdigest()
|
||||
else:
|
||||
self.nonce = text
|
||||
|
||||
def setcreated(self, dt=None):
|
||||
"""
|
||||
Set I{created}.
|
||||
@param dt: The created date & time.
|
||||
Set as datetime.utc() when I{None}.
|
||||
@type dt: L{datetime}
|
||||
"""
|
||||
if dt is None:
|
||||
self.created = Token.utc()
|
||||
else:
|
||||
self.created = dt
|
||||
|
||||
|
||||
def xml(self):
|
||||
"""
|
||||
Get xml representation of the object.
|
||||
@return: The root node.
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
root = Element('UsernameToken', ns=wssens)
|
||||
u = Element('Username', ns=wssens)
|
||||
u.setText(self.username)
|
||||
root.append(u)
|
||||
p = Element('Password', ns=wssens)
|
||||
p.setText(self.password)
|
||||
root.append(p)
|
||||
if self.nonce is not None:
|
||||
n = Element('Nonce', ns=wssens)
|
||||
n.setText(self.nonce)
|
||||
root.append(n)
|
||||
if self.created is not None:
|
||||
n = Element('Created', ns=wsuns)
|
||||
n.setText(str(UTC(self.created)))
|
||||
root.append(n)
|
||||
return root
|
||||
|
||||
|
||||
class Timestamp(Token):
|
||||
"""
|
||||
Represents the I{Timestamp} WS-Secuirty token.
|
||||
@ivar created: The token created.
|
||||
@type created: L{datetime}
|
||||
@ivar expires: The token expires.
|
||||
@type expires: L{datetime}
|
||||
"""
|
||||
|
||||
def __init__(self, validity=90):
|
||||
"""
|
||||
@param validity: The time in seconds.
|
||||
@type validity: int
|
||||
"""
|
||||
Token.__init__(self)
|
||||
self.created = Token.utc()
|
||||
self.expires = self.created + timedelta(seconds=validity)
|
||||
|
||||
def xml(self):
|
||||
root = Element("Timestamp", ns=wsuns)
|
||||
created = Element('Created', ns=wsuns)
|
||||
created.setText(str(UTC(self.created)))
|
||||
expires = Element('Expires', ns=wsuns)
|
||||
expires.setText(str(UTC(self.expires)))
|
||||
root.append(created)
|
||||
root.append(expires)
|
||||
return root
|
||||
86
awx/lib/site-packages/suds/xsd/__init__.py
Normal file
86
awx/lib/site-packages/suds/xsd/__init__.py
Normal file
@ -0,0 +1,86 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{schema} module provides a intelligent representation of
|
||||
an XSD schema. The I{raw} model is the XML tree and the I{model}
|
||||
is the denormalized, objectified and intelligent view of the schema.
|
||||
Most of the I{value-add} provided by the model is centered around
|
||||
tranparent referenced type resolution and targeted denormalization.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sax import Namespace, splitPrefix
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
def qualify(ref, resolvers, defns=Namespace.default):
|
||||
"""
|
||||
Get a reference that is I{qualified} by namespace.
|
||||
@param ref: A referenced schema type name.
|
||||
@type ref: str
|
||||
@param resolvers: A list of objects to be used to resolve types.
|
||||
@type resolvers: [L{sax.element.Element},]
|
||||
@param defns: An optional target namespace used to qualify references
|
||||
when no prefix is specified.
|
||||
@type defns: A default namespace I{tuple: (prefix,uri)} used when ref not prefixed.
|
||||
@return: A qualified reference.
|
||||
@rtype: (name, namespace-uri)
|
||||
"""
|
||||
ns = None
|
||||
p, n = splitPrefix(ref)
|
||||
if p is not None:
|
||||
if not isinstance(resolvers, (list, tuple)):
|
||||
resolvers = (resolvers,)
|
||||
for r in resolvers:
|
||||
resolved = r.resolvePrefix(p)
|
||||
if resolved[1] is not None:
|
||||
ns = resolved
|
||||
break
|
||||
if ns is None:
|
||||
raise Exception('prefix (%s) not resolved' % p)
|
||||
else:
|
||||
ns = defns
|
||||
return (n, ns[1])
|
||||
|
||||
def isqref(object):
|
||||
"""
|
||||
Get whether the object is a I{qualified reference}.
|
||||
@param object: An object to be tested.
|
||||
@type object: I{any}
|
||||
@rtype: boolean
|
||||
@see: L{qualify}
|
||||
"""
|
||||
return (\
|
||||
isinstance(object, tuple) and \
|
||||
len(object) == 2 and \
|
||||
isinstance(object[0], basestring) and \
|
||||
isinstance(object[1], basestring))
|
||||
|
||||
|
||||
class Filter:
|
||||
def __init__(self, inclusive=False, *items):
|
||||
self.inclusive = inclusive
|
||||
self.items = items
|
||||
def __contains__(self, x):
|
||||
if self.inclusive:
|
||||
result = ( x in self.items )
|
||||
else:
|
||||
result = ( x not in self.items )
|
||||
return result
|
||||
|
||||
140
awx/lib/site-packages/suds/xsd/deplist.py
Normal file
140
awx/lib/site-packages/suds/xsd/deplist.py
Normal file
@ -0,0 +1,140 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{depsolve} module defines a class for performing dependancy solving.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class DepList:
|
||||
"""
|
||||
Dependancy solving list.
|
||||
Items are tuples: (object, (deps,))
|
||||
@ivar raw: The raw (unsorted) items.
|
||||
@type raw: list
|
||||
@ivar index: The index of (unsorted) items.
|
||||
@type index: list
|
||||
@ivar stack: The sorting stack.
|
||||
@type stack: list
|
||||
@ivar pushed: The I{pushed} set tracks items that have been
|
||||
processed.
|
||||
@type pushed: set
|
||||
@ivar sorted: The sorted list of items.
|
||||
@type sorted: list
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
""" """
|
||||
self.unsorted = []
|
||||
self.index = {}
|
||||
self.stack = []
|
||||
self.pushed = set()
|
||||
self.sorted = None
|
||||
|
||||
def add(self, *items):
|
||||
"""
|
||||
Add items to be sorted.
|
||||
@param items: One or more items to be added.
|
||||
@type items: I{item}
|
||||
@return: self
|
||||
@rtype: L{DepList}
|
||||
"""
|
||||
for item in items:
|
||||
self.unsorted.append(item)
|
||||
key = item[0]
|
||||
self.index[key] = item
|
||||
return self
|
||||
|
||||
def sort(self):
|
||||
"""
|
||||
Sort the list based on dependancies.
|
||||
@return: The sorted items.
|
||||
@rtype: list
|
||||
"""
|
||||
self.sorted = list()
|
||||
self.pushed = set()
|
||||
for item in self.unsorted:
|
||||
popped = []
|
||||
self.push(item)
|
||||
while len(self.stack):
|
||||
try:
|
||||
top = self.top()
|
||||
ref = top[1].next()
|
||||
refd = self.index.get(ref)
|
||||
if refd is None:
|
||||
log.debug('"%s" not found, skipped', Repr(ref))
|
||||
continue
|
||||
self.push(refd)
|
||||
except StopIteration:
|
||||
popped.append(self.pop())
|
||||
continue
|
||||
for p in popped:
|
||||
self.sorted.append(p)
|
||||
self.unsorted = self.sorted
|
||||
return self.sorted
|
||||
|
||||
def top(self):
|
||||
"""
|
||||
Get the item at the top of the stack.
|
||||
@return: The top item.
|
||||
@rtype: (item, iter)
|
||||
"""
|
||||
return self.stack[-1]
|
||||
|
||||
def push(self, item):
|
||||
"""
|
||||
Push and item onto the sorting stack.
|
||||
@param item: An item to push.
|
||||
@type item: I{item}
|
||||
@return: The number of items pushed.
|
||||
@rtype: int
|
||||
"""
|
||||
if item in self.pushed:
|
||||
return
|
||||
frame = (item, iter(item[1]))
|
||||
self.stack.append(frame)
|
||||
self.pushed.add(item)
|
||||
|
||||
def pop(self):
|
||||
"""
|
||||
Pop the top item off the stack and append
|
||||
it to the sorted list.
|
||||
@return: The popped item.
|
||||
@rtype: I{item}
|
||||
"""
|
||||
try:
|
||||
frame = self.stack.pop()
|
||||
return frame[0]
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
a = ('a', ('x',))
|
||||
b = ('b', ('a',))
|
||||
c = ('c', ('a','b'))
|
||||
d = ('d', ('c',))
|
||||
e = ('e', ('d','a'))
|
||||
f = ('f', ('e','c','d','a'))
|
||||
x = ('x', ())
|
||||
L = DepList()
|
||||
L.add(c, e, d, b, f, a, x)
|
||||
print [x[0] for x in L.sort()]
|
||||
226
awx/lib/site-packages/suds/xsd/doctor.py
Normal file
226
awx/lib/site-packages/suds/xsd/doctor.py
Normal file
@ -0,0 +1,226 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{doctor} module provides classes for fixing broken (sick)
|
||||
schema(s).
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds.sax import splitPrefix, Namespace
|
||||
from suds.sax.element import Element
|
||||
from suds.plugin import DocumentPlugin, DocumentContext
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Doctor:
|
||||
"""
|
||||
Schema Doctor.
|
||||
"""
|
||||
def examine(self, root):
|
||||
"""
|
||||
Examine and repair the schema (if necessary).
|
||||
@param root: A schema root element.
|
||||
@type root: L{Element}
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Practice(Doctor):
|
||||
"""
|
||||
A collection of doctors.
|
||||
@ivar doctors: A list of doctors.
|
||||
@type doctors: list
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.doctors = []
|
||||
|
||||
def add(self, doctor):
|
||||
"""
|
||||
Add a doctor to the practice
|
||||
@param doctor: A doctor to add.
|
||||
@type doctor: L{Doctor}
|
||||
"""
|
||||
self.doctors.append(doctor)
|
||||
|
||||
def examine(self, root):
|
||||
for d in self.doctors:
|
||||
d.examine(root)
|
||||
return root
|
||||
|
||||
|
||||
class TnsFilter:
|
||||
"""
|
||||
Target Namespace filter.
|
||||
@ivar tns: A list of target namespaces.
|
||||
@type tns: [str,...]
|
||||
"""
|
||||
|
||||
def __init__(self, *tns):
|
||||
"""
|
||||
@param tns: A list of target namespaces.
|
||||
@type tns: [str,...]
|
||||
"""
|
||||
self.tns = []
|
||||
self.add(*tns)
|
||||
|
||||
def add(self, *tns):
|
||||
"""
|
||||
Add I{targetNamesapces} to be added.
|
||||
@param tns: A list of target namespaces.
|
||||
@type tns: [str,...]
|
||||
"""
|
||||
self.tns += tns
|
||||
|
||||
def match(self, root, ns):
|
||||
"""
|
||||
Match by I{targetNamespace} excluding those that
|
||||
are equal to the specified namespace to prevent
|
||||
adding an import to itself.
|
||||
@param root: A schema root.
|
||||
@type root: L{Element}
|
||||
"""
|
||||
tns = root.get('targetNamespace')
|
||||
if len(self.tns):
|
||||
matched = ( tns in self.tns )
|
||||
else:
|
||||
matched = 1
|
||||
itself = ( ns == tns )
|
||||
return ( matched and not itself )
|
||||
|
||||
|
||||
class Import:
|
||||
"""
|
||||
An <xs:import/> to be applied.
|
||||
@cvar xsdns: The XSD namespace.
|
||||
@type xsdns: (p,u)
|
||||
@ivar ns: An import namespace.
|
||||
@type ns: str
|
||||
@ivar location: An optional I{schemaLocation}.
|
||||
@type location: str
|
||||
@ivar filter: A filter used to restrict application to
|
||||
a particular schema.
|
||||
@type filter: L{TnsFilter}
|
||||
"""
|
||||
|
||||
xsdns = Namespace.xsdns
|
||||
|
||||
def __init__(self, ns, location=None):
|
||||
"""
|
||||
@param ns: An import namespace.
|
||||
@type ns: str
|
||||
@param location: An optional I{schemaLocation}.
|
||||
@type location: str
|
||||
"""
|
||||
self.ns = ns
|
||||
self.location = location
|
||||
self.filter = TnsFilter()
|
||||
|
||||
def setfilter(self, filter):
|
||||
"""
|
||||
Set the filter.
|
||||
@param filter: A filter to set.
|
||||
@type filter: L{TnsFilter}
|
||||
"""
|
||||
self.filter = filter
|
||||
|
||||
def apply(self, root):
|
||||
"""
|
||||
Apply the import (rule) to the specified schema.
|
||||
If the schema does not already contain an import for the
|
||||
I{namespace} specified here, it is added.
|
||||
@param root: A schema root.
|
||||
@type root: L{Element}
|
||||
"""
|
||||
if not self.filter.match(root, self.ns):
|
||||
return
|
||||
if self.exists(root):
|
||||
return
|
||||
node = Element('import', ns=self.xsdns)
|
||||
node.set('namespace', self.ns)
|
||||
if self.location is not None:
|
||||
node.set('schemaLocation', self.location)
|
||||
log.debug('inserting: %s', node)
|
||||
root.insert(node)
|
||||
|
||||
def add(self, root):
|
||||
"""
|
||||
Add an <xs:import/> to the specified schema root.
|
||||
@param root: A schema root.
|
||||
@type root: L{Element}
|
||||
"""
|
||||
node = Element('import', ns=self.xsdns)
|
||||
node.set('namespace', self.ns)
|
||||
if self.location is not None:
|
||||
node.set('schemaLocation', self.location)
|
||||
log.debug('%s inserted', node)
|
||||
root.insert(node)
|
||||
|
||||
def exists(self, root):
|
||||
"""
|
||||
Check to see if the <xs:import/> already exists
|
||||
in the specified schema root by matching I{namesapce}.
|
||||
@param root: A schema root.
|
||||
@type root: L{Element}
|
||||
"""
|
||||
for node in root.children:
|
||||
if node.name != 'import':
|
||||
continue
|
||||
ns = node.get('namespace')
|
||||
if self.ns == ns:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
class ImportDoctor(Doctor, DocumentPlugin):
|
||||
"""
|
||||
Doctor used to fix missing imports.
|
||||
@ivar imports: A list of imports to apply.
|
||||
@type imports: [L{Import},...]
|
||||
"""
|
||||
|
||||
def __init__(self, *imports):
|
||||
"""
|
||||
"""
|
||||
self.imports = []
|
||||
self.add(*imports)
|
||||
|
||||
def add(self, *imports):
|
||||
"""
|
||||
Add a namesapce to be checked.
|
||||
@param imports: A list of L{Import} objects.
|
||||
@type imports: [L{Import},..]
|
||||
"""
|
||||
self.imports += imports
|
||||
|
||||
def examine(self, node):
|
||||
for imp in self.imports:
|
||||
imp.apply(node)
|
||||
|
||||
def parsed(self, context):
|
||||
node = context.document
|
||||
# xsd root
|
||||
if node.name == 'schema' and Namespace.xsd(node.namespace()):
|
||||
self.examine(node)
|
||||
return
|
||||
# look deeper
|
||||
context = DocumentContext()
|
||||
for child in node:
|
||||
context.document = child
|
||||
self.parsed(context)
|
||||
|
||||
208
awx/lib/site-packages/suds/xsd/query.py
Normal file
208
awx/lib/site-packages/suds/xsd/query.py
Normal file
@ -0,0 +1,208 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{query} module defines a class for performing schema queries.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.sudsobject import *
|
||||
from suds.xsd import qualify, isqref
|
||||
from suds.xsd.sxbuiltin import Factory
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class Query(Object):
|
||||
"""
|
||||
Schema query base class.
|
||||
"""
|
||||
|
||||
def __init__(self, ref=None):
|
||||
"""
|
||||
@param ref: The schema reference being queried.
|
||||
@type ref: qref
|
||||
"""
|
||||
Object.__init__(self)
|
||||
self.id = objid(self)
|
||||
self.ref = ref
|
||||
self.history = []
|
||||
self.resolved = False
|
||||
if not isqref(self.ref):
|
||||
raise Exception('%s, must be qref' % tostr(self.ref))
|
||||
|
||||
def execute(self, schema):
|
||||
"""
|
||||
Execute this query using the specified schema.
|
||||
@param schema: The schema associated with the query. The schema
|
||||
is used by the query to search for items.
|
||||
@type schema: L{schema.Schema}
|
||||
@return: The item matching the search criteria.
|
||||
@rtype: L{sxbase.SchemaObject}
|
||||
"""
|
||||
raise Exception, 'not-implemented by subclass'
|
||||
|
||||
def filter(self, result):
|
||||
"""
|
||||
Filter the specified result based on query criteria.
|
||||
@param result: A potential result.
|
||||
@type result: L{sxbase.SchemaObject}
|
||||
@return: True if result should be excluded.
|
||||
@rtype: boolean
|
||||
"""
|
||||
if result is None:
|
||||
return True
|
||||
reject = ( result in self.history )
|
||||
if reject:
|
||||
log.debug('result %s, rejected by\n%s', Repr(result), self)
|
||||
return reject
|
||||
|
||||
def result(self, result):
|
||||
"""
|
||||
Query result post processing.
|
||||
@param result: A query result.
|
||||
@type result: L{sxbase.SchemaObject}
|
||||
"""
|
||||
if result is None:
|
||||
log.debug('%s, not-found', self.ref)
|
||||
return
|
||||
if self.resolved:
|
||||
result = result.resolve()
|
||||
log.debug('%s, found as: %s', self.ref, Repr(result))
|
||||
self.history.append(result)
|
||||
return result
|
||||
|
||||
|
||||
class BlindQuery(Query):
|
||||
"""
|
||||
Schema query class that I{blindly} searches for a reference in
|
||||
the specified schema. It may be used to find Elements and Types but
|
||||
will match on an Element first. This query will also find builtins.
|
||||
"""
|
||||
|
||||
def execute(self, schema):
|
||||
if schema.builtin(self.ref):
|
||||
name = self.ref[0]
|
||||
b = Factory.create(schema, name)
|
||||
log.debug('%s, found builtin (%s)', self.id, name)
|
||||
return b
|
||||
result = None
|
||||
for d in (schema.elements, schema.types):
|
||||
result = d.get(self.ref)
|
||||
if self.filter(result):
|
||||
result = None
|
||||
else:
|
||||
break
|
||||
if result is None:
|
||||
eq = ElementQuery(self.ref)
|
||||
eq.history = self.history
|
||||
result = eq.execute(schema)
|
||||
return self.result(result)
|
||||
|
||||
|
||||
class TypeQuery(Query):
|
||||
"""
|
||||
Schema query class that searches for Type references in
|
||||
the specified schema. Matches on root types only.
|
||||
"""
|
||||
|
||||
def execute(self, schema):
|
||||
if schema.builtin(self.ref):
|
||||
name = self.ref[0]
|
||||
b = Factory.create(schema, name)
|
||||
log.debug('%s, found builtin (%s)', self.id, name)
|
||||
return b
|
||||
result = schema.types.get(self.ref)
|
||||
if self.filter(result):
|
||||
result = None
|
||||
return self.result(result)
|
||||
|
||||
|
||||
class GroupQuery(Query):
|
||||
"""
|
||||
Schema query class that searches for Group references in
|
||||
the specified schema.
|
||||
"""
|
||||
|
||||
def execute(self, schema):
|
||||
result = schema.groups.get(self.ref)
|
||||
if self.filter(result):
|
||||
result = None
|
||||
return self.result(result)
|
||||
|
||||
|
||||
class AttrQuery(Query):
|
||||
"""
|
||||
Schema query class that searches for Attribute references in
|
||||
the specified schema. Matches on root Attribute by qname first, then searches
|
||||
deep into the document.
|
||||
"""
|
||||
|
||||
def execute(self, schema):
|
||||
result = schema.attributes.get(self.ref)
|
||||
if self.filter(result):
|
||||
result = self.__deepsearch(schema)
|
||||
return self.result(result)
|
||||
|
||||
def __deepsearch(self, schema):
|
||||
from suds.xsd.sxbasic import Attribute
|
||||
result = None
|
||||
for e in schema.all:
|
||||
result = e.find(self.ref, (Attribute,))
|
||||
if self.filter(result):
|
||||
result = None
|
||||
else:
|
||||
break
|
||||
return result
|
||||
|
||||
|
||||
class AttrGroupQuery(Query):
|
||||
"""
|
||||
Schema query class that searches for attributeGroup references in
|
||||
the specified schema.
|
||||
"""
|
||||
|
||||
def execute(self, schema):
|
||||
result = schema.agrps.get(self.ref)
|
||||
if self.filter(result):
|
||||
result = None
|
||||
return self.result(result)
|
||||
|
||||
|
||||
class ElementQuery(Query):
|
||||
"""
|
||||
Schema query class that searches for Element references in
|
||||
the specified schema. Matches on root Elements by qname first, then searches
|
||||
deep into the document.
|
||||
"""
|
||||
|
||||
def execute(self, schema):
|
||||
result = schema.elements.get(self.ref)
|
||||
if self.filter(result):
|
||||
result = self.__deepsearch(schema)
|
||||
return self.result(result)
|
||||
|
||||
def __deepsearch(self, schema):
|
||||
from suds.xsd.sxbasic import Element
|
||||
result = None
|
||||
for e in schema.all:
|
||||
result = e.find(self.ref, (Element,))
|
||||
if self.filter(result):
|
||||
result = None
|
||||
else:
|
||||
break
|
||||
return result
|
||||
422
awx/lib/site-packages/suds/xsd/schema.py
Normal file
422
awx/lib/site-packages/suds/xsd/schema.py
Normal file
@ -0,0 +1,422 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{schema} module provides a intelligent representation of
|
||||
an XSD schema. The I{raw} model is the XML tree and the I{model}
|
||||
is the denormalized, objectified and intelligent view of the schema.
|
||||
Most of the I{value-add} provided by the model is centered around
|
||||
tranparent referenced type resolution and targeted denormalization.
|
||||
"""
|
||||
|
||||
|
||||
import suds.metrics
|
||||
from suds import *
|
||||
from suds.xsd import *
|
||||
from suds.xsd.sxbuiltin import *
|
||||
from suds.xsd.sxbasic import Factory as BasicFactory
|
||||
from suds.xsd.sxbuiltin import Factory as BuiltinFactory
|
||||
from suds.xsd.sxbase import SchemaObject
|
||||
from suds.xsd.deplist import DepList
|
||||
from suds.sax.element import Element
|
||||
from suds.sax import splitPrefix, Namespace
|
||||
from logging import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class SchemaCollection:
|
||||
"""
|
||||
A collection of schema objects. This class is needed because WSDLs
|
||||
may contain more then one <schema/> node.
|
||||
@ivar wsdl: A wsdl object.
|
||||
@type wsdl: L{suds.wsdl.Definitions}
|
||||
@ivar children: A list contained schemas.
|
||||
@type children: [L{Schema},...]
|
||||
@ivar namespaces: A dictionary of contained schemas by namespace.
|
||||
@type namespaces: {str:L{Schema}}
|
||||
"""
|
||||
|
||||
def __init__(self, wsdl):
|
||||
"""
|
||||
@param wsdl: A wsdl object.
|
||||
@type wsdl: L{suds.wsdl.Definitions}
|
||||
"""
|
||||
self.wsdl = wsdl
|
||||
self.children = []
|
||||
self.namespaces = {}
|
||||
|
||||
def add(self, schema):
|
||||
"""
|
||||
Add a schema node to the collection. Schema(s) within the same target
|
||||
namespace are consolidated.
|
||||
@param schema: A schema object.
|
||||
@type schema: (L{Schema})
|
||||
"""
|
||||
key = schema.tns[1]
|
||||
existing = self.namespaces.get(key)
|
||||
if existing is None:
|
||||
self.children.append(schema)
|
||||
self.namespaces[key] = schema
|
||||
else:
|
||||
existing.root.children += schema.root.children
|
||||
existing.root.nsprefixes.update(schema.root.nsprefixes)
|
||||
|
||||
def load(self, options):
|
||||
"""
|
||||
Load the schema objects for the root nodes.
|
||||
- de-references schemas
|
||||
- merge schemas
|
||||
@param options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
@return: The merged schema.
|
||||
@rtype: L{Schema}
|
||||
"""
|
||||
if options.autoblend:
|
||||
self.autoblend()
|
||||
for child in self.children:
|
||||
child.build()
|
||||
for child in self.children:
|
||||
child.open_imports(options)
|
||||
for child in self.children:
|
||||
child.dereference()
|
||||
log.debug('loaded:\n%s', self)
|
||||
merged = self.merge()
|
||||
log.debug('MERGED:\n%s', merged)
|
||||
return merged
|
||||
|
||||
def autoblend(self):
|
||||
"""
|
||||
Ensure that all schemas within the collection
|
||||
import each other which has a blending effect.
|
||||
@return: self
|
||||
@rtype: L{SchemaCollection}
|
||||
"""
|
||||
namespaces = self.namespaces.keys()
|
||||
for s in self.children:
|
||||
for ns in namespaces:
|
||||
tns = s.root.get('targetNamespace')
|
||||
if tns == ns:
|
||||
continue
|
||||
for imp in s.root.getChildren('import'):
|
||||
if imp.get('namespace') == ns:
|
||||
continue
|
||||
imp = Element('import', ns=Namespace.xsdns)
|
||||
imp.set('namespace', ns)
|
||||
s.root.append(imp)
|
||||
return self
|
||||
|
||||
def locate(self, ns):
|
||||
"""
|
||||
Find a schema by namespace. Only the URI portion of
|
||||
the namespace is compared to each schema's I{targetNamespace}
|
||||
@param ns: A namespace.
|
||||
@type ns: (prefix,URI)
|
||||
@return: The schema matching the namesapce, else None.
|
||||
@rtype: L{Schema}
|
||||
"""
|
||||
return self.namespaces.get(ns[1])
|
||||
|
||||
def merge(self):
|
||||
"""
|
||||
Merge the contained schemas into one.
|
||||
@return: The merged schema.
|
||||
@rtype: L{Schema}
|
||||
"""
|
||||
if len(self):
|
||||
schema = self.children[0]
|
||||
for s in self.children[1:]:
|
||||
schema.merge(s)
|
||||
return schema
|
||||
else:
|
||||
return None
|
||||
|
||||
def __len__(self):
|
||||
return len(self.children)
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
result = ['\nschema collection']
|
||||
for s in self.children:
|
||||
result.append(s.str(1))
|
||||
return '\n'.join(result)
|
||||
|
||||
|
||||
class Schema:
|
||||
"""
|
||||
The schema is an objectification of a <schema/> (xsd) definition.
|
||||
It provides inspection, lookup and type resolution.
|
||||
@ivar root: The root node.
|
||||
@type root: L{sax.element.Element}
|
||||
@ivar baseurl: The I{base} URL for this schema.
|
||||
@type baseurl: str
|
||||
@ivar container: A schema collection containing this schema.
|
||||
@type container: L{SchemaCollection}
|
||||
@ivar children: A list of direct top level children.
|
||||
@type children: [L{SchemaObject},...]
|
||||
@ivar all: A list of all (includes imported) top level children.
|
||||
@type all: [L{SchemaObject},...]
|
||||
@ivar types: A schema types cache.
|
||||
@type types: {name:L{SchemaObject}}
|
||||
@ivar imports: A list of import objects.
|
||||
@type imports: [L{SchemaObject},...]
|
||||
@ivar elements: A list of <element/> objects.
|
||||
@type elements: [L{SchemaObject},...]
|
||||
@ivar attributes: A list of <attribute/> objects.
|
||||
@type attributes: [L{SchemaObject},...]
|
||||
@ivar groups: A list of group objects.
|
||||
@type groups: [L{SchemaObject},...]
|
||||
@ivar agrps: A list of attribute group objects.
|
||||
@type agrps: [L{SchemaObject},...]
|
||||
@ivar form_qualified: The flag indicating:
|
||||
(@elementFormDefault).
|
||||
@type form_qualified: bool
|
||||
"""
|
||||
|
||||
Tag = 'schema'
|
||||
|
||||
def __init__(self, root, baseurl, options, container=None):
|
||||
"""
|
||||
@param root: The xml root.
|
||||
@type root: L{sax.element.Element}
|
||||
@param baseurl: The base url used for importing.
|
||||
@type baseurl: basestring
|
||||
@param options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
@param container: An optional container.
|
||||
@type container: L{SchemaCollection}
|
||||
"""
|
||||
self.root = root
|
||||
self.id = objid(self)
|
||||
self.tns = self.mktns()
|
||||
self.baseurl = baseurl
|
||||
self.container = container
|
||||
self.children = []
|
||||
self.all = []
|
||||
self.types = {}
|
||||
self.imports = []
|
||||
self.elements = {}
|
||||
self.attributes = {}
|
||||
self.groups = {}
|
||||
self.agrps = {}
|
||||
if options.doctor is not None:
|
||||
options.doctor.examine(root)
|
||||
form = self.root.get('elementFormDefault')
|
||||
if form is None:
|
||||
self.form_qualified = False
|
||||
else:
|
||||
self.form_qualified = ( form == 'qualified' )
|
||||
if container is None:
|
||||
self.build()
|
||||
self.open_imports(options)
|
||||
log.debug('built:\n%s', self)
|
||||
self.dereference()
|
||||
log.debug('dereferenced:\n%s', self)
|
||||
|
||||
def mktns(self):
|
||||
"""
|
||||
Make the schema's target namespace.
|
||||
@return: The namespace representation of the schema's
|
||||
targetNamespace value.
|
||||
@rtype: (prefix, uri)
|
||||
"""
|
||||
tns = [None, self.root.get('targetNamespace')]
|
||||
if tns[1] is not None:
|
||||
tns[0] = self.root.findPrefix(tns[1])
|
||||
return tuple(tns)
|
||||
|
||||
def build(self):
|
||||
"""
|
||||
Build the schema (object graph) using the root node
|
||||
using the factory.
|
||||
- Build the graph.
|
||||
- Collate the children.
|
||||
"""
|
||||
self.children = BasicFactory.build(self.root, self)
|
||||
collated = BasicFactory.collate(self.children)
|
||||
self.children = collated[0]
|
||||
self.attributes = collated[2]
|
||||
self.imports = collated[1]
|
||||
self.elements = collated[3]
|
||||
self.types = collated[4]
|
||||
self.groups = collated[5]
|
||||
self.agrps = collated[6]
|
||||
|
||||
def merge(self, schema):
|
||||
"""
|
||||
Merge the contents from the schema. Only objects not already contained
|
||||
in this schema's collections are merged. This is to provide for bidirectional
|
||||
import which produce cyclic includes.
|
||||
@returns: self
|
||||
@rtype: L{Schema}
|
||||
"""
|
||||
for item in schema.attributes.items():
|
||||
if item[0] in self.attributes:
|
||||
continue
|
||||
self.all.append(item[1])
|
||||
self.attributes[item[0]] = item[1]
|
||||
for item in schema.elements.items():
|
||||
if item[0] in self.elements:
|
||||
continue
|
||||
self.all.append(item[1])
|
||||
self.elements[item[0]] = item[1]
|
||||
for item in schema.types.items():
|
||||
if item[0] in self.types:
|
||||
continue
|
||||
self.all.append(item[1])
|
||||
self.types[item[0]] = item[1]
|
||||
for item in schema.groups.items():
|
||||
if item[0] in self.groups:
|
||||
continue
|
||||
self.all.append(item[1])
|
||||
self.groups[item[0]] = item[1]
|
||||
for item in schema.agrps.items():
|
||||
if item[0] in self.agrps:
|
||||
continue
|
||||
self.all.append(item[1])
|
||||
self.agrps[item[0]] = item[1]
|
||||
schema.merged = True
|
||||
return self
|
||||
|
||||
def open_imports(self, options):
|
||||
"""
|
||||
Instruct all contained L{sxbasic.Import} children to import
|
||||
the schema's which they reference. The contents of the
|
||||
imported schema are I{merged} in.
|
||||
@param options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
"""
|
||||
for imp in self.imports:
|
||||
imported = imp.open(options)
|
||||
if imported is None:
|
||||
continue
|
||||
imported.open_imports(options)
|
||||
log.debug('imported:\n%s', imported)
|
||||
self.merge(imported)
|
||||
|
||||
def dereference(self):
|
||||
"""
|
||||
Instruct all children to perform dereferencing.
|
||||
"""
|
||||
all = []
|
||||
indexes = {}
|
||||
for child in self.children:
|
||||
child.content(all)
|
||||
deplist = DepList()
|
||||
for x in all:
|
||||
x.qualify()
|
||||
midx, deps = x.dependencies()
|
||||
item = (x, tuple(deps))
|
||||
deplist.add(item)
|
||||
indexes[x] = midx
|
||||
for x, deps in deplist.sort():
|
||||
midx = indexes.get(x)
|
||||
if midx is None: continue
|
||||
d = deps[midx]
|
||||
log.debug('(%s) merging %s <== %s', self.tns[1], Repr(x), Repr(d))
|
||||
x.merge(d)
|
||||
|
||||
def locate(self, ns):
|
||||
"""
|
||||
Find a schema by namespace. Only the URI portion of
|
||||
the namespace is compared to each schema's I{targetNamespace}.
|
||||
The request is passed to the container.
|
||||
@param ns: A namespace.
|
||||
@type ns: (prefix,URI)
|
||||
@return: The schema matching the namesapce, else None.
|
||||
@rtype: L{Schema}
|
||||
"""
|
||||
if self.container is not None:
|
||||
return self.container.locate(ns)
|
||||
else:
|
||||
return None
|
||||
|
||||
def custom(self, ref, context=None):
|
||||
"""
|
||||
Get whether the specified reference is B{not} an (xs) builtin.
|
||||
@param ref: A str or qref.
|
||||
@type ref: (str|qref)
|
||||
@return: True if B{not} a builtin, else False.
|
||||
@rtype: bool
|
||||
"""
|
||||
if ref is None:
|
||||
return True
|
||||
else:
|
||||
return ( not self.builtin(ref, context) )
|
||||
|
||||
def builtin(self, ref, context=None):
|
||||
"""
|
||||
Get whether the specified reference is an (xs) builtin.
|
||||
@param ref: A str or qref.
|
||||
@type ref: (str|qref)
|
||||
@return: True if builtin, else False.
|
||||
@rtype: bool
|
||||
"""
|
||||
w3 = 'http://www.w3.org'
|
||||
try:
|
||||
if isqref(ref):
|
||||
ns = ref[1]
|
||||
return ( ref[0] in Factory.tags and ns.startswith(w3) )
|
||||
if context is None:
|
||||
context = self.root
|
||||
prefix = splitPrefix(ref)[0]
|
||||
prefixes = context.findPrefixes(w3, 'startswith')
|
||||
return ( prefix in prefixes and ref[0] in Factory.tags )
|
||||
except:
|
||||
return False
|
||||
|
||||
def instance(self, root, baseurl, options):
|
||||
"""
|
||||
Create and return an new schema object using the
|
||||
specified I{root} and I{url}.
|
||||
@param root: A schema root node.
|
||||
@type root: L{sax.element.Element}
|
||||
@param baseurl: A base URL.
|
||||
@type baseurl: str
|
||||
@param options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
@return: The newly created schema object.
|
||||
@rtype: L{Schema}
|
||||
@note: This is only used by Import children.
|
||||
"""
|
||||
return Schema(root, baseurl, options)
|
||||
|
||||
def str(self, indent=0):
|
||||
tab = '%*s'%(indent*3, '')
|
||||
result = []
|
||||
result.append('%s%s' % (tab, self.id))
|
||||
result.append('%s(raw)' % tab)
|
||||
result.append(self.root.str(indent+1))
|
||||
result.append('%s(model)' % tab)
|
||||
for c in self.children:
|
||||
result.append(c.str(indent+1))
|
||||
result.append('')
|
||||
return '\n'.join(result)
|
||||
|
||||
def __repr__(self):
|
||||
myrep = '<%s tns="%s"/>' % (self.id, self.tns[1])
|
||||
return myrep.encode('utf-8')
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.str()
|
||||
|
||||
|
||||
|
||||
669
awx/lib/site-packages/suds/xsd/sxbase.py
Normal file
669
awx/lib/site-packages/suds/xsd/sxbase.py
Normal file
@ -0,0 +1,669 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{sxbase} module provides I{base} classes that represent
|
||||
schema objects.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.xsd import *
|
||||
from suds.sax.element import Element
|
||||
from suds.sax import Namespace
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class SchemaObject(object):
|
||||
"""
|
||||
A schema object is an extension to object object with
|
||||
with schema awareness.
|
||||
@ivar root: The XML root element.
|
||||
@type root: L{Element}
|
||||
@ivar schema: The schema containing this object.
|
||||
@type schema: L{schema.Schema}
|
||||
@ivar form_qualified: A flag that inidcates that @elementFormDefault
|
||||
has a value of I{qualified}.
|
||||
@type form_qualified: boolean
|
||||
@ivar nillable: A flag that inidcates that @nillable
|
||||
has a value of I{true}.
|
||||
@type nillable: boolean
|
||||
@ivar default: The default value.
|
||||
@type default: object
|
||||
@ivar rawchildren: A list raw of all children.
|
||||
@type rawchildren: [L{SchemaObject},...]
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def prepend(cls, d, s, filter=Filter()):
|
||||
"""
|
||||
Prepend schema object's from B{s}ource list to
|
||||
the B{d}estination list while applying the filter.
|
||||
@param d: The destination list.
|
||||
@type d: list
|
||||
@param s: The source list.
|
||||
@type s: list
|
||||
@param filter: A filter that allows items to be prepended.
|
||||
@type filter: L{Filter}
|
||||
"""
|
||||
i = 0
|
||||
for x in s:
|
||||
if x in filter:
|
||||
d.insert(i, x)
|
||||
i += 1
|
||||
|
||||
@classmethod
|
||||
def append(cls, d, s, filter=Filter()):
|
||||
"""
|
||||
Append schema object's from B{s}ource list to
|
||||
the B{d}estination list while applying the filter.
|
||||
@param d: The destination list.
|
||||
@type d: list
|
||||
@param s: The source list.
|
||||
@type s: list
|
||||
@param filter: A filter that allows items to be appended.
|
||||
@type filter: L{Filter}
|
||||
"""
|
||||
for item in s:
|
||||
if item in filter:
|
||||
d.append(item)
|
||||
|
||||
def __init__(self, schema, root):
|
||||
"""
|
||||
@param schema: The containing schema.
|
||||
@type schema: L{schema.Schema}
|
||||
@param root: The xml root node.
|
||||
@type root: L{Element}
|
||||
"""
|
||||
self.schema = schema
|
||||
self.root = root
|
||||
self.id = objid(self)
|
||||
self.name = root.get('name')
|
||||
self.qname = (self.name, schema.tns[1])
|
||||
self.min = root.get('minOccurs')
|
||||
self.max = root.get('maxOccurs')
|
||||
self.type = root.get('type')
|
||||
self.ref = root.get('ref')
|
||||
self.form_qualified = schema.form_qualified
|
||||
self.nillable = False
|
||||
self.default = root.get('default')
|
||||
self.rawchildren = []
|
||||
self.cache = {}
|
||||
|
||||
def attributes(self, filter=Filter()):
|
||||
"""
|
||||
Get only the attribute content.
|
||||
@param filter: A filter to constrain the result.
|
||||
@type filter: L{Filter}
|
||||
@return: A list of tuples (attr, ancestry)
|
||||
@rtype: [(L{SchemaObject}, [L{SchemaObject},..]),..]
|
||||
"""
|
||||
result = []
|
||||
for child, ancestry in self:
|
||||
if child.isattr() and child in filter:
|
||||
result.append((child, ancestry))
|
||||
return result
|
||||
|
||||
def children(self, filter=Filter()):
|
||||
"""
|
||||
Get only the I{direct} or non-attribute content.
|
||||
@param filter: A filter to constrain the result.
|
||||
@type filter: L{Filter}
|
||||
@return: A list tuples: (child, ancestry)
|
||||
@rtype: [(L{SchemaObject}, [L{SchemaObject},..]),..]
|
||||
"""
|
||||
result = []
|
||||
for child, ancestry in self:
|
||||
if not child.isattr() and child in filter:
|
||||
result.append((child, ancestry))
|
||||
return result
|
||||
|
||||
def get_attribute(self, name):
|
||||
"""
|
||||
Get (find) a I{non-attribute} attribute by name.
|
||||
@param name: A attribute name.
|
||||
@type name: str
|
||||
@return: A tuple: the requested (attribute, ancestry).
|
||||
@rtype: (L{SchemaObject}, [L{SchemaObject},..])
|
||||
"""
|
||||
for child, ancestry in self.attributes():
|
||||
if child.name == name:
|
||||
return (child, ancestry)
|
||||
return (None, [])
|
||||
|
||||
def get_child(self, name):
|
||||
"""
|
||||
Get (find) a I{non-attribute} child by name.
|
||||
@param name: A child name.
|
||||
@type name: str
|
||||
@return: A tuple: the requested (child, ancestry).
|
||||
@rtype: (L{SchemaObject}, [L{SchemaObject},..])
|
||||
"""
|
||||
for child, ancestry in self.children():
|
||||
if child.any() or child.name == name:
|
||||
return (child, ancestry)
|
||||
return (None, [])
|
||||
|
||||
def namespace(self, prefix=None):
|
||||
"""
|
||||
Get this properties namespace
|
||||
@param prefix: The default prefix.
|
||||
@type prefix: str
|
||||
@return: The schema's target namespace
|
||||
@rtype: (I{prefix},I{URI})
|
||||
"""
|
||||
ns = self.schema.tns
|
||||
if ns[0] is None:
|
||||
ns = (prefix, ns[1])
|
||||
return ns
|
||||
|
||||
def default_namespace(self):
|
||||
return self.root.defaultNamespace()
|
||||
|
||||
def unbounded(self):
|
||||
"""
|
||||
Get whether this node is unbounded I{(a collection)}
|
||||
@return: True if unbounded, else False.
|
||||
@rtype: boolean
|
||||
"""
|
||||
max = self.max
|
||||
if max is None:
|
||||
max = '1'
|
||||
if max.isdigit():
|
||||
return (int(max) > 1)
|
||||
else:
|
||||
return ( max == 'unbounded' )
|
||||
|
||||
def optional(self):
|
||||
"""
|
||||
Get whether this type is optional.
|
||||
@return: True if optional, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
min = self.min
|
||||
if min is None:
|
||||
min = '1'
|
||||
return ( min == '0' )
|
||||
|
||||
def required(self):
|
||||
"""
|
||||
Get whether this type is required.
|
||||
@return: True if required, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return ( not self.optional() )
|
||||
|
||||
|
||||
def resolve(self, nobuiltin=False):
|
||||
"""
|
||||
Resolve and return the nodes true self.
|
||||
@param nobuiltin: Flag indicates that resolution must
|
||||
not continue to include xsd builtins.
|
||||
@return: The resolved (true) type.
|
||||
@rtype: L{SchemaObject}
|
||||
"""
|
||||
return self.cache.get(nobuiltin, self)
|
||||
|
||||
def sequence(self):
|
||||
"""
|
||||
Get whether this is an <xs:sequence/>
|
||||
@return: True if <xs:sequence/>, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def xslist(self):
|
||||
"""
|
||||
Get whether this is an <xs:list/>
|
||||
@return: True if any, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def all(self):
|
||||
"""
|
||||
Get whether this is an <xs:all/>
|
||||
@return: True if any, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def choice(self):
|
||||
"""
|
||||
Get whether this is n <xs:choice/>
|
||||
@return: True if any, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def any(self):
|
||||
"""
|
||||
Get whether this is an <xs:any/>
|
||||
@return: True if any, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def builtin(self):
|
||||
"""
|
||||
Get whether this is a schema-instance (xs) type.
|
||||
@return: True if any, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def enum(self):
|
||||
"""
|
||||
Get whether this is a simple-type containing an enumeration.
|
||||
@return: True if any, else False
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def isattr(self):
|
||||
"""
|
||||
Get whether the object is a schema I{attribute} definition.
|
||||
@return: True if an attribute, else False.
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def extension(self):
|
||||
"""
|
||||
Get whether the object is an extension of another type.
|
||||
@return: True if an extension, else False.
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def restriction(self):
|
||||
"""
|
||||
Get whether the object is an restriction of another type.
|
||||
@return: True if an restriction, else False.
|
||||
@rtype: boolean
|
||||
"""
|
||||
return False
|
||||
|
||||
def mixed(self):
|
||||
"""
|
||||
Get whether this I{mixed} content.
|
||||
"""
|
||||
return False
|
||||
|
||||
def find(self, qref, classes=()):
|
||||
"""
|
||||
Find a referenced type in self or children.
|
||||
@param qref: A qualified reference.
|
||||
@type qref: qref
|
||||
@param classes: A list of classes used to qualify the match.
|
||||
@type classes: [I{class},...]
|
||||
@return: The referenced type.
|
||||
@rtype: L{SchemaObject}
|
||||
@see: L{qualify()}
|
||||
"""
|
||||
if not len(classes):
|
||||
classes = (self.__class__,)
|
||||
if self.qname == qref and self.__class__ in classes:
|
||||
return self
|
||||
for c in self.rawchildren:
|
||||
p = c.find(qref, classes)
|
||||
if p is not None:
|
||||
return p
|
||||
return None
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
"""
|
||||
Translate a value (type) to/from a python type.
|
||||
@param value: A value to translate.
|
||||
@return: The converted I{language} type.
|
||||
"""
|
||||
return value
|
||||
|
||||
def childtags(self):
|
||||
"""
|
||||
Get a list of valid child tag names.
|
||||
@return: A list of child tag names.
|
||||
@rtype: [str,...]
|
||||
"""
|
||||
return ()
|
||||
|
||||
def dependencies(self):
|
||||
"""
|
||||
Get a list of dependancies for dereferencing.
|
||||
@return: A merge dependancy index and a list of dependancies.
|
||||
@rtype: (int, [L{SchemaObject},...])
|
||||
"""
|
||||
return (None, [])
|
||||
|
||||
def autoqualified(self):
|
||||
"""
|
||||
The list of I{auto} qualified attribute values.
|
||||
Qualification means to convert values into I{qref}.
|
||||
@return: A list of attibute names.
|
||||
@rtype: list
|
||||
"""
|
||||
return ['type', 'ref']
|
||||
|
||||
def qualify(self):
|
||||
"""
|
||||
Convert attribute values, that are references to other
|
||||
objects, into I{qref}. Qualfied using default document namespace.
|
||||
Since many wsdls are written improperly: when the document does
|
||||
not define a default namespace, the schema target namespace is used
|
||||
to qualify references.
|
||||
"""
|
||||
defns = self.root.defaultNamespace()
|
||||
if Namespace.none(defns):
|
||||
defns = self.schema.tns
|
||||
for a in self.autoqualified():
|
||||
ref = getattr(self, a)
|
||||
if ref is None:
|
||||
continue
|
||||
if isqref(ref):
|
||||
continue
|
||||
qref = qualify(ref, self.root, defns)
|
||||
log.debug('%s, convert %s="%s" to %s', self.id, a, ref, qref)
|
||||
setattr(self, a, qref)
|
||||
|
||||
def merge(self, other):
|
||||
"""
|
||||
Merge another object as needed.
|
||||
"""
|
||||
other.qualify()
|
||||
for n in ('name',
|
||||
'qname',
|
||||
'min',
|
||||
'max',
|
||||
'default',
|
||||
'type',
|
||||
'nillable',
|
||||
'form_qualified',):
|
||||
if getattr(self, n) is not None:
|
||||
continue
|
||||
v = getattr(other, n)
|
||||
if v is None:
|
||||
continue
|
||||
setattr(self, n, v)
|
||||
|
||||
|
||||
def content(self, collection=None, filter=Filter(), history=None):
|
||||
"""
|
||||
Get a I{flattened} list of this nodes contents.
|
||||
@param collection: A list to fill.
|
||||
@type collection: list
|
||||
@param filter: A filter used to constrain the result.
|
||||
@type filter: L{Filter}
|
||||
@param history: The history list used to prevent cyclic dependency.
|
||||
@type history: list
|
||||
@return: The filled list.
|
||||
@rtype: list
|
||||
"""
|
||||
if collection is None:
|
||||
collection = []
|
||||
if history is None:
|
||||
history = []
|
||||
if self in history:
|
||||
return collection
|
||||
history.append(self)
|
||||
if self in filter:
|
||||
collection.append(self)
|
||||
for c in self.rawchildren:
|
||||
c.content(collection, filter, history[:])
|
||||
return collection
|
||||
|
||||
def str(self, indent=0, history=None):
|
||||
"""
|
||||
Get a string representation of this object.
|
||||
@param indent: The indent.
|
||||
@type indent: int
|
||||
@return: A string.
|
||||
@rtype: str
|
||||
"""
|
||||
if history is None:
|
||||
history = []
|
||||
if self in history:
|
||||
return '%s ...' % Repr(self)
|
||||
history.append(self)
|
||||
tab = '%*s'%(indent*3, '')
|
||||
result = []
|
||||
result.append('%s<%s' % (tab, self.id))
|
||||
for n in self.description():
|
||||
if not hasattr(self, n):
|
||||
continue
|
||||
v = getattr(self, n)
|
||||
if v is None:
|
||||
continue
|
||||
result.append(' %s="%s"' % (n, v))
|
||||
if len(self):
|
||||
result.append('>')
|
||||
for c in self.rawchildren:
|
||||
result.append('\n')
|
||||
result.append(c.str(indent+1, history[:]))
|
||||
if c.isattr():
|
||||
result.append('@')
|
||||
result.append('\n%s' % tab)
|
||||
result.append('</%s>' % self.__class__.__name__)
|
||||
else:
|
||||
result.append(' />')
|
||||
return ''.join(result)
|
||||
|
||||
def description(self):
|
||||
"""
|
||||
Get the names used for str() and repr() description.
|
||||
@return: A dictionary of relavent attributes.
|
||||
@rtype: [str,...]
|
||||
"""
|
||||
return ()
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.str())
|
||||
|
||||
def __repr__(self):
|
||||
s = []
|
||||
s.append('<%s' % self.id)
|
||||
for n in self.description():
|
||||
if not hasattr(self, n):
|
||||
continue
|
||||
v = getattr(self, n)
|
||||
if v is None:
|
||||
continue
|
||||
s.append(' %s="%s"' % (n, v))
|
||||
s.append(' />')
|
||||
myrep = ''.join(s)
|
||||
return myrep.encode('utf-8')
|
||||
|
||||
def __len__(self):
|
||||
n = 0
|
||||
for x in self: n += 1
|
||||
return n
|
||||
|
||||
def __iter__(self):
|
||||
return Iter(self)
|
||||
|
||||
def __getitem__(self, index):
|
||||
i = 0
|
||||
for c in self:
|
||||
if i == index:
|
||||
return c
|
||||
|
||||
|
||||
class Iter:
|
||||
"""
|
||||
The content iterator - used to iterate the L{Content} children. The iterator
|
||||
provides a I{view} of the children that is free of container elements
|
||||
such as <sequence/> and <choice/>.
|
||||
@ivar stack: A stack used to control nesting.
|
||||
@type stack: list
|
||||
"""
|
||||
|
||||
class Frame:
|
||||
""" A content iterator frame. """
|
||||
|
||||
def __init__(self, sx):
|
||||
"""
|
||||
@param sx: A schema object.
|
||||
@type sx: L{SchemaObject}
|
||||
"""
|
||||
self.sx = sx
|
||||
self.items = sx.rawchildren
|
||||
self.index = 0
|
||||
|
||||
def next(self):
|
||||
"""
|
||||
Get the I{next} item in the frame's collection.
|
||||
@return: The next item or None
|
||||
@rtype: L{SchemaObject}
|
||||
"""
|
||||
if self.index < len(self.items):
|
||||
result = self.items[self.index]
|
||||
self.index += 1
|
||||
return result
|
||||
|
||||
def __init__(self, sx):
|
||||
"""
|
||||
@param sx: A schema object.
|
||||
@type sx: L{SchemaObject}
|
||||
"""
|
||||
self.stack = []
|
||||
self.push(sx)
|
||||
|
||||
def push(self, sx):
|
||||
"""
|
||||
Create a frame and push the specified object.
|
||||
@param sx: A schema object to push.
|
||||
@type sx: L{SchemaObject}
|
||||
"""
|
||||
self.stack.append(Iter.Frame(sx))
|
||||
|
||||
def pop(self):
|
||||
"""
|
||||
Pop the I{top} frame.
|
||||
@return: The popped frame.
|
||||
@rtype: L{Frame}
|
||||
@raise StopIteration: when stack is empty.
|
||||
"""
|
||||
if len(self.stack):
|
||||
return self.stack.pop()
|
||||
else:
|
||||
raise StopIteration()
|
||||
|
||||
def top(self):
|
||||
"""
|
||||
Get the I{top} frame.
|
||||
@return: The top frame.
|
||||
@rtype: L{Frame}
|
||||
@raise StopIteration: when stack is empty.
|
||||
"""
|
||||
if len(self.stack):
|
||||
return self.stack[-1]
|
||||
else:
|
||||
raise StopIteration()
|
||||
|
||||
def next(self):
|
||||
"""
|
||||
Get the next item.
|
||||
@return: A tuple: the next (child, ancestry).
|
||||
@rtype: (L{SchemaObject}, [L{SchemaObject},..])
|
||||
@raise StopIteration: A the end.
|
||||
"""
|
||||
frame = self.top()
|
||||
while True:
|
||||
result = frame.next()
|
||||
if result is None:
|
||||
self.pop()
|
||||
return self.next()
|
||||
if isinstance(result, Content):
|
||||
ancestry = [f.sx for f in self.stack]
|
||||
return (result, ancestry)
|
||||
self.push(result)
|
||||
return self.next()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
|
||||
class XBuiltin(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:*/> node
|
||||
"""
|
||||
|
||||
def __init__(self, schema, name):
|
||||
"""
|
||||
@param schema: The containing schema.
|
||||
@type schema: L{schema.Schema}
|
||||
"""
|
||||
root = Element(name)
|
||||
SchemaObject.__init__(self, schema, root)
|
||||
self.name = name
|
||||
self.nillable = True
|
||||
|
||||
def namespace(self, prefix=None):
|
||||
return Namespace.xsdns
|
||||
|
||||
def builtin(self):
|
||||
return True
|
||||
|
||||
def resolve(self, nobuiltin=False):
|
||||
return self
|
||||
|
||||
|
||||
class Content(SchemaObject):
|
||||
"""
|
||||
This class represents those schema objects that represent
|
||||
real XML document content.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class NodeFinder:
|
||||
"""
|
||||
Find nodes based on flexable criteria. The I{matcher} is
|
||||
may be any object that implements a match(n) method.
|
||||
@ivar matcher: An object used as criteria for match.
|
||||
@type matcher: I{any}.match(n)
|
||||
@ivar limit: Limit the number of matches. 0=unlimited.
|
||||
@type limit: int
|
||||
"""
|
||||
def __init__(self, matcher, limit=0):
|
||||
"""
|
||||
@param matcher: An object used as criteria for match.
|
||||
@type matcher: I{any}.match(n)
|
||||
@param limit: Limit the number of matches. 0=unlimited.
|
||||
@type limit: int
|
||||
"""
|
||||
self.matcher = matcher
|
||||
self.limit = limit
|
||||
|
||||
def find(self, node, list):
|
||||
"""
|
||||
Traverse the tree looking for matches.
|
||||
@param node: A node to match on.
|
||||
@type node: L{SchemaObject}
|
||||
@param list: A list to fill.
|
||||
@type list: list
|
||||
"""
|
||||
if self.matcher.match(node):
|
||||
list.append(node)
|
||||
self.limit -= 1
|
||||
if self.limit == 0:
|
||||
return
|
||||
for c in node.rawchildren:
|
||||
self.find(c, list)
|
||||
return self
|
||||
825
awx/lib/site-packages/suds/xsd/sxbasic.py
Normal file
825
awx/lib/site-packages/suds/xsd/sxbasic.py
Normal file
@ -0,0 +1,825 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{sxbasic} module provides classes that represent
|
||||
I{basic} schema objects.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.xsd import *
|
||||
from suds.xsd.sxbase import *
|
||||
from suds.xsd.query import *
|
||||
from suds.sax import splitPrefix, Namespace
|
||||
from suds.transport import TransportError
|
||||
from suds.reader import DocumentReader
|
||||
from urlparse import urljoin
|
||||
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class RestrictionMatcher:
|
||||
"""
|
||||
For use with L{NodeFinder} to match restriction.
|
||||
"""
|
||||
def match(self, n):
|
||||
return isinstance(n, Restriction)
|
||||
|
||||
|
||||
class TypedContent(Content):
|
||||
"""
|
||||
Represents any I{typed} content.
|
||||
"""
|
||||
def resolve(self, nobuiltin=False):
|
||||
qref = self.qref()
|
||||
if qref is None:
|
||||
return self
|
||||
key = 'resolved:nb=%s' % nobuiltin
|
||||
cached = self.cache.get(key)
|
||||
if cached is not None:
|
||||
return cached
|
||||
result = self
|
||||
query = TypeQuery(qref)
|
||||
query.history = [self]
|
||||
log.debug('%s, resolving: %s\n using:%s', self.id, qref, query)
|
||||
resolved = query.execute(self.schema)
|
||||
if resolved is None:
|
||||
log.debug(self.schema)
|
||||
raise TypeNotFound(qref)
|
||||
self.cache[key] = resolved
|
||||
if resolved.builtin():
|
||||
if nobuiltin:
|
||||
result = self
|
||||
else:
|
||||
result = resolved
|
||||
else:
|
||||
result = resolved.resolve(nobuiltin)
|
||||
return result
|
||||
|
||||
def qref(self):
|
||||
"""
|
||||
Get the I{type} qualified reference to the referenced xsd type.
|
||||
This method takes into account simple types defined through
|
||||
restriction with are detected by determining that self is simple
|
||||
(len=0) and by finding a restriction child.
|
||||
@return: The I{type} qualified reference.
|
||||
@rtype: qref
|
||||
"""
|
||||
qref = self.type
|
||||
if qref is None and len(self) == 0:
|
||||
ls = []
|
||||
m = RestrictionMatcher()
|
||||
finder = NodeFinder(m, 1)
|
||||
finder.find(self, ls)
|
||||
if len(ls):
|
||||
return ls[0].ref
|
||||
return qref
|
||||
|
||||
|
||||
class Complex(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:complexType/> node.
|
||||
@cvar childtags: A list of valid child node names
|
||||
@type childtags: (I{str},...)
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return (
|
||||
'attribute',
|
||||
'attributeGroup',
|
||||
'sequence',
|
||||
'all',
|
||||
'choice',
|
||||
'complexContent',
|
||||
'simpleContent',
|
||||
'any',
|
||||
'group')
|
||||
|
||||
def description(self):
|
||||
return ('name',)
|
||||
|
||||
def extension(self):
|
||||
for c in self.rawchildren:
|
||||
if c.extension():
|
||||
return True
|
||||
return False
|
||||
|
||||
def mixed(self):
|
||||
for c in self.rawchildren:
|
||||
if isinstance(c, SimpleContent) and c.mixed():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Group(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:group/> node.
|
||||
@cvar childtags: A list of valid child node names
|
||||
@type childtags: (I{str},...)
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return ('sequence', 'all', 'choice')
|
||||
|
||||
def dependencies(self):
|
||||
deps = []
|
||||
midx = None
|
||||
if self.ref is not None:
|
||||
query = GroupQuery(self.ref)
|
||||
g = query.execute(self.schema)
|
||||
if g is None:
|
||||
log.debug(self.schema)
|
||||
raise TypeNotFound(self.ref)
|
||||
deps.append(g)
|
||||
midx = 0
|
||||
return (midx, deps)
|
||||
|
||||
def merge(self, other):
|
||||
SchemaObject.merge(self, other)
|
||||
self.rawchildren = other.rawchildren
|
||||
|
||||
def description(self):
|
||||
return ('name', 'ref',)
|
||||
|
||||
|
||||
class AttributeGroup(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:attributeGroup/> node.
|
||||
@cvar childtags: A list of valid child node names
|
||||
@type childtags: (I{str},...)
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return ('attribute', 'attributeGroup')
|
||||
|
||||
def dependencies(self):
|
||||
deps = []
|
||||
midx = None
|
||||
if self.ref is not None:
|
||||
query = AttrGroupQuery(self.ref)
|
||||
ag = query.execute(self.schema)
|
||||
if ag is None:
|
||||
log.debug(self.schema)
|
||||
raise TypeNotFound(self.ref)
|
||||
deps.append(ag)
|
||||
midx = 0
|
||||
return (midx, deps)
|
||||
|
||||
def merge(self, other):
|
||||
SchemaObject.merge(self, other)
|
||||
self.rawchildren = other.rawchildren
|
||||
|
||||
def description(self):
|
||||
return ('name', 'ref',)
|
||||
|
||||
|
||||
class Simple(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:simpleType/> node
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return ('restriction', 'any', 'list',)
|
||||
|
||||
def enum(self):
|
||||
for child, ancestry in self.children():
|
||||
if isinstance(child, Enumeration):
|
||||
return True
|
||||
return False
|
||||
|
||||
def mixed(self):
|
||||
return len(self)
|
||||
|
||||
def description(self):
|
||||
return ('name',)
|
||||
|
||||
def extension(self):
|
||||
for c in self.rawchildren:
|
||||
if c.extension():
|
||||
return True
|
||||
return False
|
||||
|
||||
def restriction(self):
|
||||
for c in self.rawchildren:
|
||||
if c.restriction():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class List(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:list/> node
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return ()
|
||||
|
||||
def description(self):
|
||||
return ('name',)
|
||||
|
||||
def xslist(self):
|
||||
return True
|
||||
|
||||
|
||||
class Restriction(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:restriction/> node
|
||||
"""
|
||||
|
||||
def __init__(self, schema, root):
|
||||
SchemaObject.__init__(self, schema, root)
|
||||
self.ref = root.get('base')
|
||||
|
||||
def childtags(self):
|
||||
return ('enumeration', 'attribute', 'attributeGroup')
|
||||
|
||||
def dependencies(self):
|
||||
deps = []
|
||||
midx = None
|
||||
if self.ref is not None:
|
||||
query = TypeQuery(self.ref)
|
||||
super = query.execute(self.schema)
|
||||
if super is None:
|
||||
log.debug(self.schema)
|
||||
raise TypeNotFound(self.ref)
|
||||
if not super.builtin():
|
||||
deps.append(super)
|
||||
midx = 0
|
||||
return (midx, deps)
|
||||
|
||||
def restriction(self):
|
||||
return True
|
||||
|
||||
def merge(self, other):
|
||||
SchemaObject.merge(self, other)
|
||||
filter = Filter(False, self.rawchildren)
|
||||
self.prepend(self.rawchildren, other.rawchildren, filter)
|
||||
|
||||
def description(self):
|
||||
return ('ref',)
|
||||
|
||||
|
||||
class Collection(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema collection node:
|
||||
- sequence
|
||||
- choice
|
||||
- all
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return ('element', 'sequence', 'all', 'choice', 'any', 'group')
|
||||
|
||||
|
||||
class Sequence(Collection):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:sequence/> node.
|
||||
"""
|
||||
def sequence(self):
|
||||
return True
|
||||
|
||||
|
||||
class All(Collection):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:all/> node.
|
||||
"""
|
||||
def all(self):
|
||||
return True
|
||||
|
||||
class Choice(Collection):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:choice/> node.
|
||||
"""
|
||||
def choice(self):
|
||||
return True
|
||||
|
||||
|
||||
class ComplexContent(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:complexContent/> node.
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return ('attribute', 'attributeGroup', 'extension', 'restriction')
|
||||
|
||||
def extension(self):
|
||||
for c in self.rawchildren:
|
||||
if c.extension():
|
||||
return True
|
||||
return False
|
||||
|
||||
def restriction(self):
|
||||
for c in self.rawchildren:
|
||||
if c.restriction():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class SimpleContent(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:simpleContent/> node.
|
||||
"""
|
||||
|
||||
def childtags(self):
|
||||
return ('extension', 'restriction')
|
||||
|
||||
def extension(self):
|
||||
for c in self.rawchildren:
|
||||
if c.extension():
|
||||
return True
|
||||
return False
|
||||
|
||||
def restriction(self):
|
||||
for c in self.rawchildren:
|
||||
if c.restriction():
|
||||
return True
|
||||
return False
|
||||
|
||||
def mixed(self):
|
||||
return len(self)
|
||||
|
||||
|
||||
class Enumeration(Content):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:enumeration/> node
|
||||
"""
|
||||
|
||||
def __init__(self, schema, root):
|
||||
Content.__init__(self, schema, root)
|
||||
self.name = root.get('value')
|
||||
|
||||
def enum(self):
|
||||
return True
|
||||
|
||||
|
||||
class Element(TypedContent):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:element/> node.
|
||||
"""
|
||||
|
||||
def __init__(self, schema, root):
|
||||
TypedContent.__init__(self, schema, root)
|
||||
a = root.get('form')
|
||||
if a is not None:
|
||||
self.form_qualified = ( a == 'qualified' )
|
||||
a = self.root.get('nillable')
|
||||
if a is not None:
|
||||
self.nillable = ( a in ('1', 'true') )
|
||||
self.implany()
|
||||
|
||||
def implany(self):
|
||||
"""
|
||||
Set the type as any when implicit.
|
||||
An implicit <xs:any/> is when an element has not
|
||||
body and no type defined.
|
||||
@return: self
|
||||
@rtype: L{Element}
|
||||
"""
|
||||
if self.type is None and \
|
||||
self.ref is None and \
|
||||
self.root.isempty():
|
||||
self.type = self.anytype()
|
||||
return self
|
||||
|
||||
def childtags(self):
|
||||
return ('attribute', 'simpleType', 'complexType', 'any',)
|
||||
|
||||
def extension(self):
|
||||
for c in self.rawchildren:
|
||||
if c.extension():
|
||||
return True
|
||||
return False
|
||||
|
||||
def restriction(self):
|
||||
for c in self.rawchildren:
|
||||
if c.restriction():
|
||||
return True
|
||||
return False
|
||||
|
||||
def dependencies(self):
|
||||
deps = []
|
||||
midx = None
|
||||
if self.ref is not None:
|
||||
query = ElementQuery(self.ref)
|
||||
e = query.execute(self.schema)
|
||||
if e is None:
|
||||
log.debug(self.schema)
|
||||
raise TypeNotFound(self.ref)
|
||||
deps.append(e)
|
||||
midx = 0
|
||||
return (midx, deps)
|
||||
|
||||
def merge(self, other):
|
||||
SchemaObject.merge(self, other)
|
||||
self.rawchildren = other.rawchildren
|
||||
|
||||
def description(self):
|
||||
return ('name', 'ref', 'type')
|
||||
|
||||
def anytype(self):
|
||||
""" create an xsd:anyType reference """
|
||||
p,u = Namespace.xsdns
|
||||
mp = self.root.findPrefix(u)
|
||||
if mp is None:
|
||||
mp = p
|
||||
self.root.addPrefix(p, u)
|
||||
return ':'.join((mp, 'anyType'))
|
||||
|
||||
|
||||
class Extension(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:extension/> node.
|
||||
"""
|
||||
|
||||
def __init__(self, schema, root):
|
||||
SchemaObject.__init__(self, schema, root)
|
||||
self.ref = root.get('base')
|
||||
|
||||
def childtags(self):
|
||||
return ('attribute',
|
||||
'attributeGroup',
|
||||
'sequence',
|
||||
'all',
|
||||
'choice',
|
||||
'group')
|
||||
|
||||
def dependencies(self):
|
||||
deps = []
|
||||
midx = None
|
||||
if self.ref is not None:
|
||||
query = TypeQuery(self.ref)
|
||||
super = query.execute(self.schema)
|
||||
if super is None:
|
||||
log.debug(self.schema)
|
||||
raise TypeNotFound(self.ref)
|
||||
if not super.builtin():
|
||||
deps.append(super)
|
||||
midx = 0
|
||||
return (midx, deps)
|
||||
|
||||
def merge(self, other):
|
||||
SchemaObject.merge(self, other)
|
||||
filter = Filter(False, self.rawchildren)
|
||||
self.prepend(self.rawchildren, other.rawchildren, filter)
|
||||
|
||||
def extension(self):
|
||||
return ( self.ref is not None )
|
||||
|
||||
def description(self):
|
||||
return ('ref',)
|
||||
|
||||
|
||||
class Import(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:import/> node
|
||||
@cvar locations: A dictionary of namespace locations.
|
||||
@type locations: dict
|
||||
@ivar ns: The imported namespace.
|
||||
@type ns: str
|
||||
@ivar location: The (optional) location.
|
||||
@type location: namespace-uri
|
||||
@ivar opened: Opened and I{imported} flag.
|
||||
@type opened: boolean
|
||||
"""
|
||||
|
||||
locations = {}
|
||||
|
||||
@classmethod
|
||||
def bind(cls, ns, location=None):
|
||||
"""
|
||||
Bind a namespace to a schema location (URI).
|
||||
This is used for imports that don't specify a schemaLocation.
|
||||
@param ns: A namespace-uri.
|
||||
@type ns: str
|
||||
@param location: The (optional) schema location for the
|
||||
namespace. (default=ns).
|
||||
@type location: str
|
||||
"""
|
||||
if location is None:
|
||||
location = ns
|
||||
cls.locations[ns] = location
|
||||
|
||||
def __init__(self, schema, root):
|
||||
SchemaObject.__init__(self, schema, root)
|
||||
self.ns = (None, root.get('namespace'))
|
||||
self.location = root.get('schemaLocation')
|
||||
if self.location is None:
|
||||
self.location = self.locations.get(self.ns[1])
|
||||
self.opened = False
|
||||
|
||||
def open(self, options):
|
||||
"""
|
||||
Open and import the refrenced schema.
|
||||
@param options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
@return: The referenced schema.
|
||||
@rtype: L{Schema}
|
||||
"""
|
||||
if self.opened:
|
||||
return
|
||||
self.opened = True
|
||||
log.debug('%s, importing ns="%s", location="%s"', self.id, self.ns[1], self.location)
|
||||
result = self.locate()
|
||||
if result is None:
|
||||
if self.location is None:
|
||||
log.debug('imported schema (%s) not-found', self.ns[1])
|
||||
else:
|
||||
result = self.download(options)
|
||||
log.debug('imported:\n%s', result)
|
||||
return result
|
||||
|
||||
def locate(self):
|
||||
""" find the schema locally """
|
||||
if self.ns[1] == self.schema.tns[1]:
|
||||
return None
|
||||
else:
|
||||
return self.schema.locate(self.ns)
|
||||
|
||||
def download(self, options):
|
||||
""" download the schema """
|
||||
url = self.location
|
||||
try:
|
||||
if '://' not in url:
|
||||
url = urljoin(self.schema.baseurl, url)
|
||||
reader = DocumentReader(options)
|
||||
d = reader.open(url)
|
||||
root = d.root()
|
||||
root.set('url', url)
|
||||
return self.schema.instance(root, url, options)
|
||||
except TransportError:
|
||||
msg = 'imported schema (%s) at (%s), failed' % (self.ns[1], url)
|
||||
log.error('%s, %s', self.id, msg, exc_info=True)
|
||||
raise Exception(msg)
|
||||
|
||||
def description(self):
|
||||
return ('ns', 'location')
|
||||
|
||||
|
||||
class Include(SchemaObject):
|
||||
"""
|
||||
Represents an (xsd) schema <xs:include/> node
|
||||
@ivar location: The (optional) location.
|
||||
@type location: namespace-uri
|
||||
@ivar opened: Opened and I{imported} flag.
|
||||
@type opened: boolean
|
||||
"""
|
||||
|
||||
locations = {}
|
||||
|
||||
def __init__(self, schema, root):
|
||||
SchemaObject.__init__(self, schema, root)
|
||||
self.location = root.get('schemaLocation')
|
||||
if self.location is None:
|
||||
self.location = self.locations.get(self.ns[1])
|
||||
self.opened = False
|
||||
|
||||
def open(self, options):
|
||||
"""
|
||||
Open and include the refrenced schema.
|
||||
@param options: An options dictionary.
|
||||
@type options: L{options.Options}
|
||||
@return: The referenced schema.
|
||||
@rtype: L{Schema}
|
||||
"""
|
||||
if self.opened:
|
||||
return
|
||||
self.opened = True
|
||||
log.debug('%s, including location="%s"', self.id, self.location)
|
||||
result = self.download(options)
|
||||
log.debug('included:\n%s', result)
|
||||
return result
|
||||
|
||||
def download(self, options):
|
||||
""" download the schema """
|
||||
url = self.location
|
||||
try:
|
||||
if '://' not in url:
|
||||
url = urljoin(self.schema.baseurl, url)
|
||||
reader = DocumentReader(options)
|
||||
d = reader.open(url)
|
||||
root = d.root()
|
||||
root.set('url', url)
|
||||
self.__applytns(root)
|
||||
return self.schema.instance(root, url, options)
|
||||
except TransportError:
|
||||
msg = 'include schema at (%s), failed' % url
|
||||
log.error('%s, %s', self.id, msg, exc_info=True)
|
||||
raise Exception(msg)
|
||||
|
||||
def __applytns(self, root):
|
||||
""" make sure included schema has same tns. """
|
||||
TNS = 'targetNamespace'
|
||||
tns = root.get(TNS)
|
||||
if tns is None:
|
||||
tns = self.schema.tns[1]
|
||||
root.set(TNS, tns)
|
||||
else:
|
||||
if self.schema.tns[1] != tns:
|
||||
raise Exception, '%s mismatch' % TNS
|
||||
|
||||
|
||||
def description(self):
|
||||
return ('location')
|
||||
|
||||
|
||||
class Attribute(TypedContent):
|
||||
"""
|
||||
Represents an (xsd) <attribute/> node
|
||||
"""
|
||||
|
||||
def __init__(self, schema, root):
|
||||
TypedContent.__init__(self, schema, root)
|
||||
self.use = root.get('use', default='')
|
||||
|
||||
def childtags(self):
|
||||
return ('restriction',)
|
||||
|
||||
def isattr(self):
|
||||
return True
|
||||
|
||||
def get_default(self):
|
||||
"""
|
||||
Gets the <xs:attribute default=""/> attribute value.
|
||||
@return: The default value for the attribute
|
||||
@rtype: str
|
||||
"""
|
||||
return self.root.get('default', default='')
|
||||
|
||||
def optional(self):
|
||||
return ( self.use != 'required' )
|
||||
|
||||
def dependencies(self):
|
||||
deps = []
|
||||
midx = None
|
||||
if self.ref is not None:
|
||||
query = AttrQuery(self.ref)
|
||||
a = query.execute(self.schema)
|
||||
if a is None:
|
||||
log.debug(self.schema)
|
||||
raise TypeNotFound(self.ref)
|
||||
deps.append(a)
|
||||
midx = 0
|
||||
return (midx, deps)
|
||||
|
||||
def description(self):
|
||||
return ('name', 'ref', 'type')
|
||||
|
||||
|
||||
class Any(Content):
|
||||
"""
|
||||
Represents an (xsd) <any/> node
|
||||
"""
|
||||
|
||||
def get_child(self, name):
|
||||
root = self.root.clone()
|
||||
root.set('note', 'synthesized (any) child')
|
||||
child = Any(self.schema, root)
|
||||
return (child, [])
|
||||
|
||||
def get_attribute(self, name):
|
||||
root = self.root.clone()
|
||||
root.set('note', 'synthesized (any) attribute')
|
||||
attribute = Any(self.schema, root)
|
||||
return (attribute, [])
|
||||
|
||||
def any(self):
|
||||
return True
|
||||
|
||||
|
||||
class Factory:
|
||||
"""
|
||||
@cvar tags: A factory to create object objects based on tag.
|
||||
@type tags: {tag:fn,}
|
||||
"""
|
||||
|
||||
tags =\
|
||||
{
|
||||
'import' : Import,
|
||||
'include' : Include,
|
||||
'complexType' : Complex,
|
||||
'group' : Group,
|
||||
'attributeGroup' : AttributeGroup,
|
||||
'simpleType' : Simple,
|
||||
'list' : List,
|
||||
'element' : Element,
|
||||
'attribute' : Attribute,
|
||||
'sequence' : Sequence,
|
||||
'all' : All,
|
||||
'choice' : Choice,
|
||||
'complexContent' : ComplexContent,
|
||||
'simpleContent' : SimpleContent,
|
||||
'restriction' : Restriction,
|
||||
'enumeration' : Enumeration,
|
||||
'extension' : Extension,
|
||||
'any' : Any,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def maptag(cls, tag, fn):
|
||||
"""
|
||||
Map (override) tag => I{class} mapping.
|
||||
@param tag: An xsd tag name.
|
||||
@type tag: str
|
||||
@param fn: A function or class.
|
||||
@type fn: fn|class.
|
||||
"""
|
||||
cls.tags[tag] = fn
|
||||
|
||||
@classmethod
|
||||
def create(cls, root, schema):
|
||||
"""
|
||||
Create an object based on the root tag name.
|
||||
@param root: An XML root element.
|
||||
@type root: L{Element}
|
||||
@param schema: A schema object.
|
||||
@type schema: L{schema.Schema}
|
||||
@return: The created object.
|
||||
@rtype: L{SchemaObject}
|
||||
"""
|
||||
fn = cls.tags.get(root.name)
|
||||
if fn is not None:
|
||||
return fn(schema, root)
|
||||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def build(cls, root, schema, filter=('*',)):
|
||||
"""
|
||||
Build an xsobject representation.
|
||||
@param root: An schema XML root.
|
||||
@type root: L{sax.element.Element}
|
||||
@param filter: A tag filter.
|
||||
@type filter: [str,...]
|
||||
@return: A schema object graph.
|
||||
@rtype: L{sxbase.SchemaObject}
|
||||
"""
|
||||
children = []
|
||||
for node in root.getChildren(ns=Namespace.xsdns):
|
||||
if '*' in filter or node.name in filter:
|
||||
child = cls.create(node, schema)
|
||||
if child is None:
|
||||
continue
|
||||
children.append(child)
|
||||
c = cls.build(node, schema, child.childtags())
|
||||
child.rawchildren = c
|
||||
return children
|
||||
|
||||
@classmethod
|
||||
def collate(cls, children):
|
||||
imports = []
|
||||
elements = {}
|
||||
attributes = {}
|
||||
types = {}
|
||||
groups = {}
|
||||
agrps = {}
|
||||
for c in children:
|
||||
if isinstance(c, (Import, Include)):
|
||||
imports.append(c)
|
||||
continue
|
||||
if isinstance(c, Attribute):
|
||||
attributes[c.qname] = c
|
||||
continue
|
||||
if isinstance(c, Element):
|
||||
elements[c.qname] = c
|
||||
continue
|
||||
if isinstance(c, Group):
|
||||
groups[c.qname] = c
|
||||
continue
|
||||
if isinstance(c, AttributeGroup):
|
||||
agrps[c.qname] = c
|
||||
continue
|
||||
types[c.qname] = c
|
||||
for i in imports:
|
||||
children.remove(i)
|
||||
return (children, imports, attributes, elements, types, groups, agrps)
|
||||
|
||||
|
||||
|
||||
|
||||
#######################################################
|
||||
# Static Import Bindings :-(
|
||||
#######################################################
|
||||
Import.bind(
|
||||
'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
'suds://schemas.xmlsoap.org/soap/encoding/')
|
||||
Import.bind(
|
||||
'http://www.w3.org/XML/1998/namespace',
|
||||
'http://www.w3.org/2001/xml.xsd')
|
||||
Import.bind(
|
||||
'http://www.w3.org/2001/XMLSchema',
|
||||
'http://www.w3.org/2001/XMLSchema.xsd')
|
||||
274
awx/lib/site-packages/suds/xsd/sxbuiltin.py
Normal file
274
awx/lib/site-packages/suds/xsd/sxbuiltin.py
Normal file
@ -0,0 +1,274 @@
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the (LGPL) GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Library Lesser General Public License for more details at
|
||||
# ( http://www.gnu.org/licenses/lgpl.html ).
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
# written by: Jeff Ortel ( jortel@redhat.com )
|
||||
|
||||
"""
|
||||
The I{sxbuiltin} module provides classes that represent
|
||||
XSD I{builtin} schema objects.
|
||||
"""
|
||||
|
||||
from logging import getLogger
|
||||
from suds import *
|
||||
from suds.xsd import *
|
||||
from suds.sax.date import *
|
||||
from suds.xsd.sxbase import XBuiltin
|
||||
import datetime as dt
|
||||
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class XString(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) <xs:string/> node
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class XAny(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) <any/> node
|
||||
"""
|
||||
|
||||
def __init__(self, schema, name):
|
||||
XBuiltin.__init__(self, schema, name)
|
||||
self.nillable = False
|
||||
|
||||
def get_child(self, name):
|
||||
child = XAny(self.schema, name)
|
||||
return (child, [])
|
||||
|
||||
def any(self):
|
||||
return True
|
||||
|
||||
|
||||
class XBoolean(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) boolean builtin type.
|
||||
"""
|
||||
|
||||
translation = (
|
||||
{ '1':True,'true':True,'0':False,'false':False },
|
||||
{ True:'true',1:'true',False:'false',0:'false' },
|
||||
)
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
if topython:
|
||||
if isinstance(value, basestring):
|
||||
return XBoolean.translation[0].get(value)
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(value, (bool,int)):
|
||||
return XBoolean.translation[1].get(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class XInteger(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) xs:int builtin type.
|
||||
"""
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
if topython:
|
||||
if isinstance(value, basestring) and len(value):
|
||||
return int(value)
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(value, int):
|
||||
return str(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
class XLong(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) xs:long builtin type.
|
||||
"""
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
if topython:
|
||||
if isinstance(value, basestring) and len(value):
|
||||
return long(value)
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(value, (int,long)):
|
||||
return str(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class XFloat(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) xs:float builtin type.
|
||||
"""
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
if topython:
|
||||
if isinstance(value, basestring) and len(value):
|
||||
return float(value)
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(value, float):
|
||||
return str(value)
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class XDate(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) xs:date builtin type.
|
||||
"""
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
if topython:
|
||||
if isinstance(value, basestring) and len(value):
|
||||
return Date(value).date
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(value, dt.date):
|
||||
return str(Date(value))
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class XTime(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) xs:time builtin type.
|
||||
"""
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
if topython:
|
||||
if isinstance(value, basestring) and len(value):
|
||||
return Time(value).time
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(value, dt.date):
|
||||
return str(Time(value))
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class XDateTime(XBuiltin):
|
||||
"""
|
||||
Represents an (xsd) xs:datetime builtin type.
|
||||
"""
|
||||
|
||||
def translate(self, value, topython=True):
|
||||
if topython:
|
||||
if isinstance(value, basestring) and len(value):
|
||||
return DateTime(value).datetime
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
if isinstance(value, dt.date):
|
||||
return str(DateTime(value))
|
||||
else:
|
||||
return value
|
||||
|
||||
|
||||
class Factory:
|
||||
|
||||
tags =\
|
||||
{
|
||||
# any
|
||||
'anyType' : XAny,
|
||||
# strings
|
||||
'string' : XString,
|
||||
'normalizedString' : XString,
|
||||
'ID' : XString,
|
||||
'Name' : XString,
|
||||
'QName' : XString,
|
||||
'NCName' : XString,
|
||||
'anySimpleType' : XString,
|
||||
'anyURI' : XString,
|
||||
'NOTATION' : XString,
|
||||
'token' : XString,
|
||||
'language' : XString,
|
||||
'IDREFS' : XString,
|
||||
'ENTITIES' : XString,
|
||||
'IDREF' : XString,
|
||||
'ENTITY' : XString,
|
||||
'NMTOKEN' : XString,
|
||||
'NMTOKENS' : XString,
|
||||
# binary
|
||||
'hexBinary' : XString,
|
||||
'base64Binary' : XString,
|
||||
# integers
|
||||
'int' : XInteger,
|
||||
'integer' : XInteger,
|
||||
'unsignedInt' : XInteger,
|
||||
'positiveInteger' : XInteger,
|
||||
'negativeInteger' : XInteger,
|
||||
'nonPositiveInteger' : XInteger,
|
||||
'nonNegativeInteger' : XInteger,
|
||||
# longs
|
||||
'long' : XLong,
|
||||
'unsignedLong' : XLong,
|
||||
# shorts
|
||||
'short' : XInteger,
|
||||
'unsignedShort' : XInteger,
|
||||
'byte' : XInteger,
|
||||
'unsignedByte' : XInteger,
|
||||
# floats
|
||||
'float' : XFloat,
|
||||
'double' : XFloat,
|
||||
'decimal' : XFloat,
|
||||
# dates & times
|
||||
'date' : XDate,
|
||||
'time' : XTime,
|
||||
'dateTime': XDateTime,
|
||||
'duration': XString,
|
||||
'gYearMonth' : XString,
|
||||
'gYear' : XString,
|
||||
'gMonthDay' : XString,
|
||||
'gDay' : XString,
|
||||
'gMonth' : XString,
|
||||
# boolean
|
||||
'boolean' : XBoolean,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def maptag(cls, tag, fn):
|
||||
"""
|
||||
Map (override) tag => I{class} mapping.
|
||||
@param tag: An xsd tag name.
|
||||
@type tag: str
|
||||
@param fn: A function or class.
|
||||
@type fn: fn|class.
|
||||
"""
|
||||
cls.tags[tag] = fn
|
||||
|
||||
@classmethod
|
||||
def create(cls, schema, name):
|
||||
"""
|
||||
Create an object based on the root tag name.
|
||||
@param schema: A schema object.
|
||||
@type schema: L{schema.Schema}
|
||||
@param name: The name.
|
||||
@type name: str
|
||||
@return: The created object.
|
||||
@rtype: L{XBuiltin}
|
||||
"""
|
||||
fn = cls.tags.get(name)
|
||||
if fn is not None:
|
||||
return fn(schema, name)
|
||||
else:
|
||||
return XBuiltin(schema, name)
|
||||
@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2014 AnsibleWorks, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
CLOUD_PROVIDERS = ('azure', 'ec2', 'gce', 'rax')
|
||||
CLOUD_PROVIDERS = ('azure', 'ec2', 'gce', 'rax', 'vmware')
|
||||
|
||||
@ -736,11 +736,12 @@ class InventorySourceOptions(BaseModel):
|
||||
'''
|
||||
|
||||
SOURCE_CHOICES = [
|
||||
('file', _('Local File, Directory or Script')),
|
||||
('rax', _('Rackspace Cloud Servers')),
|
||||
('ec2', _('Amazon EC2')),
|
||||
('gce', _('Google Compute Engine')),
|
||||
('azure', _('Windows Azure')),
|
||||
('file', _('Local File, Directory or Script')),
|
||||
('rax', _('Rackspace Cloud Servers')),
|
||||
('ec2', _('Amazon EC2')),
|
||||
('gce', _('Google Compute Engine')),
|
||||
('azure', _('Windows Azure')),
|
||||
('vmware', _('VMWare')),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
@ -839,6 +840,13 @@ class InventorySourceOptions(BaseModel):
|
||||
regions.insert(0, ('all', 'All'))
|
||||
return regions
|
||||
|
||||
@classmethod
|
||||
def get_vmware_region_choices(self):
|
||||
"""Return a complete list of regions in VMWare, as a list of two-tuples
|
||||
(but note that VMWare doesn't actually have regions!).
|
||||
"""
|
||||
return [('all', 'All')]
|
||||
|
||||
def clean_credential(self):
|
||||
if not self.source:
|
||||
return None
|
||||
|
||||
@ -512,6 +512,10 @@ class RunJob(BaseTask):
|
||||
elif cloud_cred and cloud_cred.kind == 'azure':
|
||||
env['AZURE_SUBSCRIPTION_ID'] = cloud_cred.username
|
||||
env['AZURE_CERT_PATH'] = kwargs['private_data_file']
|
||||
elif cloud_cred and cloud_cred.kind == 'vmware':
|
||||
env['VMWARE_USER'] = cloud_cred.username
|
||||
env['VMWARE_PASSWORD'] = decrypt_field(cloud_cred, 'password')
|
||||
env['VMWARE_HOST'] = cloud_cred.host
|
||||
|
||||
return env
|
||||
|
||||
|
||||
@ -1048,6 +1048,9 @@ class RunJobTest(BaseCeleryTest):
|
||||
elif kind == 'azure':
|
||||
env_var1 = 'AZURE_SUBSCRIPTION_ID'
|
||||
env_var2 = 'AZURE_CERT_PATH'
|
||||
elif kind == 'vmware':
|
||||
env_var1 = 'VMWARE_USER'
|
||||
env_var2 = 'VMWARE_PASSWORD'
|
||||
self.create_test_cloud_credential(name='%s cred' % kind, kind=kind,
|
||||
username='my %s access' % kind,
|
||||
password='my %s secret' % kind,
|
||||
@ -1077,6 +1080,9 @@ class RunJobTest(BaseCeleryTest):
|
||||
def test_azure_cloud_credential_environment_variables(self):
|
||||
self._test_cloud_credential_environment_variables('azure')
|
||||
|
||||
def test_vmware_cloud_credential_environment_variables(self):
|
||||
self._test_cloud_credential_environment_variables('vmware')
|
||||
|
||||
def test_run_async_job(self):
|
||||
self.create_test_project(TEST_ASYNC_OK_PLAYBOOK)
|
||||
job_template = self.create_test_job_template()
|
||||
|
||||
@ -31,6 +31,11 @@ except ImportError:
|
||||
|
||||
def save_cache(cache_item, data, config):
|
||||
''' saves item to cache '''
|
||||
|
||||
# Sanity check: Is caching enabled? If not, don't cache.
|
||||
if not config.has_option('defaults', 'cache_dir'):
|
||||
return
|
||||
|
||||
dpath = config.get('defaults', 'cache_dir')
|
||||
try:
|
||||
cache = open('/'.join([dpath,cache_item]), 'w')
|
||||
@ -42,6 +47,11 @@ def save_cache(cache_item, data, config):
|
||||
|
||||
def get_cache(cache_item, config):
|
||||
''' returns cached item '''
|
||||
|
||||
# Sanity check: Is caching enabled? If not, return None.
|
||||
if not config.has_option('defaults', 'cache_dir'):
|
||||
return
|
||||
|
||||
dpath = config.get('defaults', 'cache_dir')
|
||||
inv = {}
|
||||
try:
|
||||
@ -138,8 +148,8 @@ def get_inventory(client, config):
|
||||
for vm in host.vm:
|
||||
inv['all']['hosts'].append(vm.name)
|
||||
inv[vm_group].append(vm.name)
|
||||
if vm.tag:
|
||||
taggroup = 'vmware_' + vm.tag
|
||||
for tag in vm.tag:
|
||||
taggroup = 'vmware_' + tag.key.lower()
|
||||
if taggroup in inv:
|
||||
inv[taggroup].append(vm.name)
|
||||
else:
|
||||
@ -183,13 +193,15 @@ if __name__ == '__main__':
|
||||
config = ConfigParser.SafeConfigParser(
|
||||
defaults={'host': '', 'user': '', 'password': ''},
|
||||
)
|
||||
for section in ('auth', 'defaults'):
|
||||
config.add_section(section)
|
||||
for configfilename in [os.path.abspath(sys.argv[0]).rstrip('.py') + '.ini', 'vmware.ini']:
|
||||
if os.path.exists(configfilename):
|
||||
config.read(configfilename)
|
||||
break
|
||||
|
||||
try:
|
||||
client = Client(
|
||||
client = Client(
|
||||
os.environ.get('VMWARE_HOST', config.get('auth','host')),
|
||||
os.environ.get('VMWARE_USER', config.get('auth','user')),
|
||||
os.environ.get('VMWARE_PASSWORD', config.get('auth','password')),
|
||||
|
||||
@ -149,7 +149,11 @@ angular.module('CredentialFormDefinition', [])
|
||||
label: 'Host',
|
||||
type: 'text',
|
||||
ngShow: "kind.value == 'vmware'",
|
||||
autocomplete: false
|
||||
autocomplete: false,
|
||||
awRequiredWhen: {
|
||||
variable: 'host_required',
|
||||
init: false
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
labelBind: 'usernameLabel',
|
||||
@ -216,7 +220,11 @@ angular.module('CredentialFormDefinition', [])
|
||||
ask: false,
|
||||
clear: false,
|
||||
associated: 'password_confirm',
|
||||
autocomplete: false
|
||||
autocomplete: false,
|
||||
awRequiredWhen: {
|
||||
variable: "password_required",
|
||||
init: false
|
||||
}
|
||||
},
|
||||
"password_confirm": {
|
||||
label: 'Confirm Password',
|
||||
@ -226,7 +234,11 @@ angular.module('CredentialFormDefinition', [])
|
||||
editRequired: false,
|
||||
awPassMatch: true,
|
||||
associated: 'password',
|
||||
autocomplete: false
|
||||
autocomplete: false,
|
||||
awRequiredWhen: {
|
||||
variable: "password_required",
|
||||
init: false
|
||||
}
|
||||
},
|
||||
"ssh_password": {
|
||||
label: 'SSH Password',
|
||||
|
||||
@ -39,6 +39,9 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
scope.subscription_required = false;
|
||||
scope.key_description = "Paste the contents of the SSH private key file.<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>";
|
||||
scope.key_hint= "drag and drop an SSH private key file on the field below";
|
||||
scope.host_required = false;
|
||||
scope.password_required = false;
|
||||
|
||||
if (!Empty(scope.kind)) {
|
||||
// Apply kind specific settings
|
||||
switch (scope.kind.value) {
|
||||
@ -72,6 +75,11 @@ angular.module('CredentialsHelper', ['Utilities'])
|
||||
scope.key_description = "Paste the contents of the PEM file that corresponds to the certificate you uploaded in the Windows Azure console.<div class=\"popover-footer\"><span class=\"key\">esc</span> or click to close</div>";
|
||||
scope.key_hint= "drag and drop a management certificate file on the field below";
|
||||
break;
|
||||
case 'vmware':
|
||||
scope.username_required = true;
|
||||
scope.host_required = true;
|
||||
scope.password_required = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -252,8 +252,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', 'ListGenerator', '
|
||||
}]);
|
||||
$('#source_form').addClass('squeeze');
|
||||
}
|
||||
if (scope.source.value === 'rax' || scope.source.value === 'ec2'|| scope.source.value==='gce' || scope.source.value === 'azure') {
|
||||
kind = (scope.source.value === 'rax') ? 'rax' : (scope.source.value==='gce') ? 'gce' : (scope.source.value==='azure') ? 'azure' : 'aws';
|
||||
if (scope.source.value === 'rax' || scope.source.value === 'ec2'|| scope.source.value==='gce' || scope.source.value === 'azure' || scope.source.value === 'vmware') {
|
||||
kind = (scope.source.value === 'rax') ? 'rax' : (scope.source.value==='gce') ? 'gce' : (scope.source.value==='azure') ? 'azure' : (scope.source.value === 'vmware') ? 'vmware' : 'aws' ;
|
||||
url = GetBasePath('credentials') + '?cloud=true&kind=' + kind;
|
||||
LookUpInit({
|
||||
url: url,
|
||||
|
||||
BIN
requirements/psphere-0.5.2.tar.gz
Normal file
BIN
requirements/psphere-0.5.2.tar.gz
Normal file
Binary file not shown.
BIN
requirements/suds-0.4.tar.gz
Normal file
BIN
requirements/suds-0.4.tar.gz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user