Skip to content

Latest commit

 

History

History
1248 lines (899 loc) · 45.6 KB

mockwbemserver.rst

File metadata and controls

1248 lines (899 loc) · 45.6 KB

Mock WBEM server

Experimental: New in pywbem 0.12.0 as experimental.

Overview

The 'pywbem_mock' module of pywbem provides a mock WBEM server that enables using the pywbem client library without a real WBEM server. This is useful for testing the pywbem client library itself as well as for the development and testing of Python programs that use the pywbem client library.

The pywbem_mock.FakedWBEMConnection class establishes an in-process mock WBEM server and represents a faked connection to that mock WBEM server. That class acts as both the client API and as an API for managing the mocked WBEM server.

The pywbem_mock.FakedWBEMConnection class is a subclass of pywbem.WBEMConnection and replaces its internal methods that use HTTP/HTTPS to communicate with a WBEM server with methods that communicate with the mock WBEM server. As a result, the operation methods of ~pywbem_mock.FakedWBEMConnection are those inherited from ~pywbem.WBEMConnection, so they have exactly the same input parameters, output parameters, return values, and even most of the raised exceptions, as when invoked on a ~pywbem.WBEMConnection object against a real WBEM server.

The mock WBEM server has an in-memory repository of CIM objects (the CIM repository). Each ~pywbem_mock.FakedWBEMConnection object creates its own CIM repository that contains the same kinds of CIM objects a WBEM server repository contains: CIM classes, CIM instances, and CIM qualifier declarations types, contained in CIM namespaces. Because ~pywbem_mock.FakedWBEMConnection operates only on the CIM repository, the class does not have any connection- or security-related constructor parameters.

Like ~pywbem.WBEMConnection, ~pywbem_mock.FakedWBEMConnection has a default CIM namespace that is created in the CIM repository upon ~pywbem_mock.FakedWBEMConnection object creation. Additional namespaces in the CIM repository can be created with ~pywbem_mock.FakedWBEMConnection.add_namespace() .

The CIM repository must contain the CIM classes, CIM instances and CIM qualifier declaration types that are needed for the operations that are invoked. This results in a behavior of the mock WBEM server that is close to the behavior of the operations of a real WBEM server. ~pywbem_mock.FakedWBEMConnection has methods that provide for adding CIM classes, instances and qualifier types to its CIM repository by providing them as CIM objects <CIM object>, or by compiling MOF. See Building a mocked CIM repository for details.

The following example demonstrates setting up a mock WBEM server, adding several CIM objects defined in a MOF string to its CIM repository, and executing WBEM operations on the faked connection:

import pywbem
import pywbem_mock

# MOF string defining qualifiers, class, and instance
mof = '''
    Qualifier Key : boolean = false,
        Scope(property, reference),
        Flavor(DisableOverride, ToSubclass);
    Qualifier Description : string = null,
        Scope(any),
        Flavor(EnableOverride, ToSubclass, Translatable);
    Qualifier In : boolean = true,
        Scope(parameter),
        Flavor(DisableOverride, ToSubclass);

        [Description ("This is a dumb test class")]
    class CIM_Foo {
            [Key, Description ("This is key prop")]
        string InstanceID;
            [Description ("This is some simplistic data")]
        Uint32 SomeData;
            [Description ("This is a method without parameters")]
        string Fuzzy();
            [Description ("This is a second method with parameter")]
        uint32 Delete([IN, Description('blahblah']
          boolean Immediate);
    };

    instance of CIM_Foo as $I1 { InstanceID = "I1"; SomeData=3 };
    '''

# Create a faked connection including a mock WBEM server with a CIM repo
conn = pywbem_mock.FakedWBEMConnection(default_namespace='root/cimv2')

# Compile the MOF string and add its CIM objects to the default namespace
# of the CIM repository
conn.compile_mof_string(mof)

# Perform a few operations on the faked connection:

# Enumerate top-level classes in the default namespace (without subclasses)
classes = conn.EnumerateClasses();
for cls in classes:
    print(cls.tomof())

# Get the 'Description' qualifier type in the default namespace
qd = conn.GetQualifier('Description')

# Enumerate subclasses of 'CIM_Foo' in the default namespace (without subclasses)
classes2 = conn.EnumerateClasses(classname='CIM_Foo')

# Get 'CIM_Foo' class in the default namespace
my_class = conn.GetClass('CIM_Foo')

