§ Reference · Language

Settings

The $settings block. It sets where the state lives and the default refresh age, and nothing else.

View as Markdown

On this page

$settings is the one top-level field that pravo reads for itself. It takes two keys. Any other key is an error.

Key Type Default Meaning
state.path string pravo.state Directory of the local state, relative to the root.
state.backend "local" or "s3" "local" Where the state is kept. A bucket without a backend selects "s3".
state.bucket and the other S3 keys string, bool none The S3 backend. See S3 keys.
refresh "always", "never" or a duration "always" The default refresh age of every resource.

Write the block as pravo.#Settings & {...}. The schema comes from the generated pravo.dev/pravo package. It lets editors complete the keys, and CUE rejects a misspelt key or a value of the wrong type. Work in an empty directory.

main.cue
package demo

import "pravo.dev/pravo"

env: *"dev" | "staging" | "prod" @tag(env)

$settings: pravo.#Settings & {
	state: path: "state/\(env)"
	refresh: "1h"
}
terminal
$pravo init
$pravo eval -e '$settings.state.path'
$pravo eval -t env=prod -e '$settings.state.path'
$pravo eval -e '$settings.refresh'
Configuration does not load yet; generating schemas for the declared providers first.
Created cue.mod/module.cue
Providers:

pravo has been initialised. Run "pravo plan" to see what it would do.
"state/dev"
"state/prod"
"1h"

The state path depends on the tag env. When env has no default and no tag is given, the path is not concrete, and pravo says so:

main.cue
package demo

import "pravo.dev/pravo"

env: "dev" | "staging" | "prod" @tag(env)

$settings: pravo.#Settings & {state: path: "state/\(env)"}
terminalexit 6
$pravo validate
Error: $settings.state.path is not concrete: $settings.state.path: non-concrete value string
(if it depends on a tagged field such as env, pass -t env=...)

state

state.path is the directory of the state. A command that writes the state creates the directory when it does not exist. A command that only reads it, such as eval, output or pravo state list, reads an empty state and creates nothing. A path that names a file is an error, and pravo changes nothing. The layout is in State format.

The block is typed by backend. path belongs to the local backend. The S3 keys belong to s3. Mixing them is an error when the root is evaluated.

main.cue
package demo

import "pravo.dev/pravo"

$settings: pravo.#Settings & {
	state: {backend: "s3", bucket: "infra-state", path: "x"}
}
terminalexit 6
$pravo validate
Error: evaluating .:
$settings.state: 2 errors in empty disjunction:
$settings.state.backend: conflicting values "local" and "s3":
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:83:10
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:97:33
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:114:12
    ./main.cue:5:12
    ./main.cue:6:19
$settings.state.path: field not allowed:
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:101:2
    ./main.cue:6:48

The same mistakes without the schema are reported in pravo's words:

main.cue
package demo

$settings: state: {backend: "local", bucket: "infra-state"}
terminalexit 6
$pravo validate
Error: $settings.state.bucket belongs to the s3 backend: set backend: "s3", or remove it for local state

S3 keys

The graph can live in an S3 bucket or in any store that speaks the S3 API. The layout is the same, with objects in place of files.

Key Meaning
backend "s3". Required for these keys, unless bucket is set.
bucket Bucket name. Required. The bucket must exist.
prefix Key prefix under which the graph lives. Several roots can share a bucket. Default: the bucket root.
region Region to sign for. Default: the AWS configuration, then us-east-1.
endpoint Service URL of an S3-compatible store. Implies path-style addressing.
path_style Forces path-style addressing: host/bucket/key.
profile A shared-configuration profile.
access_key, secret_key Static credentials, used when both are set. They are stored in the configuration.

Without static credentials, pravo uses the AWS credential chain: environment variables, the shared files, then an instance or task role. A lock is an object created with a conditional write. See State format.

main.cue
package demo

import "pravo.dev/pravo"

$settings: pravo.#Settings & {
	state: {
		backend:    "s3"
		bucket:     "infra-state"
		prefix:     "teams/platform/app"
		endpoint:   "https://minio.internal:9000"
		path_style: true
	}
}
terminal
$pravo validate
Success! 0 resources, 0 data sources, 0 ephemeral, 0 function calls, 0 outputs across 0 providers.

pravo validate does not open the state. Commands that read or write it, such as plan and eval, connect to the bucket.

Any other backend value is rejected:

main.cue
package demo

$settings: state: backend: "gcs"
terminalexit 6
$pravo validate
Error: $settings.state.backend: unknown backend "gcs" (want local or s3)

refresh

refresh is the default refresh age: how old a record may be before a plan that looks at the resource reads it from its provider again. A plan looks at the resources it reaches and at the resources they read; the rest are not read, whatever their age. See Plans.

Value Meaning
"always" Age zero. Every plan reads the records it looks at. This is the default.
"never" No limit. A plan reads a record only on request.
a number and a unit ms, s, m, h or d, such as "30m", "6h" or "7d".

A resource overrides the default with $lifecycle: refresh; see Meta fields. The command line overrides both for one run with -refresh=expired, -refresh=all or -refresh=false. The setting is not an age of its own for a resource: only $lifecycle: refresh makes a plan read a resource that it does not look at.

A longer age means fewer calls to the providers for the records that a plan looks at, and a longer time for which a change made outside pravo can go unseen. Choosing a refresh age says how to pick one.

main.cue
package demo

import "pravo.dev/pravo"

$settings: pravo.#Settings & {refresh: "soon"}
terminalexit 6
$pravo validate
Error: evaluating .:
$settings.refresh: 3 errors in empty disjunction:
$settings.refresh: conflicting values "always" and "soon":
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:87:12
    ./main.cue:5:12
    ./main.cue:5:40
$settings.refresh: conflicting values "never" and "soon":
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:87:23
    ./main.cue:5:12
    ./main.cue:5:40
$settings.refresh: invalid value "soon" (out of bound =~"^[0-9]+(ms|s|m|h|d)$"):
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:87:33
    ./cue.mod/gen/pravo.dev/pravo/settings_gen.cue:87:12
    ./main.cue:5:40

Without the schema, pravo checks the value itself:

main.cue
package demo

$settings: refresh: "soon"
terminalexit 6
$pravo validate
Error: $settings.refresh: "soon" is not a refresh age; want "always", "never" or a duration such as "30m", "6h" or "7d"

Unknown keys

$settings takes state and refresh. A plan policy is named with --policy by whoever runs pravo, and $settings has no key for it. See Policies.

main.cue
package demo

$settings: policy: "policy/plan.cue"
terminalexit 6
$pravo validate
Error: $settings.policy is not a setting (the block takes state and refresh)

See also