Source code for pywbem_mock._instancewriteprovider

#
# (C) Copyright 2020 InovaDevelopment.com
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 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
# Lesser General Public License for more details.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# Author: Karl  Schopmeyer <inovadevelopment.com>
#

"""
The :class:`~pywbem_mock.InstanceWriteProvider` class provides the default
implementations of the ``CreateInstance``, ``ModifyInstance`` and
``DeleteInstance`` provider methods by means of
:meth:`~pywbem_mock.InstanceWriteProvider.CreateInstance`,
:meth:`~pywbem_mock.InstanceWriteProvider.ModifyInstance`, and
:meth:`~pywbem_mock.InstanceWriteProvider.DeleteInstance`.

A user-defined instance write provider may implement some or all of these
provider methods. The method descriptions linked above provide a detailed
definition of the input parameters, return values, and required behavior.

The following is a simple example of a user-defined instance write provider
that serves the 'CIM_Foo' and 'CIM_FooFoo' classes and implements
``CreateInstance`` for the purpose of setting a value for the 'InstanceID' key
property:

.. code-block:: python

    import uuid
    from pywbem_mock import InstanceWriteProvider

    class MyInstanceProvider(InstanceWriteProvider):

        # CIM classes served by this provider
        provider_classnames = ['CIM_Foo', 'CIM_FooFoo']

        def CreateInstance(self, namespace, new_instance):
            new_instance.properties["InstanceID"] = \\
                "{}.{}".format(new_instance.classname, uuid.uuid4())
            return super(MyInstanceProvider, self).CreateInstance(
                namespace, new_instance)

Because the provider in this example does not implement the
``ModifyInstance`` and ``DeleteInstance`` methods, these operations will
use their default implementations from
:class:`~pywbem_mock.InstanceWriteProvider`.

The provider in this example does not need to implement an ``__init__()``
method, because no additional init parameters are needed.
"""

from __future__ import absolute_import, print_function

from pywbem import CIMInstanceName, CIMError, \
    CIM_ERR_INVALID_PARAMETER, CIM_ERR_ALREADY_EXISTS

from pywbem._utils import _format

from ._baseprovider import BaseProvider

# None of the request method names conform since they are camel case
# pylint: disable=invalid-name

__all__ = ['InstanceWriteProvider']


