POST /v1/classified/nodes/<name>/explanation
Retrieve a detailed explanation about how a node is classified based on facts supplied in the body of your request.
Request format
When Forming node classifier API requests to this endpoint, the URI path must contain the name of a specific node, and the body can contain a JSON object using these keys:
Key | Definition |
---|---|
fact
|
A JSON object containing regular, non-trusted facts associated with the node. The object contains key/value pairs of fact names and fact values. Fact values can be strings, integers, Booleans, arrays, or objects. |
trusted
|
A JSON object containing trusted facts associated with the node. The object contains key/value pairs of fact names and fact values. Fact values can be strings, integers, Booleans, arrays, or objects. |
For example:
{ "fact": { "ear-tips": "pointed", "eyebrow pitch": "40", "hair": "dark", "resting bpm": "120", "blood oxygen transporter": "hemocyanin", "anterior tricuspids": "2", "appendices": "1", "spunk": "10" } }
Response format
The response is a JSON object describing how the node would be classified based on the submitted facts.
- If the node would be successfully classified, the response object contains the successful classification outcome.
- If the classification would fail due to conflicts, the response object describes the conflicts.
The response is intended to provide insight into the classification process, so that, if a node isn't classified as expected, you can trace the classification sequence to the source of the deviation.
Classification proceeds in this order:
- All node group rules are tested on the node's facts and name. Groups that don't match
the node are culled, leaving only the matching groups. This step contributes to the
match_explanations
key in the response body. - Inheritance relations are used to further cull the matching groups, by removing any
matching node group that has a descendant that is also a matching node group. The
remaining node groups are referred to as leaf groups. This step contributes
to the
leaf_groups
key in the response body. - Each leaf group is transformed into its inherited classification by adding all the
inherited class and class parameter values from their ancestors. This step contributes
to the
inherited_classifications
key in the response body. - All inherited classifications and individual node classifications are inspected for
conflicts. A conflict occurs whenever two inherited classifications define different
values for the same environment, class parameter, or top-level variable. This step
contributes to the
conflicts
key in the response body. - Any individual node classifications (including classes, class parameters,
configuration data, and variables) are added. This step contributes to the
individual_classification
key in the response body. - Individual node classifications are applied to the group classification, which forms
the final classification. This step contributes to the
final_classification
key in the response body.
The response's JSON object uses these keys to describe the classification:
Key | Definition |
---|---|
match_explanations
|
An object containing group ID's the node matched to. For each group ID, there is an object explaining why the node matched that particular group's rules. |
leaf_groups
|
This key's value is an array of the leaf groups. This represent a condensed list of matching groups after filtering out any matching node group that had a descendant that was also a matching node group. |
inherited_classifications
|
This key's value is an object mapping a leaf group's ID to the classification values provided by that group (including inheritance from ancestors). |
conflicts
|
This key is present only if there are conflicts in the
inherited classifications. For each conflict there is an array of conflict
details. Each of these details is an object with three keys:
value , from , and defined_by .
The value key is a conflicting value, the from
key is the group whose classification provided the conflicting value, and the
defined_by key is the group that actually defined the value
(which can be an ancestor of the from group). |
individual_classification
|
This key's value includes classes, class parameters, configuration data, and variables applied directly to the node. |
final_classification
|
This key is present only if there are no conflicts between the inherited classifications. Its value is the result of merging all individual node classifications and group classifications. |
node_as_received
|
Represents the node object as defined in the request, including the name and facts (if supplied). |
classification_source
|
An annotated version of the node's classification where the environment, each class parameter, and each variable are replaced with an annotated value object. |
This example shows a successful (non-conflicting) classification response:
{ "node_as_received": { "name": "Tuvok", "trusted": {}, "fact": { "ear-tips": "pointed", "eyebrow pitch": "30", "blood oxygen transporter": "hemocyanin", "anterior tricuspids": "2", "hair": "dark", "resting bpm": "200", "appendices": "0", "spunk": "0" } }, "match_explanations": { "00000000-0000-4000-8000-000000000000": { "value": true, "form": ["~", {"path": "name", "value": "Tuvok"}, ".*"] }, "8aeeb640-8dca-4b99-9c40-3b75de6579c2": { "value": true, "form": ["and", { "value": true, "form": [">=", {"path": ["fact", "eyebrow pitch"], "value": "30"}, "25"] }, { "value": true, "form": ["=", {"path": ["fact", "ear-tips"], "value": "pointed"}, "pointed"] }, { "value": true, "form": ["=", {"path": ["fact", "hair"], "value": "dark"}, "dark"] }, { "value": true, "form": [">=", {"path": ["fact", "resting bpm"], "value": "200"}, "100"] }, { "value": true, "form": ["=", { "path": ["fact", "blood oxygen transporter"], "value": "hemocyanin" }, "hemocyanin" ] } ] } }, "leaf_groups": { "8aeeb640-8dca-4b99-9c40-3b75de6579c2": { "name": "Vulcans", "id": "8aeeb640-8dca-4b99-9c40-3b75de6579c2", "parent": "00000000-0000-4000-8000-000000000000", "rule": ["and", [">=", ["fact", "eyebrow pitch"], "25"], ["=", ["fact", "ear-tips"], "pointed"], ["=", ["fact", "hair"], "dark"], [">=", ["fact", "resting bpm"], "100"], ["=", ["fact", "blood oxygen transporter"], "hemocyanin"] ], "environment": "alpha-quadrant", "variables": {}, "classes": { "emotion": {"importance": "ignored"}, "logic": {"importance": "primary"} }, "config_data": { "USS::Voyager": {"designation": "subsequent"} } } }, "inherited_classifications": { "8aeeb640-8dca-4b99-9c40-3b75de6579c2": { "environment": "alpha-quadrant", "variables": {}, "classes": { "logic": {"importance": "primary"}, "emotion": {"importance": "ignored"} }, "config_data": { "USS::Enterprise": {"designation": "original"}, "USS::Voyager": {"designation": "subsequent"} } } }, "individual_classification": { "classes": { "emotion": { "importance": "secondary" } }, "variables": { "full_name": "S'chn T'gai Spock" } }, "final_classification": { "environment": "alpha-quadrant", "variables": { "full_name": "S'chn T'gai Spock" }, "classes": { "logic": {"importance": "primary"}, "emotion": {"importance": "secondary"} }, "config_data": { "USS::Enterprise": {"designation": "original"}, "USS::Voyager": {"designation": "subsequent"} } }, "classification_sources": { "environment": { "value": "alpha-quadrant", "sources": ["8aeeb640-8dca-4b99-9c40-3b75de6579c2"] }, "variables": {}, "classes": { "emotion": { "puppetlabs.classifier/sources": ["8aeeb640-8dca-4b99-9c40-3b75de6579c2"], "importance": { "value": "secondary", "sources": ["node"] } }, "logic": { "puppetlabs.classifier/sources": ["8aeeb640-8dca-4b99-9c40-3b75de6579c2"], "importance": { "value": "primary", "sources": ["8aeeb640-8dca-4b99-9c40-3b75de6579c2"] } }, "config_data": { "USS::Enterprise": { "designation": { "value": "original", "sources": ["00000000-0000-4000-8000-000000000000"] } }, "USS::Voyager": { "designation": { "value": "subsequent", "sources": ["8aeeb640-8dca-4b99-9c40-3b75de6579c2"] } } } } } }
This example shows a conflicting classification response:
{ "node_as_received": { "name": "Spock", "trusted": {}, "fact": { "ear-tips": "pointed", "eyebrow pitch": "40", "blood oxygen transporter": "hemocyanin", "anterior tricuspids": "2", "hair": "dark", "resting bpm": "120", "appendices": "1", "spunk": "10" } }, "match_explanations": { "00000000-0000-4000-8000-000000000000": { "value": true, "form": ["~", {"path": "name", "value": "Spock"}, ".*"] }, "a130f715-c929-448b-82cd-fe21d3f83b58": { "value": true, "form": [">=", {"path": ["fact", "spunk"], "value": "10"}, "5"] }, "8aeeb640-8dca-4b99-9c40-3b75de6579c2": { "value": true, "form": ["and", { "value": true, "form": [">=", {"path": ["fact", "eyebrow pitch"], "value": "30"}, "25"] }, { "value": true, "form": ["=", {"path": ["fact", "ear-tips"], "value": "pointed"}, "pointed"] }, { "value": true, "form": ["=", {"path": ["fact", "hair"], "value": "dark"}, "dark"] }, { "value": true, "form": [">=", {"path": ["fact", "resting bpm"], "value": "200"}, "100"] }, { "value": true, "form": ["=", { "path": ["fact", "blood oxygen transporter"], "value": "hemocyanin" }, "hemocyanin" ] } ] } }, "leaf_groups": { "a130f715-c929-448b-82cd-fe21d3f83b58": { "name": "Humans", "id": "a130f715-c929-448b-82cd-fe21d3f83b58", "parent": "00000000-0000-4000-8000-000000000000", "rule": [">=", ["fact", "spunk"], "5"], "environment": "alpha-quadrant", "variables": {}, "classes": { "emotion": {"importance": "primary"}, "logic": {"importance": "secondary"} } }, "8aeeb640-8dca-4b99-9c40-3b75de6579c2": { "name": "Vulcans", "id": "8aeeb640-8dca-4b99-9c40-3b75de6579c2", "parent": "00000000-0000-4000-8000-000000000000", "rule": ["and", [">=", ["fact", "eyebrow pitch"], "25"], ["=", ["fact", "ear-tips"], "pointed"], ["=", ["fact", "hair"], "dark"], [">=", ["fact", "resting bpm"], "100"], ["=", ["fact", "blood oxygen transporter"], "hemocyanin"] ], "environment": "alpha-quadrant", "variables": {}, "classes": { "emotion": {"importance": "ignored"}, "logic": {"importance": "primary"} } } }, "inherited_classifications": { "a130f715-c929-448b-82cd-fe21d3f83b58": { "environment": "alpha-quadrant", "variables": {}, "classes": { "logic": {"importance": "secondary"}, "emotion": {"importance": "primary"} } }, "8aeeb640-8dca-4b99-9c40-3b75de6579c2": { "environment": "alpha-quadrant", "variables": {}, "classes": { "logic": {"importance": "primary"}, "emotion": {"importance": "ignored"} } } }, "conflicts": { "classes": { "logic": { "importance": [ { "value": "secondary", "from": { "name": "Humans", "id": "a130f715-c929-448b-82cd-fe21d3f83b58", ... }, "defined_by": { "name": "Humans", "id": "a130f715-c929-448b-82cd-fe21d3f83b58", ... } }, { "value": "primary", "from": { "name": "Vulcans", "id": "8aeeb640-8dca-4b99-9c40-3b75de6579c2", ... }, "defined_by": { "name": "Vulcans", "id": "8aeeb640-8dca-4b99-9c40-3b75de6579c2", ... } } ] }, "emotion": { "importance": [ { "value": "ignored", "from": { "name": "Vulcans", "id": "8aeeb640-8dca-4b99-9c40-3b75de6579c2", ... }, "defined_by": { "name": "Vulcans", "id": "8aeeb640-8dca-4b99-9c40-3b75de6579c2", ... } }, { "value": "primary", "from": { "name": "Humans", "id": "a130f715-c929-448b-82cd-fe21d3f83b58", ... }, "defined_by": { "name": "Humans", "id": "a130f715-c929-448b-82cd-fe21d3f83b58", ... } } ] } } }, "individual_classification": { "classes": { "emotion": { "importance": "secondary" } }, "variables": { "full_name": "S'chn T'gai Spock" } } }
Error responses
If there is an error, Node classifier API errors provide error information
in the kind
key.