Constraints
Note
This document explains how constraints work and what they are for.
Constraints are declarative logic carriers. They provide clear rules what to consume within a specific claim.
Important
The following rules are applied to a constraint:
It provides declarative logic for modules those are consuming a specific claim
It operates on actions, using entities’s data
Synopsis
Constraints has the following syntax:
constraints:
<action id>:
descr: description
entities:
- [$]
- [entity id]
<condition> (all|any|none):
<state> (label|$):
- fact: <value>
- <expr> (equals, less, more, matches (regex), contains, starts, ends): <value|claim()>
Collection of constraints is under constraints section. Constraint is always attahed to an action
by the same Id. Same as an action, it is binding to a list of entities. For example, an action can
bind to many entities, but its constraint can be limited to only few, etc. Each constraint has its own
set of expressions.
Entity Binding
Entities are bound by the section entities. The following rules apply:
A list of entities (at least one) means that the constraint will work _only_ on these entities.
If a list has only one element and it is
$(all), then the constraint will catch all entities.If a list contains some entity Ids as well as
$(all), then the constraint will catch all entitles, except those that are listed in theentitiessection.
Expressions
Expressions are defined in the <state> block. Either it is $ (any) or a specific state.
Conditions
A condition has the following syntax:
<condition>:
<state>:
- fact: <value>
- <operator>: <value> | claim()
These are currently supported conditions:
any
This expression is a logical
OR. It means that at least one of the items must betrue.
all
This expression is a logical
AND. It means that all of the items must betrue.
none
Essentially, this is an inversion to
all.
The following operators are supported:
equals— compare fact and the value on all types for their equality.less— compare fact and the value of int/float types if the fact is less then the value.more— compare fact and the value of int/float types if the fact is more then the value.matches(regex) — match a string value with the regular expression.contains— check if a value contains the defined part of a string.starts— check if a value starts with the defined part of a string.ends— check if a value ends with the defined part of a string.
Each operator can contain a static value or a dynamically call a current claim via claim() function.
Example
actions:
# NOTE: Same id as in constraints
net-addr-verification:
descr: Check addresses
module: sys.net
bind:
- addresses
args:
- iface: "claim(if)"
- inet: "claim(inet)"
entities:
# NOTE: An id of an entity, referred by a constraint below
addresses:
claims:
$:
- wifi:
if: wlp0s20f3
inet: 192.168.2.151/24
- virtual-main:
if: virbr0
inet: 192.168.122.1/24
- virtual-secondary:
if: virbr1
inet: 192.168.100.1/24
constraints:
# Corresponds to the same action Id
net-addr-verification:
descr: Interfaces have assigned addresses
all:
wifi:
- fact: if-up.wlp0s20f3.IPv4
- equals: claim(wifi.inet)
any:
$:
- fact: if-up.virbr0.IPv4
equals: claim(virtual-main.inet)
- fact: if-up.virbr1.IPv4
equals: claim(virtual-main.inet)
Origin of “fact”
One might ask where is the fact value comes from and what is this namespace
in the example above, like if-up.virbr0.IPv4?
This is the arbitrary data in the plugin output. Since a plugin can return literally
anything possible, the navigation over the structure is entirely on user. The
namespace is basically keys of nested maps. So the if-up.virbr0.IPv4 would correspond
to this JSON data structure:
{
"if-up": {
"virbr0": {
"IPv4": "192.168.0.2",
}
},
}
However, sometimes structure can have a bit different result (i.e. each final key/value is an element in the array):
{
"if-up": {
"virbr0": [
{"IPv4": "192.168.0.2",},
]
},
}
If the same key/value happens twice or more, first in the line wins.
Note
The data navigation is still under development and is subject to change.