# Get a specific instance of 'CIM_Foo' in the default namespace
inst = conn.GetInstance(CIMInstanceName('CIM_Foo', {'InstanceID': "I1"})

The mock WBEM server supports:

  1. All of the ~pywbem.WBEMConnection operation methods that communicate with the WBEM server (see below for the operations supported and their limitations).
  2. Multiple CIM namespaces and a default namespace on the faked connection.
  3. Gathering time statistics and delaying responses for a predetermined time.
  4. ~pywbem.WBEMConnection logging except that there are no HTTP entries in the log.
  5. User-defined providers that replace the the default providers specific request methods, CIM classes, and namespaces. See User-defined providers.

The mock WBEM server does NOT support:

  1. CIM-XML protocol security and security constructor parameters of ~pywbem.WBEMConnection.
  2. Processing of queries defined for ~pywbem.WBEMConnection.ExecQuery in languages like CQL and WQL. The mocked operation parses only the very general portions of the query for class/instance name and properties.
  3. Filter processing of FQL (see DSP0212) the Filter Query Language parameter QueryFilter used by the Open... operations because it does not implement the parser/processor for the FQL language. It returns the same data as if the filter did not exist.
  4. Providing data in the trace variables for last request and last reply in ~pywbem.WBEMConnection: last_request, last_raw_request, last_reply, last_raw_reply, last_request_len, or last_reply_len.
  5. Log entries for HTTP request and response in the logging support of ~pywbem.WBEMConnection, because it does not actually build the HTTP requests or responses.
  6. Generating CIM indications.
  7. Some of the functionality that may be implemented in real WBEM servers such as the __Namespace__ class/provider. Note that such capabilities can be at least partly built on top of the existing capabilities by implementing user-defined providers. Thus the CIM_Namespace class is supported with the user defined provider in the pywbem_mock directory but only registered if the user wants to use the provider.
+----------------------------------+
|                                  |
| +------------------------------+ |           +-------------+
| |                              | |           |             |
| | WBEM Server Mock Methods     | |           | Main        |
| |                              | |           | Provider    |
| |            All other Requests+------------>+             |
| |  CreateInstance, ModifyInst  +------+      | Class ,assoc|
| |  DeleteInstance, InvokeMeth  | |    |      | some inst   |
| +------------^-----------------+ |    |      | requests    +--+
|              |                   |    |      +-------------+  |
| +------------+-----------------+ |    |                       |
| | WBEM Server Mock Interface   | |    |      +-------------+  |     +-----------+
| |                              | |    |      |             |  |     | Instance  |
| +------------^-----------------+ |    |      | Provider    |  |     | Write     |
|              |                   |    |      | Dispatcher  |  |     | Provider  |
|              |                   |    |      |             +------->+ (Default) |
|              |                   |    |      | Dispatches  |  |     +-|---|-----+       +----------+
| +------------+-----------------+ |    |      | methods to  |  | +-----|   |-------------+ User     |
| |                              | |    +----->+ default or  +----------------------------> Instance |
| |  Client API request methods  | |           | registered  |  | |                       | Providers|
| |  from WBEM Connection        | |           | user        |  | |   +------------+      |          +-----+
| |                              | |           | providers   |  | |   |            |      +----------+     |
| |   *CreateClass, etc.         | |           |             +------->+ Method     |                       |
---> | | | | | | | Provider | |
| | | | | | | | (Default) | |
| | | +-----------+-+ | | +-----
+------------------------------+ | | | |
+------------------------------+ | +-------------------------------> User | |
| Mock Environment management | | | | | Method | |
| methods | | | | | Providers |
| * Mof Compiler, add objects | | | | | | |
| * Manage namespaces | | | | +---------+ |
| * Register user providers +---------+ +---------------v-V----------------------------------+ |
+------------------------------+ | | | | |
 FakedWBEMConnection | +----> CIM Repository <-----+
+----------------------------------+ | |

+----------------------------------------------------+

Diagram of flow of requests operations through mocker

WBEM operations of a mock WBEM server

The pywbem_mock.FakedWBEMConnection class supports the same WBEM operations that are supported by the pywbem.WBEMConnection class and in addition a set of methods for setting up its mocked CIM repository, and for registering user-defined providers for selected WBEM operations.

These faked WBEM operations generally adhere to the behavior requirements defined in DSP0200 for handling input parameters and returning a result.

The faked WBEM operations get the data to be returned from the CIM repository of the mock WBEM server, and put the data provided in operation parameters that modify objects (create, modify, and delete operations) into the CIM repository.

However, because the pywbem mock support is only a simulation of a WBEM server and intended to be used primarily for testing, there are limitations and differences between the behavior of the faked WBEM operations and a real WBEM server.

The descriptions below describe differences between the faked WBEM operations of the pywbem mock support and the operations of a real WBEM server, and the effects of the operation modes of the CIM repository.

Faked instance operations

The operations that retrieve instances require instances in the repository for the instances to be recovered and that the classes for these instances exist in the repository.

  • GetInstance: Behaves like ~pywbem.WBEMConnection.GetInstance. Returns an instance defined by the instance name input parameter if that instance exists in the repository.
  • EnumerateInstances: Behaves like ~pywbem.WBEMConnection.EnumerateInstances, returning all instances of the CIM class defined on input and subclasses of this class filtered by the optional attributes for property names, etc.
  • EnumerateInstanceNames: Behaves like ~pywbem.WBEMConnection.EnumerateInstances, Returns the instance name of all instances of the pywbem.CIMClass defined on input and subclasses of this class.
  • CreateInstance: Behaves like ~pywbem.WBEMConnection.CreateInstance.

    Creates the defined instance in the CIM repository.

    If there is no user-defined provider (see User-defined providers)for the class defined in the NewInstance parameter operation requires that all key properties be specified in the new instance since the CIM repository has no support for dynamically setting key properties and all key properties are required to get the newly defined instance with other requests. If a user-defined provider exists for the class, the behavior depends on that provider.

  • ModifyInstance: Behaves like ~pywbem.WBEMConnection.ModifyInstance. Modifies the instance defined by the instance name provided on input if that instance exists in the repository. It modifies only the properties defined by the instance provided and will not modify any key properties. If there is a user-defined provider defined for this operation, that provider may modify the default behavior.
  • DeleteInstance: Behaves like ~pywbem.WBEMConnection.DeleteInstance. Deletes the instance defined by the instance name provided on input if that instance exists. If there is a user-defined provider defined for this operation, that provider may modify the default behavior.
  • ExecQuery: This operation is not currently implemented.

See User-defined providers for more information on writing a user-defined provider.

Faked association operations

The faked association operations support both instance-level use and class-level requests. Class-level use requires the CIM repository to be in full mode, while instance-level use works in both operation modes of the CIM repository.

  • AssociatorNames: Behaves like ~pywbem.WBEMConnection.AssociatorNames, with the following requirements: The source, target, and association classes and their subclasses must exist in the CIM repository for both class-level use and instance-level use.
  • Associators: Behaves like ~pywbem.WBEMConnection.Associators, with the requirements described for AssociatorNames, above.
  • ReferenceNames: Behaves like ~pywbem.WBEMConnection.ReferenceNames, with the requirements described for AssociatorNames, above.
  • References: Behaves like ~pywbem.WBEMConnection.References, with the requirements described for AssociatorNames, above.

Faked method invocation operation

single: User-defined providers

The faked method invocation operation (InvokeMethod) behaves like ~pywbem.WBEMConnection.InvokeMethod, but because of the nature of InvokeMethod, the user must provide an implementation of InvokeMethod based on the API defined in ~pywbem_mock.MethodProvider.InvokeMethod.

NOTE: InvokeMethod is the method name pywbem and other clients and WBEM servers use for what the DMTF defines as extrinsic methods.

See User-defined providers for more information on writing a user-defined provider.

Faked pull operations

The faked pull operations behave like the pull operations of ~pywbem.WBEMConnection, with the following exceptions:

  • The filter query related parameters FilterQuery and FilterQueryLanguage are ignored and no such filtering takes place.
  • The ContinueOnError parameter is ignored because injecting an error into the processing of the pull operations is not supported by the pywbem mock support, so no failures can happen during the processing of the pull operations.
  • The OperationTimeout parameter is currently ignored. As a result, there will be no timeout if the ~pywbem_mock.FakedWBEMConnection.response_delay property is set to a time larger than the OperationTimeout parameter.

The faked pull operations are:

  • OpenEnumerateInstances: Behaves like ~pywbem.WBEMConnection.OpenEnumerateInstances, with the stated exceptions.
  • OpenEnumerateInstancePaths: Behaves like ~pywbem.WBEMConnection.OpenEnumerateInstancePaths, with the stated exceptions.
  • OpenAssociatorInstances: Behaves like ~pywbem.WBEMConnection.OpenAssociatorInstances, with the stated exceptions.
  • OpenAssociatorInstancePaths: Behaves like ~pywbem.WBEMConnection.OpenAssociatorInstancePaths, with the stated exceptions.
  • OpenReferenceInstances: Behaves like ~pywbem.WBEMConnection.OpenReferenceInstances, with the stated exceptions.
  • OpenReferenceInstancePaths: Behaves like ~pywbem.WBEMConnection.OpenReferenceInstancePaths, with the stated exceptions.
  • OpenQueryInstances: Behaves like ~pywbem.WBEMConnection.OpenQueryInstances, with the stated exceptions.
  • PullInstancesWithPath: Behaves like ~pywbem.WBEMConnection.PullInstancesWithPath, with the stated exceptions.
  • PullInstancePaths: Behaves like ~pywbem.WBEMConnection.PullInstancePaths, with the stated exceptions.
  • PullInstances: Behaves like ~pywbem.WBEMConnection.PullInstances, with the stated exceptions.
  • CloseEnumeration: Behaves like ~pywbem.WBEMConnection.CloseEnumeration, with the stated exceptions.

Faked iter operations

The iter operations on a faked connection are in fact the iter operations on ~pywbem.WBEMConnection, because they do not directly issue requests and responses on the connection, but instead are a layer on top of underlying operations. For example, IterEnumerateInstances invokes either pull operations (i.e. OpenEnumerateInstances followed by PullInstancesWithPath) or traditional operations (i.e. EnumerateInstances). The use of pull vs. traditional operations is controlled via the use_pull_operations init parameter of ~pywbem_mock.FakedWBEMConnection.

The iter operations are:

  • ~pywbem.WBEMConnection.IterEnumerateInstances
  • ~pywbem.WBEMConnection.IterEnumerateInstancePaths
  • ~pywbem.WBEMConnection.IterAssociatorInstances
  • ~pywbem.WBEMConnection.IterAssociatorInstancePaths
  • ~pywbem.WBEMConnection.IterReferenceInstances
  • ~pywbem.WBEMConnection.IterReferenceInstancePaths
  • ~pywbem.WBEMConnection.IterQueryInstances

Faked class operations

Class operations only work if the CIM repository is in full operation mode.

  • GetClass: Behaves like ~pywbem.WBEMConnection.GetClass. Requires that the class to be returned is in the CIM repository.
  • EnumerateClasses: Behaves like ~pywbem.WBEMConnection.EnumerateClasses. Requires that the class specified in the ClassName parameter be in the CIM repository.
  • EnumerateClassNames: Behaves like ~pywbem.WBEMConnection.EnumerateClassNames. Requires that the class specified in the ClassName parameter be in the CIM repository.
  • CreateClass: Behaves like ~pywbem.WBEMConnection.CreateClass. Requires that the superclass of the new class (if it specifies one) is in the CIM repository.
  • DeleteClass: Behaves like ~pywbem.WBEMConnection.DeleteClass, with the following difference: This operation additionally deletes all direct and indirect subclasses of the class to be deleted, and all instances of the classes that are being deleted. Requires that the class to be deleted is in the CIM repository.
  • ModifyClass: Not currently implemented.

Faked qualifier declaration operations

Qualifier operations declaration include the following.

  • SetQualifier: Behaves like ~pywbem.WBEMConnection.SetQualifier. Requires that the specified qualifier type is in the CIM repository.
  • GetQualifier: Behaves like ~pywbem.WBEMConnection.GetQualifier. Requires that the specified qualifier type is in the CIM repository.
  • EnumerateQualifiers: Behaves like ~pywbem.WBEMConnection.EnumerateQualifiers. Requires that the qualifier types to be returned are in the CIM repository.
  • DeleteQualifier: - Not implemented.

FakedWBEMConnection class

pywbem_mock.FakedWBEMConnection

Methods

pywbem_mock.FakedWBEMConnection

Attributes

pywbem_mock.FakedWBEMConnection

Details

Building a mocked CIM repository

The CIM repository of a mock WBEM server needs to contain the CIM namespaces, and within them, the CIM qualifier declarations, CIM classes, and CIM instances required by the user. These are created as part of the setup of any particular pywbem mock environment. Thus, if the user only requires CIM_ComputerSystem in a particular namespace, only that class and its dependent classes and qualifier declarations need be in that namespace in the CIM repository, along with instances of the classes that will satisfy the client methods executed.

The classes ~pywbem_mock.FakedWBEMConnection and ~pywbem_mock.DMTFCIMSchema provide the tools to build the CIM repository.

CIM namespaces are created in the CIM repository by defining a default namespace for the ~pywbem_mock.FakedWBEMConnection object, and by using the ~pywbem_mock.FakedWBEMConnection.add_namespace method to create additional namespaces.

There are multiple ways to add CIM objects to a target namespace of the CIM repository:

  • From CIM objects <CIM object>, using the ~pywbem_mock.FakedWBEMConnection.add_cimobjects method.

    The specified CIM objects are added to or updated in a target namespace of the CIM repository. Dependent classes and qualifier types of these objects must already exist in the target namespace.

  • From definitions of the CIM objects in a MOF string or a MOF file, using the ~pywbem_mock.FakedWBEMConnection.compile_mof_string or ~pywbem_mock.FakedWBEMConnection.compile_mof_file methods.

    The CIM objects defined in the MOF are added to or updated in a target namespace of the CIM repository. Dependent classes and qualifier types of these objects must already exist in the target namespace.

  • From CIM class names and a schema search path containing the MOF files of one or more schemas, using the ~pywbem_mock.FakedWBEMConnection.compile_schema_classes method.

    The schema MOF files can either be provided by the user, or the DMTF CIM schema can be automatically downloaded from the DMTF using the ~pywbem_mock.DMTFCIMSchema class.

    The specified CIM classes are added to or updated in a target namespace of the CIM repository, and their dependent classes and qualifier types are added to the target namespace from the schemas in the search path as needed.

    The dependent classes and qualifier types are determined automatically and recursively. This includes superclasses, reference classes (used in reference properties and reference parameters), and embedded classes (i.e. classes referenced through the EmbeddedInstance qualifier). Thus, a user building a CIM repository does not have to track down those dependent classes and qualifier types, and instead only needs to know the schema(s) to be used and the creation classes for any CIM instances. This also means that there is normally no reason to compile the complete schema which is much larger than the classes that are minimally needed.

It may take a combination of all of the above methods to build a CIM repository that satisfies a particular usage requirement. A typical approach for building a CIM repository is:

  1. Establish the MOF subtrees for the schema(s) needed. That can be a downloaded version of the DMTF CIM schema, local modifications to a version of the DMTF CIM schema, user-defined schemas including schemas derived from the DMTF CIM schema, or a combination thereof.
  2. Create the CIM namespaces needed, either as the default namespace or by adding namespaces, including the interop namespace.
  3. For each CIM namespace needed, create the set of needed CIM classes and qualifier types by using the ~pywbem_mock.FakedWBEMConnection.compile_schema_classes method and specifying the set of creation classes of the CIM instances that are intended to be added, and specifying the pragma MOF files of the schema(s) added in step 1 as a schema search path.
  4. For each CIM namespace needed, create the set of needed CIM instances by defining and compiling instance MOF, or by creating and adding ~pywbem.CIMInstance objects, or both. Often defining MOF is easier for this because it simplifies the definition of association instances with the instance alias.
  5. Register user-defined providers such as the ~pywbem_mock.CIMNamespaceProvider or user-written providers for the creation classes of the CIM instances that have non-default instance write behavior or that need CIM methods to be supported. See User-defined providers for details.

Example: Set up qualifier types and classes in DMTF CIM schema

This example creates a mock WBEM server using root/interop as the default namespace and compiles the classes defined in the list 'classes' from DMTF schema version 2.49.0 into the CIM repository along with all of the qualifier types defined by the DMTF CIM schema and any dependent classes (superclasses, etc.).

import pywbem
import pywbem_mock

conn = pywbem_mock.FakedWBEMConnection(default_namespace='root/interop')

# Leaf classes that are to be compiled along with their dependent classes
leaf_classes = ['CIM_RegisteredProfile',
                'CIM_Namespace',
                'CIM_ObjectManager',
                'CIM_ElementConformsToProfile',
                'CIM_ReferencedProfile']

# Download DMTF CIM schema version 2.49.0 into directory my_schema_dir.
schema = DMTFCIMSchema((2, 49, 0), "my_schema_dir", leaf_classes,
                       verbose=True)

# Compile the leaf classes, looking up dependent classes and qualifier
# types from the downloaded DMTF CIM schema.
conn.compile_schema_classes(leaf_classes, schema.schema_pragma_file
                            verbose=True)

# Display the resulting repository
conn.display_repository()

Example: Set up qualifier types and classes from MOF

This example creates a mock WBEM server and sets up its CIM repository with qualifier types and classes that are defined in a MOF string.

import pywbem
import pywbem_mock

tst_namespace = 'root/blah'
conn = pywbem_mock.FakedWBEMConnection()

# Add some qualifier types and classes to the CIM repo by compiling MOF
mof = '''
    Qualifier Key : boolean = false,
        Scope(property, reference),
        Flavor(DisableOverride, ToSubclass);

    Qualifier Association : boolean,
        Scope(class),
        Flavor(DisableOverride, ToSubclass);

    class TST_Class1 {
          [Key]
        string InstanceID;
        string Prop1;
    };

    class TST_Class2 {
          [Key]
        string InstanceID;
        string Prop2;
    };

      [Association]
    class TST_Association12 {
          [Key]
        TST_Class1 REF Ref1;
          [Key]
        TST_Class2 REF Ref2;
    };
'''
conn.compile_mof_string(mof, tst_namespace)

conn.display_repository()

Here is the output from displaying the CIM repository in the example above:

# ========Mock Repo Display fmt=mof namespaces=all =========


# NAMESPACE root/blah

# Namespace root/blah: contains 2 Qualifier Declarations

Qualifier Association : boolean,
    Scope(class),
    Flavor(DisableOverride, ToSubclass);

Qualifier Key : boolean = false,
    Scope(property, reference),
    Flavor(DisableOverride, ToSubclass);

# Namespace root/blah: contains 3 Classes

   [Association ( true )]
class TST_Association12 {

      [Key ( true )]
   TST_Class1 REF Ref1;

      [Key ( true )]
   TST_Class2 REF Ref2;

};

class TST_Class1 {

      [Key ( true )]
   string InstanceID;

   string Prop1;

};

class TST_Class2 {

      [Key ( true )]
   string InstanceID;

   string Prop2;

};

============End Repository=================

Example: Set up instances from single CIM objects

Based on the CIM repository content of the previous example, this example adds two class instances and one association instance from their CIM objects using the ~pywbem_mock.FakedWBEMConnection.add_cimobjects method.

c1_key = pywbem.CIMProperty('InstanceID', type='string', value='111')
c1_path = pywbem.CIMInstanceName(
    'TST_Class1',
    keybindings={c1_key.name: c1_key.value},
)
c1 = pywbem.CIMInstance(
    'TST_Class1',
    properties=[
        c1_key,
        pywbem.CIMProperty('Prop1', type='string', value='1'),
    ],
    path=c1_path,
)

c2_key = pywbem.CIMProperty('InstanceID', type='string', value='222')
c2_path = pywbem.CIMInstanceName(
    'TST_Class2',
    keybindings={c2_key.name: c2_key.value},
)
c2 = pywbem.CIMInstance(
    'TST_Class2',
    properties=[
        c2_key,
        pywbem.CIMProperty('Prop2', type='string', value='2'),
    ],
    path=c2_path,
)

a12_key1 = pywbem.CIMProperty('Ref1', type='reference', value=c1_path)
a12_key2 = pywbem.CIMProperty('Ref2', type='reference', value=c2_path)
a12_path = pywbem.CIMInstanceName(
    'TST_Association12',
    keybindings={
        a12_key1.name: a12_key1.value,
        a12_key2.name: a12_key2.value,
    },
)
a12 = pywbem.CIMInstance(
    'TST_Association12',
    properties=[
        a12_key1,
        a12_key2,
    ],
    path=a12_path,
)

conn.add_cimobjects([c1, c2, a12], tst_namespace)

conn.display_repository()

This adds the instances to the repository display of the previous example:

# Namespace root/blah: contains 3 Instances

#  Path=/root/blah:TST_Class1.InstanceID="111"
instance of TST_Class1 {
   InstanceID = "111";
   Prop1 = "1";
};

#  Path=/root/blah:TST_Class2.InstanceID="222"
instance of TST_Class2 {
   InstanceID = "222";
   Prop2 = "2";
};

#  Path=/root/blah:TST_Association12.Ref1="/:TST_Class1.InstanceID=\"111\"",Ref2="/:TST_Class2.InstanceID=\"222\""
instance of TST_Association12 {
   Ref1 = "/:TST_Class1.InstanceID=\"111\"";
   Ref2 = "/:TST_Class2.InstanceID=\"222\"";
};

DMTF CIM schema download support

pywbem_mock._dmtf_cim_schema

pywbem_mock.DMTFCIMSchema

Methods

pywbem_mock.DMTFCIMSchema

Attributes

pywbem_mock.DMTFCIMSchema

Details

In-memory CIM repository classes

pywbem_mock._inmemoryrepository

pywbem_mock.InMemoryRepository

Methods

pywbem_mock.InMemoryRepository

Attributes

pywbem_mock.InMemoryRepository

Details

pywbem_mock.InMemoryObjectStore

Methods

pywbem_mock.InMemoryObjectStore

Attributes

pywbem_mock.InMemoryObjectStore

Details

Mocking multiple CIM namespaces

The mock WBEM server allows creating multiple CIM namespaces in its CIM repository and adding CIM objects in some or all of those namespaces.

There is a default namespace created when the ~pywbem_mock.FakedWBEMConnection object is created from either the value of the default_namespace init parameter or its default value root/cimv2.

However, a working WBEM environment normally includes at least two namespaces:

  1. An interop namespace which contains the parts of the model that deal with the WBEM server itself and with the implemented model (ex. CIM_Namespace, CIM_ObjectManager, CIM_RegisteredProfile, etc.) and which must be publically discoverable without the user knowing what CIM namespaces exist in the WBEM server.
  2. A user namespace containing the CIM objects for the user model.

Pywbem_mock includes a user-defined provider for the CIM_Namespace class that can be enabled by adding code similar to the following to the setup of a mock environment.

# Register the provider for the CIM_Namespace class, assuming that
# dependent classes and qualifier types have already been created in
# the interop namespace.
ns_provider = pywbem_mock.CIMNamespaceProvider(conn.cimrepository)
interop_namespace = "interop"   # or "root/interop"
conn.add_namespace(interop_namespace)
conn.register_provider(ns_provider, namespaces=interop_namespace)

pair: User defined providers; user providers

User-defined providers

Within the mock WBEM server, the response to client requests is normally determined by provider methods that use data in the CIM repository to generate responses (ex. GetInstance gets the instances from the repository, possibly filters properties and returns the instance). However, it is expected that the user may want WBEM operations on specific CIM classes to have side effects, or manage the returns differently than the normal responses.

Thus, for example, the DMTF-defined CIM_Namespace class represents the namespaces in the CIM repository. That means that its provider method for CreateInstance must create a namespace as a side effect, and that its provider methods for GetInstance or EnumerateInstances must inspect the set of namespaces in the CIM repository to generate responses, etc.

Another example of user-defined providers are classes that create their key property values automatically, for example classes that have a single InstanceID key. The provider method for CreateInstance of such classes would ignore the values for the key properties provided in the NewInstance parameter, and determine the key values on its own.

Also, the InvokeMethod operation depends on a specific provider method for the invoked CIM method in the mock WBEM server.

To meet these needs, the capability is provided to users to write user-defined providers <user-defined provider> that replace the default providers for defined classes and operations.

User-defined providers are written by implementing subclasses of specific provider classes and registering these subclasses as providers using ~pywbem_mock.FakedWBEMConnection.register_provider.

The WBEM operations supported by user-defined providers can be implemented one by one. If a user-defined provider does not implement all WBEM operations, the default implementation will be used.

The following table shows the WBEM operations for which user-defined providers are supported, and the corresponding provider types:

WBEM operation Provider type Superclass Provider description
CreateInstance instance write ~pywbem_mock.InstanceWriteProvider User-defined instance write providers
ModifyInstance instance write ~pywbem_mock.InstanceWriteProvider User-defined instance write providers
DeleteInstance instance write ~pywbem_mock.InstanceWriteProvider User-defined instance write providers
InvokeMethod method ~pywbem_mock.MethodProvider User-defined method providers

Creating user-defined providers

A user-defined provider can be created as follows:

  1. Define a subclass of the superclass listed in the table above, with the methods and attributes listed below.

    Example for an instance write provider:

    from pywbem_mock import InstanceWriteProvider
    
    class MyInstanceProvider(InstanceWriteProvider):
    
        . . .
    1. Optional: It may have an __init__() method.

      The __init__() method takes as input parameters at least the cimrepository parameter and passes it to the superclass, and may have additional init parameters the user-defined provider requires (that are not passed on to the superclass). Additional init parameters are possible because the user creates the provider object when registering it with ~pywbem_mock.FakedWBEMConnection.register_provider. Having an __init__() method is optional if no additional init parameters are defined.

      Example for an __init__() method that does not define additional init parameters (and that could therefore be omitted):

      def __init__(self, cimrepository):
          super(MyInstanceWriteProvider, self).__init__(cimrepository)
    2. It must have a declaration of the CIM class(es) served by the provider.

      The CIM class or classes served by the provider are declared with a class attribute named provider_classnames. Its value must be a single string or a list/tuple of strings with the CIM class names (in any lexical case).

      provider_classnames = 'CIM_Foo'

      or

      provider_classnames = ['CIM_Foo', 'CIM_Foo_blah']
    3. It must have an implementation of the Python methods for the WBEM operations that are overwritten by the provider.

      This must be all or a subset of the WBEM operations defined for the provider type. WBEM operations not implemented in the user-defined provider class default to implementations in the superclass. See Python operation methods in user-defined providers for details.

      Example for an CreateInstance method of an instance write provider that just calls superclass method to perform the work (and that could therefore be omitted):

      def CreateInstance(self, namespace, NewInstance):
          return super(MyInstanceWriteProvider, self).CreateInstance(
              namespace, NewInstance)
    4. Optional: It may define a post register setup method.

      The provider may override the ~pywbem_mock.InstanceWriteProvider.post_register_setup method of the provider superclass to do any special setup it needs. That method includes the current connection as a parameter so that WBEM operations on the same or on different classes can be executed. That method will be called during invocation of ~pywbem_mock.FakedWBEMConnection.register_provider, after the provider registration is successful.

      Example:

      def post_register_setup(self, conn):
        # code that performs post registration setup for the provider
  2. Register the user-defined provider using pywbem_mock.FakedWBEMConnection.register_provider.

    This specifies the CIM namespaces for which the user-defined provider will be active. These namespaces must already exist in the CIM repository if the mock WBEM server.

    provider = MyInstanceProvider(self.cimrepository)
    conn.register_provider(provider,
                           namespaces=['root/interop', 'root/cimv2'])

Python operation methods in user-defined providers

The Python operation methods (i.e. the Python methods implementing WBEM operations) in user-defined providers may:

  • provide parameter or CIM repository validation in addition to the normal request validation,
  • modify parameters of the request,
  • abort the request with a pywbem.CIMError exception,
  • make modifications to the CIM repository.

The Python operation methods may call the corresponding superclass method to complete the CIM repository modification, or may implement the code to complete the modification. In any case, once a Python operation method returns, the CIM repository needs to reflect any changes on CIM objects the WBEM operation is normally expected to perform.

The Python operation methods have access to:

  • methods defined in the superclass of the provider, including :class:~pywbem_mock.BaseProvider`
  • methods to access the CIM repository using the methods defined in ~pywbem_mock.InMemoryRepository

The input parameters for the Python operation methods will have been already validated, including:

  • The input parameters have the correct Python type as per the descriptions in the superclasses.
  • The CIM namespace exists in the CIM repository.
  • The CIM class of a CIM instance or instance path specified as an input parameter exists in that namespace of the CIM repository.
  • The CIM properties of a CIM instance specified as an input parameter are defined in the CIM class of the instance and have the correct CIM types.
  • The CIM instance does not yet exist for CreateInstance and does exist for ModifyInstance.

The Python operation methods should raise any exceptions using pywbem.CIMError using the CIM status codes defined in DSP0200.

User-defined instance write providers

pywbem_mock._instancewriteprovider

pywbem_mock.InstanceWriteProvider

Methods

pywbem_mock.InstanceWriteProvider

Attributes

pywbem_mock.InstanceWriteProvider

Details

User-defined method providers

pywbem_mock._methodprovider

pywbem_mock.MethodProvider

Methods

pywbem_mock.MethodProvider

Attributes

pywbem_mock.MethodProvider

Details

Configuration of mocked behavior

pywbem_mock.config

Mocker base classes

Some bases classes are included in this documentation in order to provide the descriptions for inherited methods and properties in the previous class descriptions of the mock WBEM server.

pywbem_mock.BaseRepository

Methods

pywbem_mock.BaseRepository

Attributes

pywbem_mock.BaseRepository

Details

pywbem_mock.BaseObjectStore

Methods

pywbem_mock.BaseObjectStore

Attributes

pywbem_mock.BaseObjectStore

Details

pywbem_mock.BaseProvider

Methods

pywbem_mock.BaseProvider

Attributes

pywbem_mock.BaseProvider

Details