Precedence and conflicts¶
Precedence decides which layer wins when two of them set the same field. It is an
integer on each Layer, compared numerically, with higher values applied later and
therefore winning.
An integer is used so that two layers can be compared directly. Ranking by matcher specificity, by directory depth or by discovery order produces an ordering that cannot be determined from the two layers alone.
Ordering is total and deterministic¶
Matching layers are sorted by precedence, and layers with equal precedence are
sorted by the path of their Layer document relative to the fleet root.
base/layer.yaml 0
environments/production/layer.yaml 10
sites/london/layer.yaml 20
roles/web/layer.yaml 30
hosts/web-001/layer.yaml 100
The path tie-break gives the fold a defined order in every case. It does not resolve disagreements, and two layers of equal precedence setting the same field to different values are a conflict.
Resolution never depends on filesystem enumeration order, on the machine running the resolver, or on which host is being resolved beyond the matchers that selected it. The same repository at the same revision produces the same manifest for the same host every time.
Conflicts are errors¶
When two layers of equal precedence set the same field of the same resource to different values, resolution fails and no manifest is produced.
error: conflicting values for File[nginx-config].mode
0640 roles/web precedence 30
0600 roles/web-tls precedence 30
both layers match host web-001 at equal precedence
Selecting a winner would make the result depend on something not visible in the repository, applied as root on every host both layers match. Refusing to resolve reports the ambiguity when it is introduced.
Two layers setting the same field to the same value are not in conflict. The requirement is an unambiguous outcome, and several layers may mention a field.
Resolving a conflict means changing precedence so one layer is clearly the authority, or narrowing a matcher so the layers no longer overlap.
Host overrides¶
A single host is overridden by a layer with a high precedence and a matcher matching that host.
datum: v1alpha1
type: Layer
name: host-web-001
precedence: 100
match:
labels:
datum/host: web-001
A host override is an ordinary layer, with no separate mechanism, per-host section or special syntax. Its contributions are recorded with provenance and it can conflict with another layer at the same precedence.
The conventional precedence of 100 sits well above the others, so a host override normally wins. A fleet-wide setting that has to take priority is given a higher number.
Traceability¶
Provenance is recorded per field as well as per resource, since a question is usually about one value.
Proposed command
datum explain is a proposed command and does not exist. The output below
shows what the design has to be able to produce, which is the part being
committed to.
$ datum explain File[nginx-config] --host web-001
File[nginx-config] /etc/nginx/nginx.conf
contributed by
roles/web precedence 30 matched role=web
hosts/web-001 precedence 100 matched datum/host=web-001
fields
path /etc/nginx/nginx.conf roles/web
owner root roles/web
group root roles/web
mode 0600 hosts/web-001 overrides 0640 from roles/web
source files/nginx.conf roles/web
requires
Package[nginx] roles/web
Two things have to survive resolution. Every field retains the layer that set its final value and the values it displaced, and every layer retains the labels that caused it to match. The resolver does not discard either after merging.
Ordering by specificity¶
Ranking layers by matcher specificity was rejected.
A matcher matching three labels is not reliably more authoritative than one
matching two. role: web with site: london and architecture: amd64 is more
specific than datum/host: web-001 by any counting rule while selecting a
broader set of hosts. Making specificity work requires weighting label keys
against each other, which puts a ranking of label keys in the repository.