Classification endpoints
The classification
endpoints accepts a node name
and a set of facts, and then return information about how the specified node is
classified. The output can help you test your node group classification
rules.
POST /v1/classified/nodes/<name>
Retrieve a specific node's classification information based on facts supplied in the body of your request.
Request format
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. |
/v1/classified/nodes/<name>
endpoint:type_header='Content-Type: application/json'
auth_header="X-Authentication: $(puppet-access show)"
uri="https://$(puppet config print server):4433/classifier-api/v1/classified/nodes/<NAME>"
data='{"fact" : { "<FACT_NAME>" : "<FACT_VALUE>" }}'
curl --insecure --header "$type_header" --header "$auth_header" --request POST "$uri" --data "$data"
Response format
Key | Definition |
---|---|
name |
The node name, as a string. |
groups |
An array of group IDs for the groups that the node was classified into. |
environment |
The name of the environment that the node uses, which is taken from the node groups the node was classified into. |
classes |
An object containing key/value pairs describing the classes
that this node received from the groups it was classified into. Each key/value pair consists of a class name, as a string, and a subsequent object containing the names and values of parameters within the named class. |
parameters |
An object containing key/value pairs of top-level variables and their assigned values. |
{
"name": "foo.example.com",
"groups": ["9c0c7d07-a199-48b7-9999-3cdf7654e0bf", "96d1a058-225d-48e2-a1a8-80819d31751d"],
"environment": "staging",
"parameters": {},
"classes": {
"apache": {
"keepalive_timeout": 30,
"log_level": "notice"
}
}
}
Error responses
If there is an error, Node classifier API errors provide error information
in the kind
key.
If the node is classified into multiple node groups that supply conflicting classifications to the node, the server returns a 500 Server error response.
classification-conflict
errors, the
msg
describes generally why the conflict happened, and the
details
contains an object that uses the environment
,
variables
, or classes
key to indicate the type of
conflict (whether it was in setting the environment, setting variables, or setting class
parameters). Each key contains value-detail objects describing the specific conflicts:Value-detail object key | Definition |
---|---|
value |
The specific value having a conflict. For environment and classes ,
these are strings. For variables , these can be any
JSON value type. |
from |
The node group that the node was classified into that caused
the conflicting value to be added to the node's classification. Refer to defined_by for further details. |
defined_by |
The node group that actually defined the conflicting value.
This is often the from group, but could be an ancestor of that
group, due to How node group inheritance works. |
Blue Suede Shoes
was included in the
classification because the node matched the Elvis Presley
group (as indicated by from
). However, the conflicting value
was actually defined by the Carl Perkins
group, which is an
ancestor of the Elvis Presley
group. This caused the child
group to inherit the value from the ancestor group. The Since You've
Been Gone
conflicting value is defined by the same group that the node was
assigned to.{
"kind": "classification-conflict",
"msg": "The node was classified into multiple unrelated groups that defined conflicting class parameters or top-level variables. See `details` for a list of the specific conflicts.",
"details": {
"classes": {
"songColors": {
"blue": [
{
"value": "Blue Suede Shoes",
"from": {
"name": "Elvis Presley",
"classes": {},
"rule": ["=", "nodename", "the-node"],
...
},
"defined_by": {
"name": "Carl Perkins",
"classes": {"songColors": {"blue": "Blue Suede Shoes"}},
"rule": ["not", ["=", "nodename", "the-node"]],
...
}
},
{
"value": "Since You've Been Gone",
"from": {
"name": "Aretha Franklin",
"classes": {"songColors": {"blue": "Since You've Been Gone"}},
...
},
"defined_by": {
"name": "Aretha Franklin",
"classes": {"songColors": {"blue": "Since You've Been Gone"}},
...
}
}
]
}
}
}
}
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
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. |
{
"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
- 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.
- 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.
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. |
{
"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"]
}
}
}
}
}
}
{
"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.