Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: update: rework query model, add detail to method call handling

...

Arbitrarily structured data is the simplest 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.

...

No Format
class QmfData:
      <constructor>( _values=map of "name"=<AMQP Type> pairs, 
                     _subtypes=optional map of "name"=<AMQP String> pairs for
                           subtype information,
                     _desctag=optional AMQP string containing a human-readable
                           description for this data object., application-specific tag applied to this QmfData instance
                     _object_id=optional AMQP string that uniquely identifies
                           this QmfData instance.
                     _schema=optional <class SchemaClass> reference
                     _const=False )
      <constructor>( _map=map representation of QmfData, as generated by
                           mapEncode() method, 
                     _schema=optional <class SchemaClass> reference
                     _const=False)
      .isManaged(): returns True if object identifier string assigned, else False.
      .isDescribed(): returns True if schema is associated with this instance
      .getDescgetTag(): return thethis description of this objectobject's tag if present, else None
      .getValue(name): return the value of the named data item, returns None if
                       named property is not present.
      .hasValue(name): returns True if the named data item is present in the map,
                       else False.
      .setValue(name, value, subType=None): set the value of the named data item.
                       Creates a new item if the named data does not exist. Raises
                       an exception if _const is True. 
      .getSubType(name): returns the sub type description string, else None if not
                       present. 
      .setSubType(name, subType): set or modify the subtype associated with name.
      .get_object_id(): returns the object id string associated with the object
 instance, or None if no id assigned.
                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.
      .mapEncode(): returns a map representation of the QmfData instance, suitable
                       for use by the constructor.

...

Index

Optional

Type

Description

"_values"

N

map

Map containing all the "name"=<AMQP Type> pairs for this object.

"_subtype"

Y

map

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

"_desctag"

Y

string

Any AMQP-supported type

Application-specific tag for this Description of this data object.

"_object_id"

Y

string

Unique identifier for this data object.

"_schema_id"

Y

map

Map containing the SchemaClassId for this object.

...

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".

No Format

class QmfEvent(QmfData):
      <constructor>( 
No Format

class QmfEvent(QmfData):
      <constructor>( timestamp, 
                     _values=map of "name"=<AMQP Type> pairsseverity=<string>,
                     _subtypesvalues=optional map of "name"=<AMQP String>Type> pairs,
                     _subtypes=optional map of "name"=<AMQP String> pairs for subtype information,
                     _desctag=optional AMQP string containing a human-readable
                           description for this data object., application-specific tag applied to this QmfEvent instance
                     _schema=optional <class SchemaEventClass> )
       <constructor>( _map= map encoding of a QmfEvent instance, 
                     _schema=optional <class SchemaEventClass> )
      .getTimestampget_timestamp(): return a timestamp indicating when the Event occurred.
      .get_severity(): return the severity associated with the Event.
      .map_encode(): return a map encoding of the Event.

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

Index

Optional

Type

Description

"_timestamp"

N

AMQP Timestamp

Time the event occurred.

"_severity"

Y

string

Event severity

Schema

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

...

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 optional)
                 (required for method arguments, otherwise
                       optional)
      .getSubtype(.getSubtype(): string indicating the formal application type 
                     for the data, example: "URL", "Telephone number",
                     etc.
      .isPolled(): True if changes to the data cannot be practically 
                   monitored by an Agent.  Such a data item can only
                   be queried or polled - not published on change.
      .getReference(): if type==objId, name (str) of referenced class
 (optional) 
                     (optional) 
      .isParentRef().isParentRef(): True if this property references an object in
                       which this object is in a child-parent
                       relationship.
      .getAttribute("name"): get the value of the attribute named
          "name". This method can be used to retrieve
          application-specific attributes.  "name" should start with
          the prefix "x-"
      .mapEncode(): returns a map encoding of the instance.

...

The SchemaMethod class describes a method call its '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")
      .getDesc(): return human-readable description of the method.
      .getArgumentCount(): return the number of arguments
      .getArguments(): returns a copy of the map of "name":<SchemaProperty>
      .getArgument("name"): return the SchemaProperty for the parameter "name"

      .addArgument("name", SchemaProperty): adds an additional argument to
                  the parameter list.
      .mapEncodemap_encode(): returns a map encoding of the SchemaMethod instance

...

Index

Optional

Type

Description

"_namedesc"

NY

string

The name Description of the method.

"_arguments"

Y

map

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

...

No Format
class SchemaClass(QmfData):
      <constructor>( classId=<class SchemaClassId>, 
                     _desc=optional AMQP string containing a human-readable
 description for this schema)
      .getClassId():                 description for this schema)
      .getClassId(): return return the SchemaClassId that identifies this Schema instance.
      .generateHash(): generate a hash over the body of the schema, and return a
                       string representation of the hash in 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.