[docs]class InstanceWriteProvider(BaseProvider): """ This class defines those instance provider methods that may have user- defined providers that override the default provider implementation in this class. User providers are defined by creating a subclass of this class and defining a new provider method for one of the methods in this class with the same signature. Note that user-defined providers may, in turn, call the default providers in this class. """ #: :term:`string`: Keyword defining the type of request the provider will #: service. The type for this provider class is predefined as 'instance'. provider_type = 'instance-write' def __init__(self, cimrepository=None): """ Parameters: cimrepository (:class:`~pywbem_mock.BaseRepository` or subclass): The CIM repository to be used by the provider. """ super(InstanceWriteProvider, self).__init__(cimrepository)
[docs] def CreateInstance(self, namespace, new_instance): """ Default provider method for :meth:`pywbem.WBEMConnection.CreateInstance`. Create a new CIM instance in the CIM repository of the mock WBEM server. Validation already performed by the provider dispatcher that calls this provider method: - The provider method is called only for the registered class and namespace (only applies to user-defined providers). - The Python types of all input parameters to this provider method are as specified below. - The namespace exists in the CIM repository. - The creation class of the new instance exists in the namespace in the CIM repository. - All properties specified in the new instance are exposed (i.e. defined and inherited with any overrides resolved) by the creation class in the CIM repository, and have the same type-related attributes (i.e. type, is_array, embedded_object). Validation that should be performed by this provider method: - new_instance does not specify any properties that are not allowed to be initialized by the client, depending on the model implemented by the provider. - new_instance specifies all key properties needed by the provider, depending on the model implemented by the provider. The CIM repository will reject any new instance that does not have all key properties specified. - The new instance (i.e. an instance with the new instance path) does not exist in the CIM repository. This validation needs to be done by the provider because the determination of the key properties for the new instance path may depend on the model implemented by the provider. The CIM repository will reject the creation of instances that already exist, so this check can be delegated to the repository once the new instance path has been determined. Parameters: namespace (:term:`string`): The name of the CIM namespace in which the CIM instance is to be created, in any lexical case, and with leading and trailing slash characters removed. new_instance (:class:`~pywbem.CIMInstance`): A representation of the CIM instance to be created. This object is a deep copy of the original client parameter, and may be modified by the provider as needed, before storing it in the CIM repository. The property names in this object have been adjusted to match the lexical case of the property definitions in the creation class of the instance in the CIM repository. The `classname` attribute of this object will specify the creation class for the new instance, in any lexical case. The `properties` attribute of this object will specify the initial property values for the new CIM instance, with property names in any lexical case. Key properties may or may not be included. The `path` attribute of this object will be `None`. The `qualifiers` attribute of this object, if non-empty, should be ignored by the provider, because instance-level qualifiers have been deprecated in CIM. Returns: :class:`~pywbem.CIMInstanceName`: Instance path of the new CIM instance. Raises: :exc:`~pywbem.CIMError`: The provider may raise CIMError with any status code, and typically raises: - CIM_ERR_INVALID_PARAMETER - CIM_ERR_ALREADY_EXISTS """ # Get the creation class with all exposed properties and qualifiers. # Since the existence of the class has already been verified, this # will always succeed. class_store = self.cimrepository.get_class_store(namespace) creation_class = class_store.get(new_instance.classname, copy=False) # This default provider determines the instance path from the key # properties in the new instance. A user-defined provider may do that # as well, or invent key properties such as InstanceID. # Specifying strict=True in from_instance() verifies that all key # properties exposed by the class are specified in the new instance, # and raises ValueError if key properties are missing. try: new_instance.path = CIMInstanceName.from_instance( creation_class, new_instance, namespace=namespace, strict=True) except ValueError as exc: raise CIMError(CIM_ERR_INVALID_PARAMETER, str(exc)) # Get the instance store of the CIM repository. Since the existence of # the namespace has already been verified, this will always succeed. instance_store = self.cimrepository.get_instance_store(namespace) # Store the new instance in the CIM repository, verifying that it does # not exist yet. try: instance_store.create(new_instance.path, new_instance) except ValueError: raise CIMError( CIM_ERR_ALREADY_EXISTS, _format("New instance {0!A} already exists in namespace " "{1!A}.", new_instance.path, namespace)) # CreateInstance returns the instance path of the new instance return new_instance.path
[docs] def ModifyInstance(self, modified_instance, IncludeQualifiers=None): # pylint: disable=invalid-name,line-too-long,unused-argument """ Default provider method for :meth:`pywbem.WBEMConnection.CreateInstance`. Modify an existing CIM instance in the CIM repository of the mock WBEM server. NOTE: This method specifies the namespace in modified_instance.path rather than as a separate input parameter. The modification of the instance in the CIM repository that is performed by the provider should be limited to property value changes (including addition of properties if not yet set on the instance), because instance-level qualifiers have been deprecated in CIM. The set of properties that are to be modified in the CIM instance has already been determined by the caller so that the modified_instance parameter specifies exactly the set of properties to be modified. Therefore, this provider method does not have a property list parameter. Validation already performed by the provider dispatcher that calls this provider method: - The provider method is called only for the registered class and namespace (only applies to user-defined providers). - The Python types of all input parameters to this provider method are as specified below. - The classnames in modified_instance are consistent between instance and instance path. - The namespace exists in the CIM repository. - The creation class of the instance to be modified exists in the namespace of the CIM repository. - The instance to be modified exists in the namespace of the CIM repository. - All properties in modified_instance that are to be modified are exposed (i.e. defined and inherited with any overrides resolved) by the creation class in the CIM repository, and have the same type-related attributes (i.e. type, is_array, embedded_object). - No key properties are requested to change their values. Validation that should be performed by this provider method: - modified_instance does not specify any changed values for properties that are not allowed to be changed by the client, depending on the model implemented by the provider. Parameters: modified_instance (:class:`~pywbem.CIMInstance`): A representation of the modified CIM instance, also indicating its instance path, with exactly the set of properties to be modified. This object is a deep copy of the original client parameter, and may be modified by the provider as needed, before storing it in the CIM repository. The `path` attribute of this object will be set and is the instance path of the instance to be modified in the CIM repository. Its `namespace`, `classname` and `keybindings` attributes will be set. The names will be in any lexical case. The `classname` attribute of this object will specify the creation class of the instance to be modified, in any lexical case. The `properties` attribute of this object will specify exactly the set of properties that are to be updated, taking into account the original ModifiedInstance and PropertyList input parameters of the ModifyInstance() client call. The lexical case of the property names has been adjusted to match the lexical cae of the property definitions in the creation class in the CIM repository. The `qualifiers` attribute of this object, if non-empty, should be ignored by the provider, because instance-level qualifiers have been deprecated in CIM. IncludeQualifiers (:class:`py:bool`): This parameter should be ignored by the provider, because instance-level qualifiers have been deprecated in CIM. Raises: :exc:`~pywbem.CIMError`: The provider may raise CIMError with any status code, and typically raises: - CIM_ERR_INVALID_PARAMETER """ # noqa: E501 # pylint: disable=invalid-name,line-too-long namespace = modified_instance.path.namespace # Get a copy of the instance to be modified from the CIM repository. instance_store = self.cimrepository.get_instance_store(namespace) instance = instance_store.get(modified_instance.path) # Modify the properties of the local instance copy. The implemented # approach is intentionally careful, to ensure that only the property # values get updated. for pn in modified_instance.properties: mod_prop = modified_instance.properties[pn] inst_prop = instance.properties[pn] inst_prop.value = mod_prop.value # Update the property value # Note that IncludeQualifiers is completely ignored. # Replace the instance in the CIM repository with the local copy. instance_store.update(modified_instance.path, instance)
[docs] def DeleteInstance(self, InstanceName): """ Default provider method for :meth:`pywbem.WBEMConnection.DeleteInstance`. Delete an existing instance in the CIM repository of the mock WBEM server. NOTE: This method specifies the namespace in InstanceName rather than as a separate input parameter. The provider is not responsible for determining other instances that depend on the instance to be deleted (e.g. association instances referencing the instance to be deleted); such dependency detection and handling is done elsewhere. Validation already performed by the provider dispatcher that calls this provider method: - The provider method is called only for the registered class and namespace (only applies to user-defined providers). - The Python types of all input parameters to this provider method are as specified below. - The namespace exists in the CIM repository. - The creation class of the instance to be deleted exists in the namespace of the CIM repository. - The instance to be deleted exists in the namespace of the CIM repository. Parameters: InstanceName (:class:`~pywbem.CIMInstanceName`): The instance path of the instance to be deleted with the following attributes: * `classname`: Name of the creation class of the instance. * `keybindings`: Keybindings of the instance. * `namespace`: Name of the CIM namespace containing the instance. Will not be `None`. * `host`: Will be `None`. Raises: None """ namespace = InstanceName.namespace instance_store = self.cimrepository.get_instance_store(namespace) # Delete the instance from the CIM repository instance_store.delete(InstanceName)
[docs] def post_register_setup(self, conn): """ Method called by provider registration after registation of provider is successful. Using this method is optional for registration cases where the provider must execute some activity (ex. modify the CIM repository after successful provider registration). Override this method in the user-defined provider subclass to execute this method. Parameters: conn (:class:`~pywbem.WBEMConnection`): Current connection which allows client methods to be executed from within this method. """