QMFv2 Map Message Protocol
Introduction
This document describes the design of a proposed protocol for QMF based on map-messages (offered by the new C++ and Python APIs as well as the existing JMS API).
If adopted, this new protocol will change the formats of the messages used by QMF components to communicate. It will also change some of the message exchange patterns. It will not significantly impact the console and agent APIs and is intended to operate with applications that use the current QMF APIs.
Some highlights of the new design:
- Current QMF message bodies are in packed binary formats. While quite efficient, this style of formatting makes it difficult to make changes to the format and content for new features. The proposed format is based on encoded maps (a.k.a. dictionaries, field-tables) which are very easily extended and require less context to be useful.
- QMF currently requires the message broker to participate in the QMF protocol. The proposed protocol removes this requirement and will run properly on any AMQP message broker.
- QMF Agents currently publish periodic updates of their managed content to a globally accessible topic. This has security implications with regard to access to data. This is also inflexible in that updates to all data are sent at the same intervals. The proposed protocol removes the global publishing of data and introduces a subscription-query whereby a console may request that an agent publish certain data at a certain interval to an indicated target. Such requests can be subject to access control and may be focused on only the data that is needed for a particular application.
- The proposed protocol allows for more general use of data. For example:
- Free-form data, that has no object-identifier nor schema, can be transferred. This is useful for complex queries (joins, reports, etc.).
- Methods can be invoked against an agent in the absence of a managed object.
QMF Protocol
Use of Message Headers
Standard Message Properties
Message Property |
Use |
---|---|
correlation-id |
Used in request/response/indication sets to correlate responses and indications to their request. |
reply-to |
Used in requests to indicate the address for the response. |
content-type |
'amqp/map' or 'amqp/list' |
user-id |
Supplied in a request if authentication/authorization at the agent is appropriate. |
app-id |
'qmf2' |
Custom Application Headers
Application Header Key |
Use |
---|---|
method |
'request', 'response', or 'indication'. This field describes the message's role in a particular message-exchange pattern. |
qmf.opcode |
QMF-specific operation code (see list below). The opcode defines what content, if any, is to be found in the message body. |
qmf.content |
If the opcode is a data indication, this field indicates what kind of data will be found in the message body. |
qmf.agent |
If this message is a data indication sent by an agent, this field contains the agent's name. |
QMF OpCodes
qmf.opcode field |
Message Body Data Type |
Description |
---|---|---|
_agent_locate_request |
QMF_QUERY_PREDICATE |
|
_agent_locate_response |
QMF_DATA |
|
_agent_heartbeat_indication |
QMF_DATA |
|
_query_request |
QMF_QUERY |
|
_query_response |
??? |
|
_subscribe_request |
QMF_SUBSCRIBE |
|
_subscribe_cancel_request |
VOID |
|
_subscribe_refresh_indication |
VOID |
|
_data_indication |
List of <qmf.content> |
|
h4 QMF Content Types
qmf.content field |
Data Type |
Description |
---|---|---|
_schema_package |
STRING |
Schema package name |
_schema_id |
SCHEMA_ID |
Schema class identifier |
_schema_class |
SCHEMA_CLASS |
Schema class definition |
_object_id |
OBJECT_ID |
Managed object identifier |
_data |
QMF_DATA |
Data, managed and/or described or free-form |
_event |
QMF_EVENT |
Event |
Operations
Agent Announce
Console Topic Agent | | | | | <---- Agent Indication ---- | | <------------------------ | | | | |
Agent Locate
Console Topic Agent | | | | ---- Agent Locate Indication -> | | | | --------------------------> | | | | | <-------------------------------------- Agent Indication ---- | | | | | | | | ---- Agent Locate Indication -------------------------------> | | | | | <-------------------------------------- Agent Indication ---- | | | |
Schema Query
Console Agent | | | ---- Schema Request ----------------> | | | | <------------- Schema Indication ---- | | <------------- Schema Indication ---- | | | | <---------------------- Response ---- | | |
Schema Announce
Console Topic Agent | | | | | <--- Schema Indication ---- | | <------------------------ | | | | |
Get Query
Console Agent | | | ---- Get Query Request -------------> | | | | <--------------- Data Indication ---- | | <--------------- Data Indication ---- | | <--------------- Data Indication ---- | | <--------------- Data Indication ---- | | <--------------- Data Indication ---- | | <---------- Last Data Indication ---- | | | | <------------------------ Result ---- | | |
Create Subscription Query
Console Target Agent | | | | ---- Create Subscription Request ---------------------> | | | | | | <----------- Data Indication ---- | | | <----------- Data Indication ---- | | | <----------- Data Indication ---- | | | <----------- Data Indication ---- | | | <----------- Data Indication ---- | | | | | <------------------------------------------ Result ---- | | | | | | <----------- Data Indication ---- | | | | | | <----------- Data Indication ---- | | | |
Cancel Subscription Query
Console Target Agent | | | | ---- Cancel Subscription Request ---------------------> | | | | | <------------------------------------------ Result ---- | | | | | | <----------- Data Indication ---- | | | <------ Last Data Indication ---- | | | |
Renew Subscription Query
Console Target Agent | | | | ---- Renew Subscription Request ----------------------> | | | | | <------------------------------------------ Result ---- | | | |
Invoke Method
Console Agent | | | ---- Method Request ----------------> | | | | <------------------------ Result ---- | | |
Raise Event
Console Topic Agent | | | | | <---------- Event Indication ---- | | <------------------ | | | | |
Map Body Formats
QMF Data Formats
qmfAgentLocate := {qmfQuery} qmfAgentIndicate := {qmfAgentInfo} qmfAgentInfo := agent_info: {name: (sstr), vendor: (sstr), product: (sstr), version: (sstr), -- optional platform: (sstr), -- optional arch: (sstr)} -- optional qmfQuery := query: {what: qmfQueryTarget, where: qmfQueryPredicate} -- optional qmfQueryTarget := {schema_package: (void)} || {schema_id: (void)} || {schema: (void)} || {agent: (void)} || {object_id: qmfClassSpecifier} || {object: qmfClassSpecifier} qmfClassSpecifier := {class_name: (sstr), package_name: (sstr), -- optional hash: (bin128)} -- optional qmfQueryPredicate := {qmfCompare} || {and: listOf(qmfQueryPredicate)} || {or: listOf(qmfQueryPredicate)} || {not: qmfQueryPredicate} qmfCompare := list(eq, (sstr), amqpValue) || list(ne, (sstr), amqpValue) || list(lt, (sstr), amqpValue) || list(gt, (sstr), amqpValue) || list(le, (sstr), amqpValue) || list(ge, (sstr), amqpValue) || list(exists, (sstr)) || list(is-type, (sstr), amqpTypeCode) || list(is-subtype, (sstr), (sstr)) || list(re-match, (sstr), (lstr)) qmfData := {values: mapOf(amqpValue), subtypes: mapOf(sstr) } -- optional, keys must be in values qmfDescribedData := {(qmfData), class_id: qmfClassId } qmfManagedData := {(qmfDescribedData), object_id: (lstr), create_time: (datetime), delete_time: (datetime), -- optional update_time: (datetime) } qmfClassId := {package: (sstr), name: (sstr), hash: (bin128) } qmfObjectClass := {(qmfData[qmfProperty|qmfMethod]), class_id: qmfClassId, desc: (lstr), superclass: qmfClassId } qmfProperty := {amqp_type: (amqpTypeCode), access_rule: (sstr), optional: (void), unit: (sstr), desc: (lstr), subtype: (sstr), discrete: (void), min: (amqp_type), max: (amqp_type), maxlen: (uint32) } qmfMethod := {desc: (lstr), arguments: mapOf(qmfArgument) } qmdArgument := {amqp_type: (uint8), unit: (sstr), desc: (lstr), subtype: (sstr), input: (void) output: (void)