Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

  • Implement QMF protocol via QPID Map messages
  • Improve thread safety by simplifying minimizing the callback notification mechanism.
  • Move to a work-queue based event model.
  • Reorganize QMF code into common API, Console API, and Agent API modules.

Common Object Classes

Object classes that are used by Agent and Console components.

Schema

Schemas are used by QMF to describe the structure of management data.

Schema Types

There are two classes (or types) of Schema - those that describe
QmfData objects, and those that describe QmfEvent objects.

No Format

SchemaTypeData:
SchemaTypeEvent:

These types may be represented by the strings "data" and "event",
respectively.

Schema Identifier

Schema are identified by a combination of their package name and class
name. A hash value over the body of the schema provides a revision
identifier. The class SchemaClassId represents this Schema
identifier.

No Format

class SchemaClassId:
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     hash=<hash-str, format="%08x-%08x-%08x-%08x">, 
      .getPackageName(): returns <package-name-str>
      .getClassName(): returns <class-name-str>
      .getHashString(): returns <hash-str, "%08x-%08x-%08x-%08x">
      .getType(): returns SchemaTypeObject or SchemaTypeEvent
      .mapEncode(): returns a map encoding of the instance.

If the hash is not supplied, then the default value
"00000000-00000000-00000000-00000000" will be supplied. This may be
the case when a SchemaClass is being dynamically constructed, and a
proper hash is not yet available.

The map encoding of a SchemaClassId:

Index

Optional

Type

Description

"package_name"

N

string

The name of the associated package.

"class_name"

N

string

The name of the class within the package.

"type"

N

string

The type of schema, either "data" or "event".

"hash_str"

Y

string

The MD5 hash of the schema, in the format "%08x-%08x-%08x-%08x"

Schema For Describing The Properties of Data

The SchemaProperty class represents the description of a single
data item. A SchemaProperty is a list of named attributes and their
values. QMF defines a set of primative attributes. An application
can extend this set of attributes with application-specific
attributes.

All application-specific attributes must be named using the prefix "x-",
and their values must be encoded by an AMQP type.

Once instantiated, the SchemaProperty is immutable.

Component Addressing

QMF uses AMQP messaging as the means for communications between Console and Agent components. Thus instances of Agents and Consoles must have addresses which uniquely identify them within the AMQP messaging domain.

QMF uses AMQP string types to represent Agent and Console addresses. These strings are assigned by the application, and their contents are opaque to the QMF implementation.

A QMF address is composed of two parts - an optional domain string, and a mandatory name string. The domain string is used to construct the name of the AMQP exchange to which the component's name string will be bound. If not supplied, the value of the domain defaults to "default". Both Agents and Components must belong to the same domain in order to communicate.

When a Console or Agent is instantiated, it will create a receiving endpoint (source) on the AMQP message domain. The endpoint's address will be sent as the reply_to field for all messages originating from that Console or Agent. The address of the endpoint is created from the value of the domain and name strings, using the following format:

No Format

    "qmf.<domain-string>.direct/<name-string>"

Data Model

Representation of Managment Data

The QMF data model supports two methods for representing management data:

  1. arbitrarily structured data
  2. data with a formally defined structure

Arbitrarily structured data is the simpliest method for representing data under QMF. It consists of a set of named data values. Each data value is represented by a primitive AMQP data type. The data is accessed using the data's name as a key. QMF represents arbitrarily structured data as a map of AMQP data types indexed by a name string.

Data that has a formally defined structure extends the data representation by associating the data with a Schema. The Schema describes the structure of all instances of data that are based on that Schema. This is akin to a record type in database design.

Both types of data representations can be managed by an agent. Managed data includes:

  1. an object identifier
  2. object lifecycle state

An object identifier uniquely addresses a data object within the domain of its managing agent. QMF represents the object identifier as an opaque string. An object identifier can be assigned to the object by the agent when the object is instantiated. Alternatively, a schema can define an object identifier by defining an ordered list of names of data items. In this case, the object identifier string is built by concatenating the string representations of the value of each named data item. This approach is similar to defining index fields within a database record.

For example, assume a managed object with the following map of data item values:

No Format

{"field1" : "foo",
 "field2" : "bar",
 "field3" : 42,
 "field4" : "baz"}

and assume the data item list defined by the managed object's schema is:

No Format

["field1", "field3"]

The identifier for this data object would be:

No Format

"foo42"

QmfData Class

QMF defines the QmfData class to represent an atomic unit of managment data. The QmfData class defines a collection of named data values. Optionally, a string tag, or "sub-type" may be associated with each data item. This tag may be used by an application to annotate the data item.

When representing formally defined data, a QmfData instance is assigned a Schema.

When representing managed data, a QmfData instance is assigned an object identifier (either explicitly, or via the Schema).

No Format

class QmfData:
      <constructor>( _values=map of "name"=<AMQP Type> pairs,
                     _subtypes=optional map of "name"=<AMQP String> pairs for subtype information,
                     _tag=optional, application-specific tag applied to this QmfData instance
No Format

class SchemaProperty:
      <constructor>( name=<name-value>, 
                     type=<type-value>,
                     ...)
      .getType(): AMQP typecode for encoding/decoding the property data
      .getAccess(): "RC"=read/create, "RW"=read/write, "RO"=read only (default)
      .isOptional(): True if this property is optional
      .getUnit(): string describing units (optional)
      .getMin(): minimum value (optional)
      .getMax(): maximum value (optional)
      .getMaxLen(): maximum length for string values (optional)
      .getDesc(): optional string description of this Property
      .getDirection(): "I"=input, "O"=output, or "IO"=input/output
                       (required for method arguments, otherwise
        _object_id=optional AMQP string that uniquely identifies this QmfData instance.
       optional)
      .getSubtype(): string indicating the formal application type 
 _schema=optional <class SchemaClass> reference
                 for the data, example: "URL", "Telephone number", _const=False )
      <constructor>( _map=map representation of QmfData, as generated by mapEncode() method,
      etc.
      .isPolled(): True if changes to the data cannot be practically 
  _schema=optional <class SchemaClass> reference
                 monitored by an Agent.  Such a data item can only
          _const=False)
      .is_managed(): returns True if object identifier string assigned, else False.
      .is_described(): returns True if beschema queriedis orassociated polledwith - not published on change.this instance
      .getReferenceget_tag(): return if type==objId, name (str) of referenced classthis object's tag if present, else None
      .get_value(name): return the value of the named data item, returns None if named property is   (optional) not present.
      .isParentRefhas_value(name): returns True if the thisnamed propertydata referencesitem anis objectpresent in
 the map, else False.
      .set_value(name, value, subType=None): set the value of the named data item.   which this object is in a child-parent
                       relationshipCreates a new item if the named data does not exist. Raises an exception if _const is True.
      .getAttributeget_subtype("name"): getreturns the valuesub oftype thedescription attributestring, named
else None if not present.
      "name". This method can be used to retrieve.set_subtype(name, subType): set or modify the subtype associated with name.
      .get_object_id(): returns the  application-specific attributes.  "name" should start with
          the prefix "x-"object id string associated with the object instance, or None if no id assigned.
      .get_schema_class_id: returns the identifier of the Schema that describes the structure of the data, or None if no schema.
      .mapEncodemap_encode(): returns a map encodingrepresentation of the QmfData instance, suitable for use by the constructor.

The QMF uses a map encoding of a SchemaProperty's bodyto represent a QmfData class in an AMQP message. The map encoding of an instance of the QmfData Class is made up of the following elements:

Index

Optional

Type

Description

"qmf_typevalues"

N

integer

map

Map containing all the "name"=<AMQP Type> pairs for this objectThe QMF type code indicating property's data type.

"access_subtype"

N Y

string

The access allowed to this property, default "RO"

"optional"

N

boolean

True if this property is optional, default False

map

Map containing all "name"=<AMQP String> subtype entries for this object.

"_tag"

Y

Any AMQP-supported type

Application-specific tag for this object.

"_object_id"unit"

Y

string

Description of the units used to express this property Unique identifier for this data object.

"min_schema_id"

Y

integer

map

Map containing the SchemaClassId The minimum allowed value for this property

"max"

Y

integer

The maximun allowed value for this property

"maxlen"

Y

integer

For string types, this is the maximum length in bytes required to represent the longest permittable instance of this string.

"desc"

Y

string

Human-readable description of this property.

"dir"

Y

string

Direction for an argument when passed to a Method call: "I", "O", "IO", default value: "I"

"subtype"

Y

string

Type information for use by the application.

"polled"

Y

boolean

True if this property can only be queried/polled. Default False.

"reference"

Y

string

unknown?

"parent_ref"

Y

boolean

True if this property references an object in which this object is in a child-parent relationship. Default False

"x-"<varies>

Y

Any AMQP type

An application-defined attribute.

Schema For Describing Method Calls

object.

QmfEvent Class

QMF supports event management functionality. An event is a notification that is sent by an Agent to alert Console(s) of a change in some aspect of the system under management. Like QMF Data, Events may be formally defined by a Schema or not. Unlike QMF Data, Events are not manageable entities - they have no lifecycle. Events simply indicate a point in time where some interesting action occurred.

An instance of an event is represented by the QmfEvent class.

An AMQP timestamp value is associated with each QmfEvent instance. It indicates the moment in time the event occurred. This timestamp is mandatory.

A severity level may be associated with each QmfEvent instance. The following severity levels are supported:

  • "emerg" - system is unusable
  • "alert" - action must be taken immediately
  • "crit" - the system is in a critical condition
  • "err" - there is an error condition
  • "warning" - there is a warning condition
  • "notice" - a normal but significant condition
  • "info" - a purely informational message
  • "debug" - messages generated to debug the application

The default severity is "notice"SchemaMethod class identifies the method call and describes its
parameter list. The parameter list is represented by an unordered
map of SchemaProperty entries indexed by parameter name.

No Format
class SchemaMethodQmfEvent(QmfData):
      <constructor>( [args=<map of "name":<SchemaProperty> entries>],
timestamp,
                     _severity=<string>,
         desc="description of the method")
      .getDesc(): return human-readable description of the method. _values=map of "name"=<AMQP Type> pairs,
      .getArgumentCount(): return the number of arguments
      .getArguments(): returns a copy of the _subtypes=optional map of "name":<SchemaProperty>=<AMQP String> pairs for subtype information,
      .getArgument("name"): return the SchemaProperty for the parameter "name"

               .addArgument("name", SchemaProperty): adds an additional argument to_tag=optional, application-specific tag applied to this QmfEvent instance
                  the parameter list   _schema=optional <class SchemaEventClass> )
       <constructor>( _map= map encoding of a QmfEvent instance,
                     _schema=optional <class SchemaEventClass> )
      .get_timestamp(): return a timestamp indicating when the Event occurred.
      .get_severity(): return the severity associated with the Event.
      .mapEncodemap_encode(): returnsreturn a map encoding of the SchemaMethod instanceEvent.

The map encoding of a SchemaMethodan instance of the QmfEvent class extends the map of the parent class with the following class properites:

Index

Optional

Type

Description

"name_timestamp"

N

string

AMQP Timestamp

Time the event occurredThe name of the method.

"arguments_severity"

Y

map

Map of "name":<SchemaProperty> values, one for each argument to the method.

Note that the "dir" SchemaProperty attribute applies to each
argument. If "dir" is not specified, it is assumed to be "I".

Schema for Data Objects and Events

A top-level data object in QMF is a collection of properties and
methods. Data objects are described by the class SchemaObjectClass.
Data objects may be managed (owned) by an Agent.

Events describe a change within the underlying management system. Unlike
data objects, events do not correspond to a managable entity. They
are composed of a list of arguments that apply to the event. Event
objects are described by the class SchemaEventClass.