...

No Format
class SchemaObjectClass(SchemaClass):
      <constructor>( classId=<class SchemaClassId>, 
                     _desc=optional AMQP string containing a human-readable description for this schema,
                     _props=map of "name"=<SchemaProperty> instances,
                     _meths=map of "name"=<SchemaMethod> instances,
                     _id_names=(optional) ordered list of "name"s used to identify the properties whose
                                          values are used to construct the object identifier)

      .get_id_names(): return an ordered list of names of the values that are used to construct the key
                       for identifying unique instances of this class.  Returns None if no list defined.
      .getPropertyCount(): return the count of SchemaProperty's in this instance.
      .getProperties(): return a map of "name":<SchemaProperty> entries for each value in the object.
      .getProperty("name"): return the SchemaProperty associated with "name", else None if "name" value
 does not exist.

                         does not exist.

      .getMethodCount.getMethodCount(): return the count SchemaMethod's in this instance.
      .getMethods(): return a map of "name":<SchemaMethod> entries for each method associated with the
                     object.
      .getMethod("name"): return the SchemaMethod associated with the "name", else None if "name" does
                          not exist or is not a method.

      .addProperty("name", SchemaProperty): add a new property.
      .addMethod("name", SchemaMethod): add a new method.
      .set_id_names([name-list]): set the value of the order list of names 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.

...

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.

Queries are expressed using the following map object:

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 syntax:

No Format
No Format
{"query": {"what":<target>},
           {"where":<predicate>}
          ...future selectors....<selector_type>:<selector_params>}
}

Where:

The value of the "what" key indicates the set of desired objects to match against. The value of the "where" key is an optional predicate to use as the match criteria. If the "where" key is not present, then the query matches against all members of the target set. The agent processes a received query, and returns a 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.

...

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

<predicate> 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=["exists"]

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

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

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

  expression = compare_exp | logic_exp

In implementation, predicate expressions are expressed as nested maps. Each map
element is indexed by the operator keyword. The value of the element
is an n-entry ordered list of the operands to the operator. The
format of a single operator expression would be:

No Format

    {operator: [operand1, operand2, ...]}

Examples:

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

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

     would be expressed in a python map as:
  
         {"or": [{"eq": ["name", "tross"]},
                 {"and": [{"eq": ["name", "jross"]},
                          {"eq": ["address", "1313 Spudboy Lane"]},
                          {"eq": ["town", "Utopia"]}]
              ["eq" "address"  }["quote" "1313 Spudboy Lane"]]
              ["eq" ["quote" "Utopia"] "town"]
         }]
]

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"   the conditional:
["quote" "?ross"]]
         !(("name" matches regular expression "?ross") and ["and" ["exists" "age"]
           (("age" property is present) ["or" (["statusgt" is not "sleepy")))

     would be:

"age" 27] ["lt" "age" 12]]
        {"not": [{"and": [{"re_match": ["name", "?ross"]},
                          {"or": [{"exists": ["age"]},
                                  {"ne": ["status", "sleepy"]}]
                          }
                         ]
                }]
        }

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

]
]

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_infoTarget "schema_package" valid names

Description

"_package_name"

Evaluates to the schemaagent's package name string.

Target "schemaobject_id" and "schemaobject" valid names

Description

"_package_name"

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

"_class_name"

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

"_type"

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

"_hash_str"

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

"_schema_id"

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

"_object_id"

<property-name>

Name of a property defined by the schema. Evaluates to the identifying 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:

.

"_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

class QmfQuery:
      <constructor>(_target=<target map>,
                    _predicate=(optional)<predicate map>)
      .get_target(): return target map
      .get_predicate(): return predicate map
      .evaluate(QmfData): evaluate query against a QmfData instance.  Returns True if query
           "what":               matches the instance, else false.{"schema_id": None}
      .mapEncode(): returns a map encoding of the QmfQuery instance

The map encoding of a SchemaMethod:

Index

Optional

Type

Description

"what"

N

map

The target map.

"where"

Y

map

The predicate map.

Example Queries

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

 }
}

Query for the particular QmfData data object with the identifier "Agent007"For example, a query for all known schema identifiers:

No Format
    {"query": {"what": {"schema_idobject":None},
           "id": "Agent007"}
}

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"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": {"wherewhat": {"eq"schema":None},
           "id": [{"_package_name",: "myPackageMyPackage"]},
                "what  "_class_name": {"schema_id": None}
"MyClass",
                  "_type": "_data",
               }
   "_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"]]},
                                 {["eq": ["_class_name", ["quote" "someClass"]]}]}
              }
    }

