Skip to content

ADR-0001: Use typed resources

Status

Accepted

Context

Desired state has to be expressed in some form, and three were available.

Scripts or command sequences are the easiest to write and the hardest to reason about. A script has no state to read before running and nothing to compare afterwards, so nothing built on top of it can report what differs or confirm that a change worked.

Freeform data applied through templates, where the repository holds arbitrary key and value structures rendered into configuration files, covers a lot of ground quickly. The problem is that the data has no meaning to the tool. Rendering port: 8080 into a template gives no way to ask whether the port is currently 8080 on the host, since nothing records that the value corresponds to observable state.

Typed resources, where each unit of configuration is an instance of a type with a known set of fields, make the tool aware of what it is managing. A File type gives the implementation a defined way to read a file's mode, so comparison, planning and verification are written once rather than per piece of configuration.

The requirement that forces the choice is that Datum has to be able to report what differs, what it intends to change, and whether the result was verified. All three need state to be readable and comparable, which only the third option provides.

Decision

Desired state is expressed as typed resources. Every resource has the same envelope, being datum, type, name and labels, requires and desired, and each type defines the fields its desired accepts.

A type is only admitted if its state can be read back from the host. Observability is the admission criterion, not a quality to aim for, which rules out any type whose effect cannot be measured after the fact.

Consequences

Diffing, planning, ordering and verification are written once against the type system rather than per piece of configuration. Adding a type inherits all of it.

Every capability needs a type before it can be used. Managing something Datum has no type for means writing a provider and a type definition instead of a script, which is a much higher barrier and is the main cost of this decision.

There is no escape hatch. A Command or Exec type would let anybody bypass the type system, and because such a resource could not be diffed or verified, its presence in a repository would weaken every guarantee for that host. The barrier above is therefore permanent, not something to relieve later.

The set of manageable things is bounded by what providers can observe. Configuration held in a database, in a service's runtime state, or in a format nothing can parse is outside what Datum can manage, and recognising that early is better than discovering it after a type has been designed.