Both of these classes derive from the virtual base SchemaClass.

Agent applications may dynamically construct instances of these
objects by adding properties and methods at run time.
However, once the Schema is published, it must be considered
immutable, as the hash value must be constant once the Schema is
in use.

string

Event severity

Schema

Schemas are used by QMF to describe the structure of management data and events. The use of Schemas is optional.

Schema Types

There are two classes (or types) of Schema - those that describe data objects, and those that describe event objects.

No Format

SchemaTypeData:
SchemaTypeEvent:

These types may be represented by the strings "_data" and "_event",
respectively.

Schema Identifier

Schema are identified by a combination of their package name and class
name. A hash value over the body of the schema provides a revision
identifier. The class SchemaClassId represents this Schema
identifier.

No Format

class SchemaClassId
No Format

class SchemaClass:
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>),
                     desc=<description of schema>hash=<hash-str, format="%08x-%08x-%08x-%08x">,
      .get_package_name(): returns <package-name-str>
      .get_class_name(): returns <class-name-str>
     hash= .get_hash_string(): returns <hash-str, format="%08x-%08x-%08x-%08x">)
      .getClassIdget_type(): returnreturns theSchemaTypeObject SchemaClassId that identifies thisor SchemaTypeEvent
      .map_encode(): returns a map encoding of           Schema instance.
      .getDesc(): return a human-readable description of this schema.
      .generateHash(): generate a hash over the body of the schema,
                       and return a string representation of the hash
                       in format  the instance.

If the hash value is not supplied, then the value of the hash string will be set to None. This will be the case when a SchemaClass is being dynamically constructed, and a proper hash is not yet available.

The map encoding of a SchemaClassId:

Index

Optional

Type

Description

"_package_name"

N

string

The name of the associated package.

"_class_name"

N

string

The name of the class within the package.

"_type"

N

string

The type of schema, either "data" or "event".

"_hash_str"

Y

string

The MD5 hash of the schema, in the format "%08x-%08x-%08x-%08x"

Schema For Describing The Properties of a Data Item

The SchemaProperty class describes a single data item in a QmfData object. A SchemaProperty is a list of named attributes and their values. QMF defines a set of primitive attributes. An application can extend this set of attributes with application-specific attributes.

QMF reserved attribute names all start with the underscore character ("_"). Do not create an application-specific attribute with a name starting with an underscore.

Once instantiated, the SchemaProperty is immutable.

No Format

class SchemaProperty
      .mapEncode(): returns a map encoding of the instance.


class SchemaObjectClass(SchemaClass):
      <constructor>( packagename=<package<name-name-str>value>, 
                     classtype=<class<type-name-str>value>,
                     type=<SchemaTypeData|SchemaTypeEvent>...)
      .get_type(): AMQP typecode for encoding/decoding the property data
        hash=<hash-str, format="%08x-%08x-%08x-%08x">,
   .get_access(): "RC"=read/create, "RW"=read/write, "RO"=read only (default)
      .is_optional(): True if this property is optional
      _properties=<map of "name":SchemaProperty instances>,
   .get_unit(): string describing units (optional)
      .get_min(): minimum value (optional)
         _methods=<map of "name":SchemaMethod instances>.get_max(): maximum value (optional)
      .getPrimaryKeyListget_max_len(): returnmaximum anlength orderfor liststring of names of thevalues (optional)
          property(s) that are used to construct the key for
.get_desc(): optional string description of this Property
      .get_direction(): "I"=input, "O"=output, or "IO"=input/output (required identifyingfor uniquemethod instancesarguments, of this class.

otherwise optional)
      .getPropertyCountget_subtype(): string returnindicating the number of data propertiesformal application type for the data, example: "URL", "Telephone number", etc.
      .getPropertiesis_polled(): returnTrue aif mapchanges of "name":<SchemaProperty>
          entries for each property in the object.
to the data cannot be practically monitored by an Agent.  Such a data item can only
          be  .getProperty("name"): return the SchemaProperty associated with "name"

queried or polled - not published on change.
      .getMethodCountget_reference(): return the numberif type==objId, name (str) of methods.referenced class (optional)
      .getMethodsis_parent_ref(): returnTrue aif mapthis of "name":<SchemaMethod> entries for
          each  method in the objectproperty references an object in which this object is in a child-parent relationship.
      .getMethodget_attribute("name"): returnget the SchemaMethodvalue associated withof the "name"

      .addProperty(attribute named "name",. SchemaProperty):This addmethod acan newbe property
used to retrieve
    .addMethod("name", SchemaMethod): add a new method.
    application-specific  .appendPrimaryKey("name"): addattributes.  "name" toshould thestart end ofwith the list of
   prefix "x-"
       names used to construct the primary key.


class SchemaEventClass(SchemaClass):
      <constructor>( package=<package-name-str>, 
                     class=<class-name-str>,
                     type=<SchemaTypeData|SchemaTypeEvent>)
                     hash=<hash-str, format="%08x-%08x-%08x-%08x">,
                     _properties=<map of "name":SchemaProperty instances>)
      .getPropertyCount(): return the number of data properties.
      .getProperties(): return a map of "name":<SchemaProperty>
          entries for each property in the event.
      .getProperty("name"): return the SchemaProperty associated with "name"

      .addProperty("name", SchemaProperty): add a new property.

The map encoding of a SchemaObjectClass:

.map_encode(): returns a map encoding of the instance.

The map encoding of a SchemaProperty's body:

Index

Optional

Type

Description

"_qmf_type"

N

integer

The QMF type code indicating the value's data type.

"_access"

N

string

The access allowed to this property, default "RO"

"_optional"

N

boolean

True if this property is optional, default False

"_unit"

Y

string

Description of the units used to express this property.

"_min"

Y

integer

The minimum allowed value for this property

"_max"

Y

integer

The maximun allowed value for this property

"_maxlen"

Y

integer

For string types, this is the maximum length in bytes required to represent the longest permittable instance of this string.

"_

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"desc"

Y

string

Human-readable description of this Schemaproperty.

"primary_keydir"

Y

string

Direction for an argument when passed to a Method call: "I", "O", "IO", default value: "I"

"_subtype

list

Ordered list of property names used to construct the Primary Key.

"properties"

Y

map

string

Type information for use by the applicationMap of "name":<SchemaProperty> values, one for each property in the object.

"methods_polled"

Y

map

Map of "name":<SchemaMethod> values, one for each method in this object.

The map encoding of a SchemaEventClass:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"desc"

Y

string

Human-readable description of this Schema.

"properties"

Y

map

Map of "name":<SchemaProperty> values, one for each property in the event.

Data Model

The QMF defines three layers of data representation:

  1. arbitrarily structured data
  2. structured data
  3. managed structured data

Arbitrarily structured data is represented by a map of named data
items. There is no schema associated with this data, as its structure
is arbitrary. This class of data is represented by the QmfData class.

Data that has a formally defined structure is represented by the
QmfDescribed class. This class extends the QmfData class by
associating the data with a formal schema.

Managed structured data extends the concept of structured data by
providing an owner for the data. In QMF, this owner is an Agent.
This class of data extends the QmfDescribed class by adding an
identifier of the owning Agent.

QmfData Class

boolean

True if this property can only be queried/polled. Default False.

"_reference"

Y

string

unknown?

"_parent_ref"

Y

boolean

True if this property references an object in which this object is in a child-parent relationship. Default False

"x-"<varies>

Y

Any AMQP type

An application-defined attribute.

Schema For Describing Method Calls

The SchemaMethod class describes a method call's parameter list. The parameter list is represented by an unordered map of SchemaProperty entries indexed by parameter name.

No Format

class SchemaMethod:
      <constructor>( [args=<map of "name":<SchemaProperty> entries>],
                     desc="description of the method")
No Format

class QmfData:
      <constructor>( map of "name"=<AMQP Type> pairs, _const=False )
      .isManaged(): returns False for QmfData instances.
      .isDescribed(): returns False for QmfData instances.
      .getPropertyget_desc(name): return thehuman-readable valuedescription of the named propertymethod.
      .get_argument_count(): return the number of arguments
               data, returns None if named property is
                          not present. .get_arguments(): returns a copy of the map of "name":<SchemaProperty>
      .setPropertyget_argument("name, value"): setreturn the valueSchemaProperty offor the namedparameter "name"

      .add_argument("name", SchemaProperty): adds an additional argument to the parameter list.
      .map_encode(): returns a map encoding of the  property data.  Creates a new property
                             if the named property does not exist.
                             Raises an exception if _const is True.
      .getProperties(): return a map of "name"=<value> pairs for each
                        of the object's properties. 
      .mapEncode(): returns a map representation of the QmfData
          instance, suitable for use by the constructor.

The map encoding of a QmfData Class is merely a map of the
"name"=<value> property pairs.

QmfDescribed Class

The isDescribed() method of an instance of a QmfDescribed class
returns True. The SchemaCache allows the QmfDescribed instance to
retrieve the instance of the schema identified by SchemaClassId (TBD).

SchemaMethod instance

The map encoding of a SchemaMethod:

Index

Optional

Type

Description

"_desc"

Y

string

Description of the method.

"_arguments"

Y

map

Map of "name":<SchemaProperty> values, one for each argument to the method.

Note that the "dir" SchemaProperty attribute applies to each
argument. If "dir" is not specified, it is assumed to be "I".

Schema for Data Objects and Events

The structure of QmfData objects is formally defined by the class SchemaObjectClass.

The structure of QmfEvent objects is formally defined by the class SchemaEventClass.

Both of these classes derive from the virtual base SchemaClass.

Agent applications may dynamically construct instances of these objects by adding properties and methods at run time. However, once the Schema is made public, it must be considered immutable, as the hash value must be constant once the Schema is in use.

QMF defines the following classes to represent data and event schema:

No Format