Query all managed objects belonging to the "myPackage" package, of the
class "myClass", whose primary key 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"]
          "_class_name": "myClass"}},
               "where": {["re_match": ["_primary_key",_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": "someClass"}},
]
                          "where": {["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

    
{"query": {"what": {"object": { None},
           "where": ["and" ["eq" "_package_name": ["quote" "aPackage,]]
                           ["eq" ["quote"       "someClass"] "_class_name": "someClass"}},
]
                          "where": {["or": [{"not": [{"re_match": "state" ["statequote", "$Error"]]}]},
                                 {["ne": "owner" ["ownerquote", "Cartman"]}]
                           }]
                }    ]
          }
}

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:
      ?tbd?

Invoking Methods

A managed object's methods provide a mechanisms for a QMF allows a Console application to perform a "remote procedure call" against on the objectAgent. The procedure - or method actually - call executes on the Agent, and the . On completion a result is passed back to the Console on completion. 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, 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 a QmfData an error object in the MethodResult. This object is described as an "exception", and contains 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 an exception the QmfData error object 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> ) )
      .succeeded(): returns True if the method call executed without error.
      .getExceptionget_exception(): returns the QmfData exceptionerror dataobject if method fails., else None
      .getArgumentsget_arguments(): returns a map of "name"=<value> pairs
                       of all returned arguments.
      .getArgumentget_argument(<name>): returns value of argument named "name".

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.

 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. 
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 
        This method will              [2] = deletion timestamp, or zero if not deleted.
      .get_create_time(): returns the creation timestamp
      .get_update_time(): returns the update timestampbe called by the internal QMF management thread - it is illegal to invoke any QMF APIs from 
      .get_delete_time(): returns thewithin deletionthis timestamp,callback. or zeroThe ifpurpose notof yetthis deleted.
callback is to indicate that  .is_deleted(): True if deletion timestamp not zero.

the application should schedule itself
        to  .refresh([reply-handle | timeout]): request that the Agentprocess 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 updatean theasynchronous valueoperation, of this object's contentsif present.
      .invokeget_methodparams(name, inArgs{}, [[reply-handle] | [timeout]]): 
                          invoke the named method.

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:

...

): 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

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

Local representation of a remote Agent.

...

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.
      .isActive(): returns True if the agent is alive (heartbeats have not timed out)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.
      .invokedisable_method(name, inArgs{}, [[reply-handle] | [timeout]]events(): 
prevents reception of events from this agent.
      .destroy(): releases this Agent instance.  Once called, the console application should not reference invokethis the named method against the agentinstance again.
      ?tbd?

The Console Object.

...

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 blocking calls>,
                    agent_timeout=<default timeout for agent heartbeat>,
                    subscription_duration=<default lifetime of a subscription>)

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

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

      .removeConnection(conn): Remove the AMQP connection from the
          console.  Un-does the addConnection() 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.

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

      .findAgentfind_agent( name string, [timeout] ): Query for the presence of a specific
                string, [timeout] ): Query for the presence of a specific agent in the QMF domain. Returns a class Agent if the agent is
          class Agent if the agent is present.  If the agent is not already known to the console, this
 call will send 
            call will send a query for the agent and block (with default
                timeout override) waiting for a response.

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

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

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

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

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

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

      .getAgent( name string ): Return the class Agent for the named agent, if known. 

      .getPackages( [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.

      .getClasses( [class Agent] ):  Returns a list of SchemaClassIds
          for all available Schema.  If an optional Agent is provided,
          then the returned SchemaClassIds are limited to those
          Schema known to the given Agent.

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

      .getObjects( _SchemaClassId= | _package=, _class= |
                    _object_identifier=,
                   [timeout=],
                   [list-of-class-Agent] ): perform a blocking query
           for QmfConsoleObjects.  Returns a list (possibly empty) of matching
           objects. The selector for the query may be either:
           * class SchemaClassId - all objects whose schema match the
                    schema identified by _SchemaClassId parameter.
           * package/class name - all objects whose schema are
                    contained by the named package and class.
           * the object identified by _object_identifier
           This method will block until all known agents reply, or the
                    timeout expires. Once the timeout expires, all
          Once the timeout expires, all
           data retrieved to date is returned.  
           If a list of agents is supplied, then the query is sent to
                    only those agents.  


      .createSubscription( class Query [, duration=<secs> [, list of agents] ): creates a
            subscription using the given Query.  If a list of agents
            is provided, 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.
            The duration argument can be used to override the
            console's default subscription lifetime for this
            subscription.  Returns a class SubscriptionId.

      .refreshSubscription( SubscriptionId [, duration=<secs>] ):
      (re)activates a subscription.  Uses the console default duration
          unless the duration is explicitly specified.

      .cancelSubscription( SubscriptionId ): terminates the
 given     subscription. 

Example Console Application

...

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

...

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=655350)
      .get_name(): return the name string of the agent.
      .setConnection( QPID Connection ): connect the agent to the AMQP cloud.
      .registerObjectClass( 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 return the name string of the agent.
      .setConnection( QPID Connection ): connect the handleagent objectsto ofthe thatAMQP classcloud.
      .registerEventClassregisterObjectClass( class SchemaEventClassSchemaObjectClass ) : Register a
            schema for an eventobject class with the agent.  The agent must
            have a registered schema for an eventobject class before it can
            handle eventsobjects of that class.
      .raiseEventregisterEventClass( class QmfEventSchemaEventClass ) : CauseRegister thea
 agent to raise the
        schema for   givenan event.
 class with the agent.  .addObject(The class QmfAgentData ):agent must
            passeshave a registered referenceschema tofor an instance of a managed QMF object
            to the agent. The object's name must uniquely identify this
   event class before it can
         object among all objectshandle knownevents toof thisthat agentclass.
      .getWorkItemCount(raise_event( class QmfEvent ): ReturnsCause the countagent ofto pendingraise WorkItems thatthe
            cangiven be retrievedevent.
      .getNextWorkItem([timeout=0]): Obtains the next pending workaddObject( class QmfAgentData ):
            item,passes ora Nonereference ifto nonean available.instance 
of a managed QMF object
  .releaseWorkItem(wi): Releases a WorkItem instance obtained by
    to the agent. The object's name must uniquely getNextWorkItem(). Called when the application has finished
identify this
            object among all objects known processingto thethis WorkItemagent. 
      .methodResponsegetWorkItemCount(): handle=<handleReturns fromthe WorkItem>,
count of pending WorkItems that
            can be retrieved.
      [output argument list],
     .getNextWorkItem([timeout=0]): Obtains the next pending work
            item, or None if none  result=<status code>,available. 
      .releaseWorkItem(wi): Releases a WorkItem instance obtained by
           exception=<QmfData> getNextWorkItem():. IndicateCalled towhen the application agenthas finished
            thatprocessing the applicationWorkItem. 
  has completed processing a .method_response(name="method name",
                  request.    A resulthandle=<handle codefrom ofWorkItem>,
 zero indicates success.  If the
            result code is non-zero, exception may optionally be set to a
 out_args={output argument map}
               QmfData object that describes the failure.  On success, zero or
   error=<QmfData> ): Indicate to the agent
         more output arguments maythat bethe suppliedapplication ashas definedcompleted byprocessing thea method's
            schema. request. See the description of the 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):
      <constructor>(name=<name-string>,
                    domain=(optional) domain string for agent's AMQP address,
                    notifier= class Notifier,
                    heartbeat_interval=30,
                    max_msg_size=65535)
      .allocObjectId( name="object name"): indicate to QMF that the named
             object is available to be managed.  Once this method returns,
             the agent will service requests from consoles referencing this data.
      .freeObjectId( name="object name" ): indicate to QMF that the named
             object is no longer available to be managed.
      .queryResponse( handle=<handle from WorkItem>,
                      class QmfAgentObject): send a managed object in 
            reply 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 agent
            that the application has completed processing a query request.
            Zero or more calls to the queryResponse() method should be
            invoked before calling queryComplete().  If the query should
            fail - for example, due to authentication error - the result
            should be set to a non-zero error code ?TBD?.
      .subscriptionResponse( handle=<handle from WorkItem>,
                             result=<status code>,
                             subscription_handle=<application context>):
            Indicate the status of a subscription request.  If result
            is zero, the subscription is accepted by the application,
            and an subscription handle is provided.  This handle must
            be passed to the application when the agent unsubscribes.

...

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 WorkItem types are supported:

  • METHOD_CALL
  • QUERY
  • SUBSCRIBE
  • UNSUBSCRIBE

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
  METHOD_CALL parameters: ( name=<method name>, 
               class MethodCallParams:
      .get_name(): returns a string containing the name of the method call.
      .get_object_id(): returns the identifier for the object on which this 
          method needs to be invoked.  Returns None iff there is no associated 
          object (a method [argument list],
   call against the agent itself).
      .get_args(): returns a map of input arguments for the method. Arguments 
        object identifier,
 are in "name"=<value> pairs.  Returns None if no arguments are supplied.
      .get_user_id(): returns authenticated user id of caller if present,  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.

else 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, 
                      user_id=<authenticated id of the 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.

SUBSCRIBE

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.

UNSUBSCRIBE

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.
12/14/2009 - Update query implementation based on feedback.

Todo List

...