class SchemaClass(QmfData):
      <constructor>( classId=<class SchemaClassId>,
No Format

class QmfDescribed(QmfData):
      <constructor>( map of "name"=<AMQP Type> pairs, _const=False,
                     _schemaId=<class SchemaClassId>, SchemaCache )
      <constructor>( map encoding of a QmfDescribed instance, SchemaCache _desc=optional AMQP string containing a human-readable description for this schema)
      .getSchemaClassIdget_class_id(): returnsreturn the identifierSchemaClassId that ofidentifies thethis Schema thatinstance.
      .generate_hash(): generate a hash over the body of the schema, and return a string representation of the hash in    describes the structure of the data.
      .getPrimaryKey(): return a string composed from concantenating
  format  "%08x-%08x-%08x-%08x"

The map encoding of an instance of the SchemaClass class extends the map of its parent class with elements for the following class properties.

Index

Optional

Type

Description

"_schema_id"

N

map

Map containing the SchemaClassId for this object.

No Format

class SchemaObjectClass(SchemaClass):
      <constructor>( classId=<class SchemaClassId>,
          the values of all properties whose names appear in the schema's
            Primary Key List.  Each value is converted to an AMQP
 _desc=optional AMQP string containing a human-readable description for this schema,
                     _props=map of "name"=<SchemaProperty> string, then concantenated in the order given by the
instances,
                     _meths=map of "name"=<SchemaMethod> instances,
              schema's Primary Key List.       _id_names=(optional) ordered list of "name"s used to identify the properties whose values are used to construct the object identifier)

      .mapEncodeget_id_names(): returnsreturn aan mapordered representationlist of thenames QmfDescribed
of the values that are used to construct instance,the suitablekey for identifying
 use by the constructor.

The map encoding of an instance of the QmfDescribed class:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"properties"

Y

map

Map of "name"=<value> pairs, one for each property.

QmfManaged Class

The QmfManaged class represents a data object that is owned by a
particular Agent. All QmfManaged objects contain a unique object
identifier.

The isManaged() method of an instance of a QmfManaged class
returns True.

The QmfManaged class extends the QmfDescribed class:

No Format

class QmfManaged(QmfDescribed):
      <constructor>( map of "name"=<AMQP Type> pairs, _const=False,
                     _schemaId=<class SchemaClassId>, SchemaCache,       unique instances of this class.  Returns None if no list defined.
      .get_property_count(): return the count of SchemaProperty's in this instance.
      .get_properties(): return a map of "name":<SchemaProperty> entries for each value in the object.
      .get_property("name"): return the SchemaProperty associated with "name", else None if "name" value does not exist.

      .get_method_count(): return the count SchemaMethod's in this instance.
      .get_methods(): return a map of "name":<SchemaMethod> entries for each method associated with    _agentId=<class AgentId> )the object.
      <constructor>( map encoding of a QmfManaged instance, SchemaCache )
      .getObjectId(): return ObjectId for this object.
.get_method("name"): return the SchemaMethod associated with the "name", else None if "name" does not exist or is not a method.

      .getTimestamps(add_property("name", SchemaProperty): returnsadd a list of timestamps describing thenew property.
      .add_method("name", SchemaMethod): add a new method.
             lifecycle.set_id_names([name-list]): set the value of the object.order list Allof timestampsnames are
to use when constructing the object identifier.

The map encoding of an instance of the SchemaObjectClass class extends the map of its parent class with elements for the following class properties.

Index

Optional

Type

Description

"_primary_key"

Y

list

Order list of property names used to construct the primary key for objects defined by this schema

No Format

class SchemaEventClass(SchemaClass):
      <constructor>( classId=<class SchemaClassId>,
          represented by the AMQP timestamp type.
      _desc=optional AMQP string containing a human-readable description for this event,
         [0] = time of last update from Agent,
     _props=map of "name":SchemaProperty instances)
      .get_property_count(): return the number       [1] = creation timestamp of properties.
      .get_properties(): return a map of "name":<SchemaProperty> entries for each property in the event.
      [2] = deletion timestamp, or zero if not deleted.
.get_property("name"): return the SchemaProperty associated with "name".

      .isDeleted(add_property("name", SchemaProperty): Trueadd ifa deletion timestamp not zeronew property.

The map encoding of an a SchemaEventClass instance of the QmfManaged class:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"agent_id"

N

map

Map representation of the AgentId value.

"properties"

Y

map

Map of "name"=<value> pairs, one for each property.

Object Identification

An instance of a managed object must be uniquely identified within the
management system. This is done by combining an object's Primary Key
with the identifier for the agent which manages the object.

Each managed object is identified by its Primary Key. The Primary Key
is constructed by concatenating the values of the object's properties
that are named in the schema's Primary Key List.

uses the same format as the map for the SchemaClass.

Data Management

QMF allows data managment via the Query, Subscription, and Method Call actions.

Queries

A Query is a mechanism for interrogating the management database. A Query represents a selector which is sent to an Agent. The Agent applies the Query against its management database, and returns those objects which meet the constraints described in the query.

A Query must specify the class of information it is selecting. This class of information is considered the target of the query. Any data objects selected by the query will be of the type indicated by the target.

A Query may also specify a selector which is used as a filter against the set of all target instances. Only those instances accepted by the filter will be returned in response to the query.

Queries are expressed using the following map syntaxFor example, assume a managed object with the following property map:

No Format
{"field1query" : {"foowhat":<target>,
 "field2"  : "bar",
 "field3" : 42,
 "field4" : "baz"}
    <selector_type>:<selector_params>}
}

Where:

The value of the "what" key is a map that specifies the target for the Query. The Agent will return a list of instances of target types that match the query.

<target> is implemented as a map with a single element in the formatand assume the Primary Key List defined by the managed object's schema
is:

No Format
["field1", "field3"]

The Primary Key for this object would be:

No Format

"foo:42"

QMF inserts ":" between each field.

Note that these Primary Key values are not unique across Agents.
Therefore, a globally unique name for an instance of a managed object
is the concatenation of the object's name and the managing Agent's
AgentId. This unique object identifier is represented by the ObjectId class.

ObjectIds are considered hashable. That is, it is a requirement
that ObjectIds are deterministically sortable.

No Format

class ObjectId:
      <constructor>(agentid=class AgentId, 
                    key="primary key string")
      .getAgentId(): returns AgentId
      .getPrimaryKey(): returns the primary key string.
      .operators(==, !=, <, >) supported.
      .mapEncode(): returns a map representation of the ObjectId.

The map encoding of an instance of an ObjectId:

Index

Optional

Type

Description

"agent_id"

N

map

Map representation of the AgentId value.

"primary_key"

N

string

The Primary Key string.

QmfEvent Class

A QMF Event is a type of QmfDescribed data that is not managed.
Events are notifications that are sent by Agents.
Unlike QmfManaged objects, events do not correspond to managed data on the
Agent. Instead, an event notifies a Console of a change in some
aspect of the system under management. For example, an event may
indicate that a threshold was exceeded, or a resource was returned.
The structure of an event is described by the SchemaEventClass. An
instance of an event is represented by the QmfEvent class.

A timestamp - in milliseconds since midnight, January 1, 1970 UTC - is
associated with each QmfEvent instance.

No Format

class QmfEvent(QmfDescribed):
      <constructor>( timestamp, agentId, map of "name"=<AMQP Type> pairs,
                     _const=False, _schemaId=<class SchemaClassId>,
                     SchemaCache )
      <constructor>( map encoding of a QmfEvent instance, SchemaCache )
      .getTimestamp(): return a timestamp indicating when the Event
                       occurred.
      .getAgentId(): return the class AgentId of this issuing agent.

The map encoding of an instance of the QmfDescribed class:

Index

Optional

Type

Description

"schema_id"

N

map

Map containing the SchemaClassId for this object.

"timestamp"

N

AMQP Timestamp

Time the event occurred.

"agent_id"

N

map

Map representation of the AgentId value.

"properties"

Y

map

Map of "name"=<value> pairs, one for each property.

Data Management

The role of a QMF component determines how it will interact with
managment data. Therefore the QmfManaged class is subclassed
to provide an Agent specific implementation and a Console specific
implementation.

The Console application represents a managed data object by the
QmfConsoleData class. The Console has "read only" access to the
properties in the data object via this class. The
Console can also invoke the methods defined by the object via this
class. The actual data stored in this object is cached from the
Agent. In order to update the cached values, the Console invokes the
refresh() method.

Note that the refresh() and invokeMethod() methods require
communication with the remote Agent. As such, they may block. For
these two methods, the Console has the option of blocking in the call
until the call completes. Optionally, the Console can receive a
notification asynchronously when the operation is complete. See below
for more detail regarding synchronous and asynchronous API calls.

{"<target name string>": <optional map of target qualifiers>}

QMF defines the following values for <target name string>:

Target

Description

"schema_package"

Query against the set of known packages. Returns a list of package name strings.

"schema_id"

Query against the set of SchemaClass objects, return a list of SchemaClassId instances for the objects that match.

"schema"

Query against the set of SchemaClass objects, and return a list of matched SchemaClass instances.

"object_id"

Query against the set of managed QmfData objects, return a list of name strings for all matching instances.

"object"

Query against the set of managed objects, return a list of matching QmfData instances.

"agent"

Query against all agents within the current QMF domain, return a list of name strings for each matching agent. Used only by the "agent-locate" message.

more tbd ...

...

The value of the <target name string> map entry is ignored for now, its use is TBD.

The selector_type is optional. If it is not present, then the Query has no filter. The Agent will return every instance of type target it has. If selector_type is present, it may be one of the following supported values:

  • "id" - an exact match against the target's unique identifier.
  • "where" - a logical expression to apply to the target.
  • ...more tbd...

Only one selector_type is allowed in the Query at a time.

"id" Selector

A Query with an id selector is used to find one particular instance of a given target type. The value of the "id" keyword is a type that suitably represents an exact identifier for the target type. The Agent will return the first instance that matches the identifier.

id selectors are only valid for the following subset of targets:

Target

Selector Description

"schema"

A SchemaClassId

"object"

String containing the object identifier

"agent"

String containing the name of the agent

The Agent will return no matches should a Query using an id selector specify a target name not in the above subset.

"Where" Selector

A Query with a where selector describes a logical expression that is used to filter the target set. This logical expression is built from a set of boolean operations that are applied against the target's data. These boolean operations may be combined using logical operations.

The Agent will apply the logical expression against every instance of the target type, and return the set of instances for which the expression evaluates as True.

The value of the "where" keyword is a list representation of a predicate expression. QMF will support the following syntax for predicate expressions:

No Format

PREDICATE-EXP: [LOGIC-OP LOGIC-ARG]
LOGIC-ARG: PREDICATE-EXP
LOGIC-ARG: BOOL-EXP LOGIC-ARG
LOGIC-ARG: BOOL-EXP

BOOL-EXP: [BOOL-OP BOOL-ARG]
BOOL-ARG: VARIABLE BOOL-ARG
BOOL-ARG: CONST BOOL-ARG
BOOL-ARG:

CONST: [QUOTE NAME]
CONST: [QUOTE ATOMIC]
CONST: ATOMIC

VARIABLE: [UNQUOTE NAME]
VARIABLE: NAME

ATOMIC: any non-string type
NAME: string

QUOTE: "quote"
UNQUOTE: "unquote"

LOGIC-OP: string
BOOL-OP: string

In the above expressions, the left and right braces indicate lists. For example, BOOL-EXP is a list containing a BOOL-OP followed by BOOL-ARG.

A BOOL-EXP is a boolean test that is applied against the target. BOOL-OP defines the boolean operation that is performed on the arguments. QMF will define a set of string literals representing the supported boolean operations. At minimum, the following boolean operators are defined:

  • "eq" - equality
  • "ne" - inequality
  • "lt" - arithmetical/lexical less-than
  • "le" - arithmetical/lexical less-than-or-equal
  • "gt" - arithmetical/lexical greater-than
  • "ge" - arithmetical/lexical greater-than-or-equal
  • "re_match" - string regular expression match (one argument)
  • "exists" - True if named value is present in target, else False (one argument)
  • "true" - always true (no arguments)
  • "false" - always false (no arguments)
  • <more tbd>

All operators are binary unless otherwise noted.

LOGIC-OP defines the logical operation that is applied to its arguments. QMF will define a set of string literals representing supported logical operations. At minimum, the following logical operators will be defined:

  • "and" - logical AND, all arguments must evaluate to True.
  • "or" - logical OR, at least one argument must evaluate to True
  • "not" - logical NOT, all arguments must evaluate to False
  • <more tbd>

Logic operations are "short-circuiting". That is, evaluation ceases as soon as the truth value of the expression is determined. For example, the evaluation of an "and" expression stops when the first argument that evaluates as False is found.

QMF considers string arguments in boolean expressions to be names of data values in the target object. When evaluating a predicate expression, QMF will fetch the value of the named data item from each candidate target object. The value is then used in the boolean expression. In other words, QMF considers string arguments to be variables in the expression. In order to indicate that a string should be treated as a literal instead, the string must be quoted using the "quote" expression.

For example, the following boolean expression contains the data item named "employee" against the string literal "Joey Jojo":

No Format

        ["eq" "employee" ["quote" "Joey Jojo"]]

In implementation, predicate expressions are nested lists. The first element of all lists is the operator keyword string. The remaining list elements are arguments to the operator.

Examples:

Assume a QmfData type defines fields named "name", "address" and "town". The following predicate expression matches any instance with a name field set to "tross", or any instance where the name field is "jross", the address field is "1313 Spudboy Lane" and the town field is "Utopia":

No Format

 ["or" ["eq" "name" ["quote" "tross"]]
       ["and" ["eq" "name" ["quote" "jross"]]
No Format

class QmfConsoleData(QmfManaged):
      .refresh([reply-handle | timeout]): request that the Agent
                    update the value of this object's contents.
      .invokeMethod(name, inArgs{}, [[reply-handle] | [timeout]]): 
                          invoke the named method.

The Agent that manages the data represents it by the
QmfAgentData class. The Agent is responsible for managing the
values of the properties within the object, as well as
servicing the object's method calls. Unlike the Console, the Agent
has full control of the state of the object.

No Format

class QmfAgentData(QmfManaged):["eq" "address" ["quote" "1313 Spudboy Lane"]]
      .destroy(): mark the object as deleted by setting the deletion
  ["eq" ["quote" "Utopia"] "town"]
                timestamp to the current time.
      .setProperty(name, value): update the value of the property.]
]

Assume a QmfData type with fields "name" and "age". A predicate to find all instances with name matching the regular expression "?ross" with an optional age field that is greater than the value 29 or less than 12 would be:

No Format

["and" ["re_match" "name" ["quote" "?ross"]]
       ["and" ["exists" "age"]
      .incProperty(name, delta): add the delta to the property
 ["or" ["gt" "age" 27]  .decProperty(name, delta): subtract the delta from the property
      ?tbd?
Invoking Methods

A managed object's methods provide a mechanisms for a Console application to
perform a "remote procedure call" against the object. The method
actually executes on the Agent, and the result is passed back to the
Console on completion.

The value(s) returned to the Console when the method call completes
are represented by the MethodResult class. The MethodResult class
indicates whether the method call succeeded or not, and, on success,
provides access to all data returned by the method call.

Should a method call result in a failure, this failure is indicated by
the presence of a QmfData object in the MethodResult. This object is
described as an "exception", and contains a description of the reason
for the failure. There are no returned parameters when a method call
fails.

A successful method invokation is indicated by the absence of an
exception in the MethodResult. In addition, a map of returned
parameter values may be present. The structure of the returned
parameters is described by the SchemaMethod for the method.
The map contains only those parameters that the SchemaMethod marks
with an "output" direction.

No Format

class MethodResult:
      <constructor>( QmfData <exception> | <map of properties> )
      .getException(): returns exception data if method fails.
      .getArguments(): returns a map of "name"=<value> pairs
                       of all returned arguments.
      .getArgument(<name>): returns value of argument named "name".

Queries

A Query is a mechanism for interrogating the management database. A
Query represents a selector which is sent to an Agent. The Agent
applies the Query against the management database, and
returns those objects which meet the constraints described in the query.

Queries are expressed using the following map object:

No Format

{"query": {"what":<target>}
          {"where":<expression selector>}
          ...future selectors....
}

Where:

<target> indicates the desired object to match. These are
implemented as strings containing reserved words that identify the
target type. The query returns a list of instances of target types
that match the query. QMF queries will support the following values
for <target>:

Target

Description

"schema_id"

Query against the set of schema class identifiers, return
a list of matched SchemaClassId instances.

"schema"

Query against class SchemaClass objects, and
return a list of matched SchemaClass instances.

"object_id"

Query against an agent's set of known ObjectsIds, return
a list of matching ObjectId instances.

"mgt_data"

Query against an agent's set of QmfManaged data, return a
list of matching QmfManaged instances.

"agent_id"

Query against all agents within the QMF domain, return a
list of matching AgentId instances.

more tbd ...

...

<expression selector> describes a logical match expression
that is applied to the target. The expression can be built up from
the following syntax:

No Format

  binary_cmp=["eq", "ne", "lt", "le", "gt", "ge", "re_match"]
  unary_cmp=["present"]

  compare_exp = [binary_cmp, <name>, <value>] | 
                [unary_cmp, <name>]

  n_ary_logic = ["and", "or"]
  unary_logic = ["not"]

  logic_exp = [n_ary_logic, <expression>, <expression>, ... ] | 
              [unary_logic, <expression>] 

  expression = compare_exp | logic_exp

In implementation, n_ary operations may be expressed as (n+1)-element
lists in the format: <keyword>, <arg1>, <arg2>, ..., <argN>. Unary
operations may be expressed as 2-element lists in the format:
<keyword>, <arg1>

Examples:

["lt" "age" 12]]
       ]
]

The valid set of <name> values in an predicate expression is determined by the target of the Query. QMF reserves a set of <name> values it recognizes. The tables below list the set of name strings allowed for each type of target, and what these names evaluate to from the target instance.

Target "schema_package" valid names

Description

"_package_name"

Evaluates to the schema's package name string.

Target "schema_id" and "schema" valid names

Description

"_package_name"

Evaluates to the schema's package name string.

"_class_name"

Evaluates to the schema's class name string.

"_type"

Evaluates to the schema's type string ("_data" or "_event").

"_hash_str"

Evaluates to the schema's hash string value.

"_schema_id"

Evaluates to the schema's full identifier (SchemaClassId).

<property-name>

Name of a property defined by the schema. Evaluates to the name string, or None if the property is not defined.

<method-name>

Name of a method defined by the schema. Evaluates to the name string, or None if the method is not defined.

Target "agent_info" valid names

Description

"_name"

Evaluates to the agent's name string.

Target "object_id" and "object" valid names

Description

"_package_name"

If schema assigned, evaluates to the schema's package name string, else None.

"_class_name"

If schema assigned, evaluates to the schema's class name string, else None.

"_hash_str"

If schema assigned, evaluates to the schema's hash string value, else None.

"_schema_id"

If schema assigned, evaluates to the schema's full identifier (SchemaClassId), else None.

"_object_id"

Evaluates to the identifying name string.

"_update_ts"

Evaluates to the last update timestamp.

"_create_ts"

Evaluates to the creation timestamp.

"_delete_ts"

Evaluates to the deletion timestamp.

<value-name>

Specifies the name of a data item in the QmfData data object. Evaluates to the value of the data item.

QMF reserved <name> values all start with the underscore character "_". Do not create value or method names starting with an underscore.

The QmfQuery class represents a query:

No Format

class QmfQuery:
      <constructor>(target=<target name>,
                    _target_params=None,
                    _predicate=(optional)<predicate map>,
                    _id=(optional)<target-identifier>)
      <constructor>(map=Map representation of a QmfQuery, as generated by .map_encode())
      .get_target(): return target name
      .get_target_param(): return params.
      .get_selector(): returns QmfQuery.ID or QmfQuery.PREDICATE
      .get_id(): return identifier if selector type is QmfQuery.ID, else None
      .get_predicate(): return predicate expression if selector type is QmfQuery.PREDICATE
      .evaluate(QmfData): evaluate query against a QmfData instance.  Returns True if query matches the instance, else false.
      .map_encode(): returns a map encoding of the QmfQuery instance

The map encoding of a QmfQuery:

Index

Optional

Type

Description

"what"

N

map

The target map.

"id"

Y

map

The identifier, map format determined by target type.

"where"

Y

map

The predicate map.

Example Queries

With the above syntax, QMF queries can be constructed using AMQP maps and lists. For example, a query for all known schema identifiers:

No Format

{"query": {"what": {"schema_id":None}}}

Note that the absence of a "where" clause acts as a "match all"
directive. This query will return a list of all known SchemaId's.

A query for all schema identifiers whose package names are equal to the string "myPackage":

No Format

{"query": {"where": ["eq" "_package_name" ["quote" "myPackage"]]
No Format

     the conditional:
    
         "name" == "tross" or ("name" == "jross" 
                                and "address" == "1313 Spudboy Lane"
                                and "town" == "Utopia")

     would be expressed in a python-ish list as:
  
         ["or", ["eq", "name", "tross"],
                ["and", ["eq", "name", "jross"],"what": {"schema_id": None}
                        ["eq", "address", "1313 Spudboy Lane"]}
}

Query for the particular QmfData data object with the identifier "Agent007":

No Format

{"query": {"what": {"object":None},
           "id": "Agent007"}
}

Query for the particular SchemaObjectClass instance that has the package name "MyPackage", class name "MyClass", that has a hash string of 'b49cda2d-bbe53b97-9f6ee5d1-485ea3da':

No Format

{"query": {"what": {"schema":None},
              ["eq", "town", "Utopia"]]]


     the conditional:

         !(("name" matches regular expression "?ross") and 
 "id": {"_package_name": "MyPackage",
             (("age" property is present) or ("status_class_name": is not "sleepyMyClass")))

,
       would be:

        ["not", ["and", ["re_matchtype",: "name_data", "?ross"],
                       "_hash_str": "b49cda2d-bbe53b97-9f6ee5d1-485ea3da"}}
}

Query for all SchemaClass objects that match a given package and class
name:

No Format

{"query": {"what": {"schema": None}
           "where": ["and" ["eq" "_package_name" ["quote" "myPackage"]] ["or", ["present", "age"],
                               ["ne", "status", "sleepy"]]]]

The valid set of <name> values in the expressions above is determined
by the <target> supplied in the "what" qualifier. The tables below
list the set of name strings allowed for each type of query:

"schema_id" query names

Description

"package_name"

Compare value against the package name string.

"class_name"

Compare value against the class name string.

"type"

Compare value against the schema type strings "data" and
"event".

"hash_str"

Compare against the schema's hash string value.

"schema" query names

Description

"package_name"

Compare value against the package name string.

"class_name"

Compare value against the class name string.

"type"

Compare value against the schema type strings "data" and
"event".

"hash_str"

Compare against the schema's hash string value.

"agent_id" query names

Description

"vendor"

Compare against the value of the agent's vendor string.

"product"

Compare against the value of the agent's product string.

"name"

Compare against the value of the agent's name string.

"object_id" query names

Description

"vendor"

Compare against the value of the managing agent's vendor
string.

"product"

Compare against the value of the managing agent's product
string.

"name"

Compare against the value of the managing agent's name
string.

"primary_key"

Compare against the value of the object's primary key
string.

"mgt_data" query names

Description

"package_name"

Compare value against the package name string.

"class_name"

Compare value against the class name string.

"type"

Compare value against the schema type strings "data" and
"event".

"hash_str"

Compare against the schema's hash string value.

"vendor"

Compare against the value of the managing agent's vendor
string.

"product"

Compare against the value of the managing agent's product
string.

"name"

Compare against the value of the managing agent's name
string.

"primary_key"

Compare against the value of the object's primary key
string.

"property()"

Specifies the name of property in the QmfManaged data
object. The value of the property is used for the comparison.
Example: property(address) retrieves the value of the property named
"address"

a <expression selector> to apply against the
objects properties. The name strings of this <expression selector>
are the names of the object's properties.|

Example Queries

With the above syntax, QMF queries can be constructed using AMQP maps
and lists.

For example, a query for all known schema identifiers:

["eq" "_class_name" ["quote" "someClass"]]]
          }
}

Query all managed objects belonging to the "myPackage" package, of the class "myClass", whose object_id matches a given regular expression. Return a list of matching object identifiers:

No Format

{"query": {"what": {"object_id": None},
           "where": ["and" ["eq" "_package_name" ["quote" "myPackage]]
                           ["eq" ["quote" "myClass"] "_class_name"]
                           ["re_match" "_primary_key" ["quote" "foo*"]]
                    ]
          }
}

Query for all QmfData objects from a particular schema, whose "temperature" property is greater or equal to 50:

No Format

{"query": {"what": {"object": None},
           "where": ["and" ["eq" "_package_name" ["quote" "aPackage]]
                           ["eq" ["quote" "someClass"] "_class_name"]
                           ["ge" "temperature" 50]
                    ]
          }
}

In the previous example, the agent will convert the value 50 to a type compatible with the type given by the "temperature" property's schema in order to do the comparison.

Query for all objects that match the given schema, which have a property named "state" which does not match the regular expression "$Error*", or whose "owner" property is not set to "Cartman".

No Format

No Format

    {"query": {"what": {"schema_id"}}

Note that the absence of a "where" clause acts as a "match all"
directive.

A query for all schema identifiers whose package names are equal to
the string "myPackage":

No Format

    {"query": {"where": ["eq", "package_name", "myPackage"],object": None},
           "where": ["and" ["eq" "_package_name" ["quote" "aPackage]]
               "what":"schema_id"
            ["eq"  }["quote" "someClass"] "_class_name"]
    }

Query for all SchemaClass objects that match a given package and class
name:

No Format

      {"query": {"what":"schema",
               "where": ["andor", ["eqnot", ["packagere_namematch", "myPackage"],state" ["quote" "$Error"]]]
                                 ["eqne" "owner", ["class_namequote", "someClassCartman"]]
              }
     }

Query for an ObjectId whose primary key matches a given regular
expression:

No Format

    {"query": {"what":"object_id",
   ]
            "where": ["re_match", "primary_key", "foo*"]
        ]
          }
    }

Query for all QmfManaged objects from a particular schema, whose
"temperature" property is greater or equal to 50:

No Format

    {"query": {"what":"mgt_data",
               "where": ["and", ["eq", "package_name", "myPackage"],
                                ["eq", "class_name", "someClass"],
                                ["ge", "property(temperature)", 50]
                        ]
              }
    }

In the previous example, the agent will convert the value 50 to a
type compatible with the type given by the "temperature" property's
schema in order to do the comparison.

Query for all objects that match the given schema, which have a
property named "state" which does not match the regular expression
"$Error*", or whose "owner" property is not set to "Cartman".

Subscriptions

A subscription allows a Console application to monitor specific management data for changes in state. A Console creates a subscription with an Agent based on a Query. The Query specifies the set of management data that is to be monitored. The Agent will periodically publish updates to the subscribing Console(s).  The update contains a snapshot of the of the monitored data. 

A subscription remains in effect for a predetermined amount of time.  Once the subscription expires, no further updates are published.  A console may elect to refresh a subscription prior to its expiration.   Alternatively, a Console may explicitly cancel the subscription when the data no longer needs to be monitored.

Invoking Methods

QMF allows a Console application to perform a "remote procedure call" on the Agent. The procedure - or method - call executes on the Agent. On completion a result is passed back to the Console. Method calls can be associated with an instance of a data object, or applied to the Agent as a whole.

The structure of a method call may be described by the schema associated with the object. The schema can define a name for the method and a description of its input and output parameters. The SchemaMethod class is used for this purpose.

The value(s) returned to the Console when the method call completes are represented by the MethodResult class. The MethodResult class indicates whether the method call succeeded or not, and, on success, provides access to all data returned by the method call. Returned data is provided in a map indexed by the name of the parameter. The map contains only those parameters that are classified as "output" by the SchemaMethod.

Should a method call result in a failure, this failure is indicated by the presence of an error object in the MethodResult. This object is represented by a QmfData object. The structure of this QmfData object is application-defined, but should contain a description of the reason for the failure. There are no returned parameters when a method call fails.

A successful method invokation is indicated by the absence of the QmfData error object in the MethodResult.

No Format

class MethodResult:
      <constructor>( QmfData <exception> | <map of properties> )
      .succeeded(): returns True if the method call executed without error.
      .get_exception(): returns the QmfData error object if method fails, else None
      .get_arguments(): returns a map of "name"=<value> pairs of all returned arguments.
      .get_argument(<name>): returns value of argument named "name".

Management Events

An event is a notification that is sent by an Agent to alert Console(s) of a change in some aspect of the system under management. Agents publish events asynchronously. Consoles have the option of receiving events from a given Agent.

To publish an event, the Agent application must call the raise_event() method, passing an instance of a QmfEvent object. The Agent publishes the QmfEvent instance.

To receive events, the Console application must enable event reception on a per-agent basis. The Console application does this by calling the enable_events() method on the desired Agent instance. Published events from the Agent will then appear on the Console's work-queue. The Console application may disable events by invoking the Agent's disable_events() method.

Work-Queue Event Model.

The original QMF API defined a set of callback methods that a Console or Agent application needed to provide in order to process asynchronous QMF events. Each asynchonous event defined its own callback method.

The new API replaces this callback model with a work-queue approach. All asynchronous events are represented by a WorkItem object. When a QMF event occurs it is translated into a WorkItem object and placed in a FIFO queue. It is left to the application to drain this queue as needed.

This new API does require the application to provide a single callback. The callback is used to notify the application that WorkItem object(s) are pending on the work queue. This callback is invoked by QMF when one or more new WorkItem objects are added to the queue. To avoid any potential threading issues, the application is not allowed to call any QMF API from within the context of the callback. The purpose of the callback is to notify the application to schedule itself to drain the work queue at the next available opportunity.

For example, a console application may be designed using a select() loop. The application waits in the select() for any of a number of different descriptors to become ready. In this case, the callback could be written to simply make one of the descriptors ready, and then return. This would cause the application to exit the wait state, and start processing pending events.

The callback is represented by the Notifier virtual base class. This base class contains a single method. An application derives a custom notification handler from this class, and makes it available to the Console or Agent object.

No Format

class Notifier:
    .indication():  Called when the internal work queue becomes non-empty due to the arrival of one or more WorkItems.
        This method will be called by the internal QMF management thread - it is illegal to invoke any QMF APIs from
        within this callback.  The purpose of this callback is to indicate that the application should schedule itself
        to process the work items.

The WorkItem class represents a single notification event that is read from the work queue:

No Format

class WorkItem:
    .get_type(): Identifies the type of work item.
    .get_handle(): returns the reply handle for an asynchronous operation, if present.
    .get_params(): Returns the payload of the work item.  The type of this object is determined by the type of the workitem.

Console and Agent-specific WorkItem types are defined.

Console Application Model

This section describes the API that is specific to Console components.

A QMF console component is represented by a Console class. This class is the topmost object of the console application's object model.

A Console is composed of the following objects:

  • a connection to the AMQP bus
  • a queue of inbound work items
  • a collection of all known schemas
  • a list of all known remote Agents
  • a cache of known data object proxies

The connection to the AMQP bus is used to communicate with remote Agents. The queue is used as a source for notifications coming from remote Agents.

QmfConsoleData Class

The QmfData class is subclassed to provide a Console specific representation of management data.

The Console application represents a managed data object by the QmfConsoleData class. The Console has "read only" access to the data values in the data object via this class. The Console can also invoke the methods defined by the object via this class. The actual data stored in this object is cached from the Agent. In order to update the cached values, the Console invokes the instance's refresh() method.

Note that the refresh() and invoke_method() methods require communication with the remote Agent. As such, they may block. For these two methods, the Console has the option of blocking in the call until the call completes. Optionally, the Console can receive a notification asynchronously when the operation is complete. See below for more detail regarding synchronous and asynchronous API calls.

No Format

class QmfConsoleData(QmfData):
      .get_timestamps(): returns a list of timestamps describing the
                        lifecycle of the object.  All timestamps are
                        represented by the AMQP timestamp type.
                        [0] = time of last update from Agent,
                        [1] = creation timestamp
                        [2] = deletion timestamp, or zero if not deleted.
      .get_create_time(): returns the creation timestamp
      .get_update_time(): returns the update timestamp
      .get_delete_time(): returns the deletion timestamp, or zero if not yet deleted.
      .is_deleted(): True if deletion timestamp not zero.

      .refresh([reply-handle | timeout]): request that the Agent update the value of this object's contents.
      .invoke_method(name, inArgs{}, [[reply-handle] | [timeout]]): invoke the named method on this instance.

Asychronous Event Model.

The Console application must support the following WorkItem types:

  • AGENT_ADDED
  • AGENT_DELETED
  • NEW_PACKAGE
  • NEW_CLASS
  • OBJECT_UPDATE
  • EVENT_RECEIVED
  • AGENT_HEARTBEAT
  • SUBSCRIBE_RESPONSE
  • RESUBSCRIBE_RESPONSE
  • SUBSCRIPTION_INDICATION

These WorkItem types are described in detail below:

AGENT_ADDED

When the QMF Console receives the first heartbeat from an Agent, an AGENT_ADDED WorkItem is pushed onto the work-queue. The WorkItem's get_param() call returns a map which contains a reference to the new Console Agent instance. The reference is indexed from the map using the key string "agent". There is no handle associated with this WorkItem.

Note: If a new Agent is discovered as a result of the Console find_agent() method, then no AGENT_ADDED WorkItem is generated for that Agent.

AGENT_DELETED

When a known Agent stops sending heartbeat messages, the Console will time out that Agent. On Agent timeout, an AGENT_DELETED WorkItem is pushed onto the work-queue. The WorkItem's get_param() call returns a map which contains a reference to the Agent instance that has been deleted. The reference is indexed from the map using the key string "agent". There is no handle associated with this WorkItem.

The Console application must release all saved references to the Agent before returning the WorkItem.

NEW_PACKAGE

TBD.

NEW_CLASS

TBD.

OBJECT_UPDATE

TBD.

EVENT_RECEIVED

TBD

SUBSCRIBE_RESPONSE

The SUBSCRIBE_RESPONSE WorkItem returns the result of a subscription request made by this Console.  This WorkItem is generated when the Console's create_subscription() is called in an asychronous manner, rather than pending for the result. 

The get_params() method of a SUBSCRIBE_RESPONSE  WorkItem will return an instance of the following object:

No Format

class SubscribeParams:
      .get_subscription_id(): If the subscription is successful, this method returns a SubscriptionId object.
No Format

    {"query": {"what":"mgt_data",
               "where": ["and", ["eq", "package_name", "myPackage"],
                                ["eq", "class_name", "someClass"],
                                ["or", ["not", ["re_match", "property(state)", "$Error"]],
                    Should the subscription fail, this method returns None, and get_error() can be used to      ["ne", "property(owner)", "Cartman"]]obtain an
          application-specific QmfData error object.
      .get_publish_interval(): returns the time interval ]
in seconds on which the Agent will publish updates
      }
    }

Subscriptions

A subscription is a mechanism for monitoring management data for
changes in its state. A Console creates a subscription with an Agent
based on a Query. The Query specifies the set of management data that
is to be monitored. When the Agent detects changes to the selected
set, a notification is sent to the subscribing Console(s). A
Subscription is represented by the SubscriptionId class. A Console
must cancel the subscription when the console no longer needs to
monitor the data.

No Format

class SubscriptionId:for this subscription.
      ?tbd?

Agent Identifiers

An Agent is uniquely identified by an AgentId. An AgentId is a
three-tuple containing:

  • the name of the vendor that produced the agent
  • the name of the product using the agent
  • the name of the agent component within the product.

This naming convention allows for a single product to host multiple
distinct Agents. The Agent identifier is represented by the AgentId
class. An AgentId is considered hashable. That is, it is a
requirement that AgentIds are deterministically sortable.

No Format

class AgentId:
      <constructor>( vendor, product, name ).get_lifetime(): returns the time interval in seconds for the subscription. The subscription will automatically
          expire after this interval if not renewed by the console.
      .getVendorget_error(): return the vendor name string(optional) returns an application-specific QmfData object indicating why the subscription
          request failed.  Returns None if not supported.
      .getProductget_console_handle(): returnreturns the product name string
      .getName(): return agent component name string

By convention, AgentIds are specified as a string containing the
vendor, product, and name strings separated by colons ":", in that
order. For example: "company.com:OurProduct:AnAgent"

Console application model

A QMF console component is represented by a Console class. This class
is the topmost object of the console application's object model.

A Console is composed of the following objects:

  • a connection to the AMQP bus
  • a queue of inbound work items
  • a collection of all known schemas
  • a list of all known remote Agents
  • a cache of QmfConsoleObject proxies

The connection to the AMQP bus is used to communicate with remote
Agents. The queue is used as a source for notifications coming from
remote Agents.

Asychronous event model.

The original QMF API defined a set of callback methods that a Console
application needed to provide in order to process asynchronous QMF
events. Each asynchonous event defined its own callback method.

The new API replaces this callback model with a work-queue approach.
All asynchronous events are represented by a WorkItem object. When
a QMF event occurs it is translated into a WorkItem object and placed
in a FIFO queue. It is left to the console application to drain
this queue as needed.

This new API does require the console application to provide a single
callback. The callback is used to notify the console application that
WorkItem object(s) are pending on the work queue. This callback is
invoked by QMF when the work queue transitions from the empty to the
non-empty state. To avoid any potential threading issues, the console
application is not allowed to call any QMF API from within the
callback context. The purpose of the callback is to allow the console
application to schedule itself to drain the work queue at the next
available opportunity.

For example, a console application may be designed using a select()
loop. The application waits in the select() for any of a number
of different descriptors to become ready. In this case, the callback
could be written to simply make one of the descriptors ready, and then
return. This would cause the application to exit the wait state, and
start processing pending events.

The callback is represented by the Notifier virtual base class. This
base class contains a single method. A console application derives a
custom handler from this class, and makes it available to the Console
object.

No Format

class Notifier:
    .indication():  Called when the internal work queue becomes
    non-empty due to the arrival of one or more WorkItems. This method
    will be called by the internal QMF management thread - it is
    illegal to invoke any QMF APIs from within this callback.  The
    purpose of this callback is to indicate that the application
    should schedule itself to process the work items.  

The WorkItem class represents a single notification event that is read
from the work queue:

No Format

class WorkItem:
    #
    # Enumeration of the types of WorkItems produced by the Console
    #
    AGENT_ADDED = 1
    AGENT_DELETED = 2
    NEW_PACKAGE = 3
    NEW_CLASS = 4
    OBJECT_UPDATE = 5
    EVENT_RECEIVED = 7
    AGENT_HEARTBEAT = 8

    .getType(): Identifies the type of work item by returning one of
    the above type codes. 

    .getHandle(): return the handle for an asynchronous operation, if present.

    .getParams(): Returns the data payload of the work item.  The type
    of this object is determined by the type of the workitem (?TBD?). 

Local representation of a remote Agent.

The console application maintains a list of all known remote Agents.
Each Agent is represented by the Agent class:

console handle as passed to the create_subscription() call.

The SubscriptionId object must be used when the subscription is refreshed or cancelled - it must be passed to the Console's refresh_subscription() and cancel_subscription() methods.  The value of the SubscriptionId does not change over the lifetime of the subscription.

The console handle will be provided by the Agent on each data indication event that corresponds to this subscription.  It should not change for the lifetime of the subscription.

The get_handle() method returns the reply handle provided to the create_subscription() method call.  This handle is merely the handle used for the asynchronous response, it is not associated with the subscription in any other way.

Once a subscription is created, the Agent that maintains the subscription will periodically issue updates for the subscribed data.  This update will contain the current values of the subscribed data, and will appear as the first SUBSCRIPTION_INDICATION WorkItem for this subscription.

SUBSCRIPTION_INDICATION

The SUBSCRIPTION_INDICATION WorkItem signals the arrival of an update to subscribed data from the Agent. 

The get_params() method of a SUBSCRIPTION_INDICATION  WorkItem will return an instance of the following object:

No Format

class SubscribeIndication:
      .get_console_handle(): returns the console handle as passed to the create_subscription() call.
      .get_data(): returns a list containing all updated data objects associated with the subscripion.

The get_handle() method returns None.

RESUBSCRIBE_RESPONSE

The RESUBSCRIBE_RESPONSE WorkItem is generated in response to a subscription refresh request made by this Console.  This WorkItem is generated when the Console's refresh_subscription() is called in an asychronous manner, rather than pending for the result. 

The get_params() method of a RESUBSCRIBE_RESPONSE  WorkItem will return an instance of the following object:

No Format

class SubscribeParams:
      .get_subscription_id(): If the re-subscription is successful, this method returns an instance of
          the original SubscriptionId object.  Should the subscription fail, this method returns None,
          and get_error() can be used to obtain an application-specific QmfData error object.
      .get_publish_interval(): returns the time interval in seconds on which the Agent will publish updates
          for this subscription.
      .get_lifetime(): returns the time interval in seconds for the subscription. The subscription will automatically
          expire after this interval if not renewed by the console.
      .get_error(): (optional) returns an application-specific QmfData object indicating why the re-subscription
          request failed.  Returns None on successful resubscribe.
      .get_console_handle(): returns the console handle as passed to the create_subscription() call, if available.
          Note: if the Agent failed the resubscribe request due to an unrecognized subscription, this call may
          return None.

The get_handle() method returns the reply handle provided to the refresh_subscription() method call.  This handle is merely the handle used for the asynchronous response, it is not associated with the subscription in any other way.

Local representation of a remote Agent.

The console application maintains a list of all known remote Agents. Each Agent is represented by the Agent class:

No Format

class Agent:
      .get_name(): returns the identifying name string of the agent.  This name is used to send AMQP messages directly to this agent.
      .is_active(): returns True if the agent is alive (heartbeats have not timed out)
      .invoke_method(name, inArgs{}, [[reply-handle] | [timeout]]): invoke the named method against the agent.
      .enable_events(): allows reception of events from this agent.
      .disable_events(): prevents reception of events from this agent.
      .destroy(): releases this Agent instance.  Once called, the console application should not reference this instance again.
No Format

class Agent:
      <constructor>( AgentId )
      .getName(): returns the AgentId
      ?tbd?

The Console Object.

The Console class is the top-level object used by a console
application. All QMF console functionality is made available by this
object. A console application must instatiate one of these objects.

As noted below, some Console methods require contacting a remote
Agent. For these methods, the caller has the option to either block
for a (non-infinite) timeout waiting for a reply, or to allow the
method to complete asynchonously. When the asynchronous approach is
used, the caller must provide a unique handle that identifies the
request. When the method eventually completes, a WorkItem will be
placed on the work queue. The WorkItem will contain the handle that
was provided to the corresponding method call.

All blocking calls are considered thread safe - it is possible to have
a multi-threaded implementation have multiple blocking calls in flight
simultaineously.

If a name is supplied, it must be unique across all Consoles attached
to the AMQP bus under the given domain. If no name is supplied, a unique name will be
synthesized in the format: "qmfc-<hostname>.<pid>"

No Format
class Console:
      <constructor>(name=<name-str>,
                    domain=(optional) domain string for console's AMQP address,
                    notifier=<class Notifier>,
                    reply_timeout=<default for all   notifier=<class Notifier>blocking calls>,
                    agent_timeout=<default timeout for allagent blocking calls>heartbeat>,
                    subscription_duration=<default lifetime of a subscription>)

      .destroy(timeout=None): Must be called to release Console's resources.

      .addConnectionadd_connection(QPID Connection): Connect the console to the AMQP cloud.

      .removeConnectionremove_connection(conn): Remove the AMQP connection from the
          console.  Un-does the addConnectionadd_connection() operation, and
          releases any agents associated with the connection.  All
          blocking methods are unblocked and given a failure status.
          All outstanding asynchronous operations are cancelled
          without producing WorkItems.

      .getAddressget_address():
          Get the AMQP address this Console is listening to (type str).

      .findAgentfind_agent( classname AgentIdstring, [timeout | handle] ): Query for the
      presence of a specific agent in the QMF domain. Returns a
          class Agent if the agent
 is present.  If the agent is not present.already known Mayto bethe calledconsole, blockingthis (withcall defaultwill timeoutsend
      override), or may allow asynchronous completion (producing a
 query for the agent and WorkItemblock (with thedefault giventimeout handle)override) waiting for a response.

      .enableAgentDiscovery(enable_agent_discovery( [Query] ): Called to enable the asynchronous
          Agent Discovery process. Once enabled, AGENT_ADDADDED
   work items
      and AGENT_DELETED work items can arrive on the WorkQueue.  If a query is supplied, it will be used to filter agent
          notifications.

      .disableAgentDiscoverydisable_agent_discovery(): Called to disable the async Agent
      Discovery process enabled by calling enableAgentDiscoveryenable_agent_discovery().  

      .getWorkItemCountget_workitem_count(): Returns the count of pending WorkItems that
      can be retrieved. 

      .getNextWorkItem.get_next_workitem([timeout=0]): Obtains the next pending work
      item, or None if none available. 

      .releaseWorkItemrelease_workitem(wi): Releases a WorkItem instance obtained by
      getNextWorkItem(). Called when the application has finished
          processing the WorkItem. 

      .getAgentsget_agents(): Returns a list of available agents (class Agent)

      .getAgentget_agent( classname AgentIdstring ): Return the class Agent for the
          named agent, if known. 

      .getPackagesget_packages( [class Agent] ): Returns a list of the names of all known packages.  If an optional Agent is provided, then
          only those packages available from that Agent are returned.

      .get_classes( [class Agent] ):  Returns a list of SchemaClassIds for all knownavailable packagesSchema.  If an optional Agent is provided, then

          then the returned SchemaClassIds are limited onlyto those Schema packagesknown availableto fromthe thatgiven Agent are returned.

      .getClassesget_schema( class SchemaClassId [, class Agent] ):  ReturnsReturn a list of SchemaClassIds
     all available class SchemaClass across all known agents.
     for all available Schema.  If an optional Agent is provided,
 restrict the returned schema to those supported by that Agent.

  then   the returned SchemaClassIds are limited to those.get_objects( _SchemaClassId= | _package=, _class= |
          Schema      known to the given Agent.

 _object_identifier=,
                .getSchema( class SchemaClassId [timeout=], class Agent]): Return a list

              of all available class SchemaClass across all known agents.
          If an optional Agent is provided, restrict the returned
 [list-of-class-Agent] ): perform a blocking query for QmfConsoleObjects.  Returns a list (possibly empty) of matching
           objects. The selector for the schemaquery tomay thosebe supportedeither:
 by that Agent.

      .makeObject( SchemaClassId, **kwargs ):class returnsSchemaClassId an- uninitialized
all objects whose schema match the instanceschema ofidentified aby QmfDescribed data object.
_SchemaClassId parameter.
      .getObjects( _SchemaClassId= | _package=, _class= |
* package/class name - all objects whose schema are contained by the named package and class.
     _objectId=,
      * the object identified by _object_identifier
        [timeout=],
   This method will block until all known agents reply, or the timeout expires. Once the  [list-of-class-Agent] ): perform a blocking query
timeout expires, all
           data retrieved to date foris QmfConsoleObjectsreturned. If Returns a list (possibly empty) of matching
agents is supplied, then the query is sent to only those objectsagents.

  The selector for the query may be either:
     .create_subscription( agent, class Query, console_handle [, reply_handle] [, timeout],
      * class SchemaClassId - all objects whose schema match the
             [, publish_interval] [, lifetime] ):  creates schemaa identifiedsubscription byto _SchemaClassIdthe parameter.agent
          using *the package/class name - all objects whose schema are
       given Query.  The console_handle is an application-provided handle that will accompany each subscription update
          send from the containedAgent. by theSubscription namedupdates packagewill andappear class.
       as SUBSCRIPTION_INDICATION WorkItems on the Console's work queue.
    * the object identified by _objectId
 The publish_interval is the requested time interval in seconds on Thiswhich methodthe willAgent blockshould untilpublish allupdates. known agentsThe reply,lifetime
 or the
        parameter is the requested time interval in seconds for which this subscription timeoutshould expires.remain Oncein theeffect. timeout expires,Both allthe
          requested lifetime and publish_interval may be overridden by the Agent, dataas retrievedindicated toin datethe issubscription returnedresponse.  
          This Ifmethod amay listbe ofcalled agentsasynchronously isby supplied,providing thena the query is sent to
   reply_handle argument.  When called asynchronously, the result
          of this method call is returned in onlya those agents.  


      .createSubscription( class Query [, duration=<secs> [, list of agents] ): creates a
            subscription using the given Query.  If a list of agents
SUBSCRIBE_RESPONSE WorkItem with a handle matching the value of reply_handle.
          Timeout can be used to override the console's default reply timeout.  When called synchronously, this method returns a class
          SubscribeParams object containing the isresult provided,of the Query will apply only to those agents.
            Otherwise it will apply to all active agents, including
            those discovered during the lifetime of the subscription.
subscription request.

      .refresh_subscription( SubscriptionId [, lifetime] [,reply_handle] [, timeout] ): renews a subscription identified by
          SubscriptionId.  The Console may request a new subscription duration by providing a requested lifetime. This
          method may be called asynchronously Theby durationproviding argumenta can be used to override thereply_handle argument. When called asynchronously, the result
          of this console'smethod defaultcall subscriptionis lifetimereturned forin this
a SUBSCRIBE_RESPONSE WorkItem.  Timeout can be used to override the console's
 subscription.  Returns a class SubscriptionId.

    default reply timeout.refreshSubscription( SubscriptionId [, duration=<secs>] ):
      (re)activates a subscription.  Uses the console default duration
When called synchronously, this method returns a class SubscribeParams object containing
          the result unlessof the duration is explicitly specifiedsubscription request.

      .cancelSubscriptioncancel_subscription( SubscriptionId ): terminates the
     given subscription. 

Example Console Application

The following pseudo-code performs a blocking query for a particular agent.

No Format
logging.info( "Starting Connection" )
conn = Connection("localhost")
conn.connect()

logging.info( "Starting Console" )
myConsole = Console()
myConsole.addConnectionadd_connection( conn )

logging.info( "Finding Agent" )
myAgent = myConsole.findAgentfind_agent( AgentId( "com.aCompany.com", "Examples", "Examples.anAgent" ), _timeout=5 )

if myAgent:
   logging.info( "Agent Found: %s" % myAgent )
else:
   logging.info( "No Agent Found!")

logging.info( "Removing connection" )
myConsole.removeConnectionremove_connection( conn )

logging.info( "Destroying console:" )
myConsole.destroy( _timeout=10 )

...

No Format
class MyNotifier(Notifier):
    def __init__(self, context):
        self._myContext = context
        self.WorkAvailable = False

    def indication(self):
        print("Indication received! context=%d" % self._myContext)
        self.WorkAvailable = True

noteMe = MyNotifier( 668 )

logging.info( "Starting Connection" )
conn = Connection("localhost")
conn.connect()

myConsole = Console(notifier=noteMe)
myConsole.addConnectionadd_connection( conn )

myConsole.enableAgentDiscoveryenable_agent_discovery()
logging.info("Waiting...")


while not noteMe.WorkAvailable:
    print("No work yet...sleeping!")
    time.sleep(1)


print("Work available = %d  time.sleep(1)


print("Work available = %d items!" % myConsole.getWorkItemCount())
wi = myConsole.getNextWorkitem(timeout=0)
while wi:
    print("work item %d:%s" % (wi.getType(), str(wi.getParams())))
    wi = myConsole.getNextWorkitem(timeout=0)


logging.info( "Removing connection" )
myConsole.remove_connection( conn )

logging.info( "Destroying console:" )
myConsole.destroy( 10 )

Agent Application Model

A QMF agent component is represented by a instance of the Agent
class. This class is the topmost object of the agent application's
object model. Associated with a particular agent are

  • the set of objects managed by that agent
  • the schema that describes the objects owned by the agent
  • a collection of consoles that are interfacing with the agent

The Agent class communicates with the application using the same
notification-based model as the console. The agent maintains a
work-queue of pending requests. Each pending request is
associated with a handle. When the application is done servicing the
work request, it passes the response to the agent along with the
handle associated with the originating request.

items!" % myConsole.getWorkItemCount())
wi = myConsole.get_next_workitem(timeout=0)
while wi:
    print("work item %d:%s" % (wi.getType(), str(wi.getParams())))
    wi = myConsole.get_next_workitem(timeout=0)


logging.info( "Removing connection" )
myConsole.remove_connection( conn )

logging.info( "Destroying console:" )
myConsole.destroy( 10 )

Agent Application Model

This section describes the API that is specific to Agent components.

A QMF agent component is represented by a instance of the Agent class. This class is the topmost object of the agent application's object model. Associated with a particular agent are:

  • the set of objects managed by that agent
  • the set of schema that describes the structured objects owned by the agent
  • a collection of consoles that are interfacing with the agent

The Agent class communicates with the application using the same work-queue model as the console. The agent maintains a work-queue of pending requests. Each pending request is associated with a handle. When the application is done servicing the work request, it passes the response to the agent along with the handle associated with the originating request.

QmfAgentData Class

The Agent manages the data it represents by the QmfAgentData class - a derivative of the QmfData class. The Agent is responsible for managing the values of the properties within the object, as well as servicing the object's method calls. Unlike the Console, the Agent has full control of the state of the object.

No Format

class QmfAgentData(QmfData):
      .destroy(): mark the object as deleted by setting the deletion timestamp to the current time.
      .set_value(name, value): update the value of the property.
      .inc_value(name, delta): add the delta to the property
      .dec_value(name, delta): subtract the delta from the property
      ?tbd?

An agent can support one of two different models for managing its
object database of QmfAgentData objects: internal or external store.

...

An agent that implements internal object store takes gives full
responsibility for managing its associated objects. In this model,
the application passes a reference for each managed objects to the
agent. The agent manages the set of objects internally, directly
accessing the contents of the object in order to service console
requests.

With this model, the application's complexity is reduced. The
application needs to instantiate the object and register it with the
agent. The application also maintains a reference to the object, as
the application is responsible for updating the object's properties
as necessary.

The application must also service method calls invoked on the object.
The agent notifies the application when a method call has been
requested by a console. The application services the method call,
passing the result of the method back to the agent. The agent then
relays the response to the originating console.

The application may decide to delete an object instance. The
application does this by invoking the destroy() method on the object.
This notifies the agent, which will mark the object as deleted in its
database. Once the application invokes the destroy() method on an
object, it must no longer access the object. The agent will clean up
the object at a later point in time.

Internal object store is the default model for agent object
managment.

Data Consistency

The internal object store requires sharing of the managed data
between the agent and the application. The application is responsible
for keeping the data up to date, while the agent is responsible for
providing the data to client consoles. It is likely that these
components may be implemented in separate execution contexts. This
raises the possibility that a data item could be in the process of
being written to by the application at the same moment the agent
attempts to read it. This would result in invalid data being read.

To prevent this from occuring, the QmfAgentObject class provides
accessors for all property data in the object. These accessors provide
atomic access to the underlying data. Therefore, both the agent and
the application code must use these accessors to manipulate a shared
object's data.

External Object Store

An alternate agent implementation allows the application to take
full responsibility for managing the objects. With this model, all
instances of managed objects exist external to the agent. When a
console requests an action against an object, that action is
transferred from the agent to the application. The application then
must process the request, and send the result to the agent. The agent
then sends a reply to the requesting console.

The model gives full control of the managed objects to the
application, but usually requires more application development work.

Agent Class

The base class for the agent object is the Agent class. This base
class represents a single agent implementing internal store.

data objects to the QMF infrastructure. In this model, the application passes a reference for each managed object to the QMF agent. The agent manages the set of objects internally, directly accessing the contents of the object in order to service console requests.

With this model, the application's complexity is reduced. The application needs to instantiate the object and register it with the agent. The application also maintains a reference to the object, as the application is responsible for updating the object's properties as necessary.

However, the application must still service method calls. The agent notifies the application when a method call has been requested by a console. The application services the method call, passing the result of the method back to the agent. The agent then relays the response to the originating console.

The application may decide to delete an object instance. The application does this by invoking the destroy() method on the object. This notifies the agent, which will mark the object as deleted in its database. Once the application invokes the destroy() method on an object, it must no longer access the object. The agent will clean up the object at a later point in time.

Internal object store is the default model for agent object managment.

Data Consistency

The internal object store requires sharing of the managed data between the agent and the application. The application is responsible for keeping the data up to date, while the agent is responsible for providing the data to client consoles. It is likely that these components may be implemented in separate execution contexts. This raises the possibility that a data item could be in the process of being written to by the application at the same moment the agent attempts to read it. This could result in invalid data being read.

To prevent this from occuring, the QmfAgentObject class provides accessors for all data in the object. These accessors provide atomic access to the underlying data. Therefore, both the agent and the application code must use these accessors to manipulate a shared object's data.

External Object Store

An alternate agent implementation allows the application to take full responsibility for managing the objects. With this model, all instances of managed objects exist external to the agent. When a console requests an action against an object, that action is transferred from the agent to the application. The application then must process the request, and send the result to the agent. The agent then sends a reply to the requesting console.

The model gives full control of the managed objects to the application, but usually requires more application development work.

Agent Class

The base class for the agent object is the Agent class. This base
class represents a single agent implementing internal store.

No Format

class Agent:
      <constructor>( name=<name-string>,
                     domain=(optional) domain string for agent's AMQP address,
                     notifier=class Notifier,
                     heartbeat_interval=30,
                     max_msg_size=0)
      .get_name(): return the name string of the agent.
      .set_connection( QPID Connection ): connect the agent to the AMQP cloud.
      .register_object_class( class SchemaObjectClass ): Register a schema for an object class with the agent.  The agent must
            have a registered schema for an object class before it can handle objects of that class.
      .register_event_class( class SchemaEventClass ) : Register a schema for an event class with the agent.  The agent must
No Format

class Agent:
      <constructor>( vendor=<vendor-string>,
            have a registered schema for an event class  product=<product-string>,
      before it can handle events of that class.
      .raise_event( class QmfEvent ): Cause the agent to  name=<name-string>,
  raise the given event.
      .add_object( class QmfAgentData ): passes a reference to an instance of a managed classQMF Notifierobject ):to the vendor/product/name
  agent. The object's
          combinationname must uniquely identify this object among all objects known to this agent instance.
      .get_workitem_count(): Returns the count of pending WorkItems withinthat thecan QMFbe domainretrieved.
  The Notifier is used to alert the
            application to incoming method requests.
      .getAgentId(): return the agent identifier .get_next_workitem([timeout=0]): Obtains the next pending work item, or None if none available.
      .release_workitem(wi): Releases a WorkItem instance obtained by get_next_workitem(). Called when the application has finished
      .setConnection( QPID Connection ): connectprocessing the agent to the AMQP cloudWorkItem.
      .registerObjectClass( class SchemaObjectClass ): Register a
method_response(name="method name",
                schema for an object class with the agent.handle=<handle  The agent mustfrom WorkItem>,
            have a registered schema for an object class before it can
    out_args={output argument map}
         handle objects of that class.
      .registerEventClass( class SchemaEventClass ) : Register a
 error=<QmfData> ): Indicate to the agent that the application has completed schemaprocessing fora anmethod
 event class with the agent.  The agent must
            have a registeredrequest. schemaSee forthe andescription eventof classthe METHOD_CALL WorkItem.

AgentExternal Class

The AgentExternal class must be used by those applications that implement the external store model. The AgentExternal class extends the Agent class by adding interfaces that notify the application when it needs to service a request for management operations from the agent.

No Format

class AgentExternal(Agent):before it can
      <constructor>(name=<name-string>,
      handle  events of that class.
      .raiseEvent( class QmfEvent ): Cause the agent to raise the
domain=(optional) domain string for agent's AMQP address,
             given event.
      .addObject(notifier= class QmfManagedNotifier,
 object_name=<object name str> ):
            passes a reference to an instance of a managed QMF object
 heartbeat_interval=30,
                  to the agent. The object name must uniquely identify this
            object among all objects known to this agent.  Returns a
 max_msg_size=65535)
      .alloc_object_id( name="object name"): indicate to QMF that the named object is available to be managed.  Once this method returns,
          the agent will service classrequests ObjectIdfrom containingconsoles thereferencing objectthis identifierdata. 
      .getWorkItemCount(): Returns the count of pending WorkItems that
            can be retrievedfree_object_id( name="object name" ): indicate to QMF that the named object is no longer available to be managed.
      .getNextWorkItem([timeout=0]): Obtains the next pending workquery_response( handle=<handle from WorkItem>,
            item, or None if none available. 
    class  .releaseWorkItem(wiQmfAgentObject): Releasessend a WorkItemmanaged instanceobject obtainedin by
reply to a received query. Note that ownership of the object
  getNextWorkItem(). Called when the application has finished
  instance is returned to the caller on return from this processing the WorkItemcall. 
      .methodResponsequery_complete( handle=<handle from WorkItem>,
                      result=<status [outputcode> argument list],
             ):  Indicate to the agent that the application has completed processing a query request.
          result=<status code>,
                 Zero or more calls to the queryResponse() method should be invoked before calling query_complete().  If the query should
      exception=<QmfData> ): Indicate to thefail agent
- for example, due to authentication error - the result should be thatset theto applicationa hasnon-zero completederror processing a methodcode ?TBD?.

      .subscription_response( handle=<handle from WorkItem>,
   request. A result code of zero indicates success.  If the
            result code is non-zero, exception may optionally be set to a
    console_handle=<handle provided by Console for this subscription>,
        QmfData object that describes the failure.  On success, zero or
            more output arguments may be supplied as defined by the method's
subscription_handle=<agent-provided context>,
                       schema. 

AgentExternal Class

The AgentExternal class must be used by those applications that
implement the external store model. The AgentExternal class extends
the Agent class by adding interfaces that notify the application when
it needs to service a request for management operations from the
agent.

No Format

class AgentExternal(Agent):
    lifetime=<seconds>,  <constructor>(vendor, product, name, class Notifier)
publish_interval=<seconds>,
            .allocObjectId( name="object name"): create a class ObjectId
           error=<QmfData>): usingIndicate the objectresult nameof provided.a  The object name must be
SUBSCRIBE_REQUEST WorkItem.
          If the subscription request is successful, uniquethe acrossAgent allapplication objectsmust knownprovide toa thisunique agentsubscription_handle.  ReturnsIf areplying
          to  class ObjectId.  Once this method returns, the agent willa sucessful subscription refresh, the original subscription_handle must be supplied.  The lifetime parameter should be
          set to servicethe requestsduration fromof consolesthe referencingsubscription thisin ObjectIdseconds.
      .freeObjectId( class ObjectId ): releases the ObjectId
  The publish_interval should be set to the time interval in seconds
          between successive publications on previouslythis allocatedsubscription. by allocObjectId() method.  Once
    If the subscription or refresh fails, the subscription_handle
        this call isshould complete,be theset agentto willNone rejectand allerror further
may be set to an application-specific QmfData instance that describes the error. requests fromShould
 consoles referencing this ObjectId.
      .queryResponse( handle=<handle from WorkItem>,
         a refresh request fail, the console_handle may be set to None if unknown.

      .subscription_indicate(console_handle, [list of subscribed data]): Send a classlist QmfAgentObject):of sendupdated asubscribed manageddata objectto inthe Console.

      .subscription_cancel(handle=<handle from WorkItem>, console_handle): Acknowledge a replySubscription to a received query. Note that ownership of the
            object instance is returned to the caller on return from
            this call. 
      .queryComplete( handle=<handle from WorkItem>, 
                      result=<status code> ):  Indicate to the agentCancel WorkItem.

Asychronous Event Model.

The Agent uses the same notification driven work-queue model as the Console. In the Agent case, the following set of WorkItem types are supported:

  • METHOD_CALL
  • QUERY
  • SUBSCRIBE_REQUEST
  • RESUBSCRIBE_REQUEST
  • UNSUBSCRIBE_REQUEST

Note Well: In the case of an internal store agent implementation, only the METHOD_CALL work item is generated. An external store agent must support all work item types.

METHOD_CALL

The METHOD_CALL WorkItem describes a method call that must be serviced by the application on behalf of this agent.

The get_params() method of a METHOD_CALL WorkItem will return an instance of the following object:

No Format

class MethodCallParams:
      .get_name(): returns a string containing  that the applicationname has completed processing a query request.
            Zero or more calls to the queryResponse() method should beof the method call.
            invoked before calling queryComplete().  If the query should
     .get_object_id(): returns the identifier for the object on which this
       fail - for example,method dueneeds to authenticationbe errorinvoked. - theReturns result
None iff           should be set to a non-zero error code ?TBD?.
there is no associated
          object .subscriptionResponse(a handle=<handlemethod fromcall WorkItem>,
against the agent itself).
      .get_args(): returns a map of input arguments for the method. Arguments
          result=<status code>,
          are in "name"=<value> pairs.  Returns None if no arguments are supplied.
      .get_user_id(): returns authenticated user id of caller if present,     subscription_handle=<application context>):
            Indicate the status of a subscription request.  If result
            is zero, the subscription is accepted by the applicationelse None.

On completion of the method call, the application must provide the result of the call to the Agent. This is done by invoking the Agent's method_response() method. The method_response() method must be passed the handle from the METHOD_CALL WorkItem.

On successful completion of a method call, any output arguments from the method call must be passed in the out_args map parameter, in name=<value> pairs. The error parameter must be set to None.

If the method call fails the application must indicate the failure by passing a QmfData instance via the error parameter. The structure of this QmfData is application-specific, and meant to provide a description of the failure to the console.

QUERY

No Format

  QUERY parameters: ( class Query,
            and an subscription handle is provided.  This handle must
 user_id=<authenticated id of the        be passed to the application when the agent unsubscribes.

Asychronous event model.

The Agent uses the same notification driven work queue model as the
Console. In the Agent case, the WorkItem supports the following set
of work types:

  • METHOD_CALL
  • QUERY
  • SUBSCRIBE
  • UNSUBSCRIBE

In the case of an internal store agent implementation, only the
METHOD_CALL work item is generated. An external store agent must support
all work item types.

user> )

The QUERY WorkItem describes a query that the application must service. The application should call the query_response() method for each object that satisfies the query. When complete, the application must call the query_complete() method. If a failure occurs, the application should indicate the error to the agent by calling the query_complete() method with a description of the error.

SUBSCRIBE_REQUEST

The SUBSCRIBE_REQUEST WorkItem provides a query that the agent application must periodically publish until the subscription is cancelled or expires. On receipt of this WorkItem, the application should call the Agent::subscription_response() method to acknowledge the request. On each publish interval, the application should call Agent::subscription_indicate(), passing a list of the objects that satisfy the query. The subscription remains in effect until an UNSUBSCRIBE_REQUEST WorkItem for the subscription is received, or the subscription expires.

The get_params() method call of the SUBSCRIBE_REQUEST WorkItem returns an instance of the following object:

No Format

class SubscriptionParams:
      .get_console_handle(): returns the handle that the console uses to identify this subscription.
No Format

  METHOD_CALL parameters: ( name=<method name>, 
                  This handle must be passed along with every published update from [argument list],the Agent.
      .get_query(): returns the QmfQuery object associated with the subscription.
      .get_publish_interval(): returns the requested time interval in seconds for updates. class ObjectId,Returns
          zero if the Agent's default interval should be used.
      .get_lifetime(): returns the requested lifetime for the subscription.  user_id=<authenticated id of the user> )

The METHOD_CALL WorkItem describes a method call that must be serviced by the
application on behalf of this agent. On completion of the
method call, the application must invoke the agent's
methodResponse() method.

No Format

  QUERY parameters: ( class Query, 
        Zero if the Agent's
          default subscription lifetime should be used.
      .get_user_id(): returns     authenticated  user_id=<authenticated id of Console theif user> )

The QUERY WorkItem describes a query that the application must
service. The application should call the queryResponse() method for
each object that satisfies the query. When complete, the application
must call the queryComplete() method. If a failure occurs, the
application should indicate the error to the agent by calling the
queryComplete() method with a description of the error.

No Format

  SUBSCRIBE parameters: ( class Query, 
                          user_id=<authenticated id of the user> )

The SUBSCRIBE WorkItem provides a query that the application should
monitor until the subscription is cancelled. On receipt of this
WorkItem, the application should call the subscriptionResponse() agent
method to acknowledge the response. Whenever the matching objects are
updated, the application should call queryResponse() for each updated
object, followed by a call to queryComplete() when done. The
subscription remains in effect until an UNSUBSCRIBE WorkItem for the
subscription is received.

No Format

  UNSUBSCRIBE parameters: ( <handle associated with subscription> )

Alerts the application that the corresponding subscription has been
cancelled. The application should no longer supply query updates
against the subscribed query.

Revision History

11/20/2009 - First Revision
11/24/2009 - Added agent classes
12/01/2009 - Cleaned up Schema api and added map definitions.
12/04/2009 - Removed distinction between properties and statistics.
Object identification now based on Primary Key List.
Added more map definitions.
12/11/2009 - Formally define query implementation.

Todo List

...

present, else None.

The Agent application must call the AgentExternal::subscription_response() method in response to this WorkItem.

The get_handle() WorkItem method returns the reply handle which should be passed to the Agent's subscription_response() method.

RESUBSCRIBE_REQUEST

The RESUBSCRIBE_REQUEST is sent by a Console to renew an existing subscription.  The Console may request a new duration for the subscription, otherwise the previous lifetime interval is repeated.

The get_params() method call of the RESUBSCRIBE_REQUEST WorkItem returns an instance of the following object:

No Format

class ResubscribeParams:
    .get_subscription_id(): returns the subscription identifier provided by the Agent.
    .get_lifetime(): returns the requested lifetime for the subscription.  Zero if the previous
        interval should be used.
    .get_user_id(): returns the authenticated user id of the Console if present, else None.

The Agent application must call the AgentExternal:subscription_reponse method in response to this WorkItem.

The get_handle() WorkItem method returns the reply handle which should be passed to the Agent's subscription_reponse() method

UNSUBSCRIBE_REQUEST

The UNSUBSCRIBE_REQUEST is sent by a Console to terminate an existing subscription.

The get_params() method call returns the subscription identifier assigned by the Agent when the subscription is created.

The Agent application should terminate the given subscription if it exists, and cancel sending any further updates against it.

...