§ A2 · Track A · CUE from zero
A value can be a type
In CUE, int and 30 are both values. One allows every integer and the other allows one.
On this page
In HCL, a type and a value are separate declarations. They sit in separate files and meet by name.
variable "retention_days" {
type = number
}
retention_days = 30
OpenTofu checks the second file against the first when it plans. The type has no value, and the value has no type.
In CUE, int is a value. So is 30. The first stands for every integer. The second stands for one. A field can hold either, and a bound such as >=1 sits between them.
A value that stands for one thing is concrete. A value that stands for many things is a constraint. 30, "web" and true are concrete. int, string, bool and >=1 are constraints.
| You write | It allows | Kind |
|---|---|---|
int |
every integer | constraint |
>=1 |
every number from 1 upward | constraint |
30 |
exactly 30 | concrete |
The more specific the value, the fewer values it allows.
Leave some values open
Work in the directory from A1. The platform team knows everything about logs. The web team has answered only part of the questions about uploads. Record what is known and leave the rest as constraints. Replace estate.cue. Each bucket gains encrypted and retention_days.
package estate
buckets: {
logs: {
name: "logs"
versioning: true // keep old versions
encrypted: true
retention_days: 365
tags: owner: "platform"
}
uploads: {
name: "uploads"
versioning: false
encrypted: bool
retention_days: >=1
tags: owner: string
}
}
rules: {
https: {
port: 443
protocol: "tcp"
}
ssh: {
port: 22
protocol: "tcp"
}
}
Ask for the uploads bucket only. The -e flag evaluates one field, given by its path.
name: "uploads"
versioning: false
encrypted: bool
retention_days: >=1
tags: {
owner: string
}
pravo eval prints a constraint as it is. An unfinished value is not an error.
uploads has five fields: name, versioning, encrypted, retention_days and tags.owner. Decide before you open the answer.
Predict Which fields of the uploads bucket are concrete?
name and versioning. They hold "uploads" and false, each one value. The other three hold bool, >=1 and string. The flag -c asks pravo eval to fail unless the value is concrete, so these two commands pass.
"uploads"
false
Break it
The flag -c makes pravo eval fail unless every value is concrete. Run it on the file you wrote. The file is valid. The command is refused.
Error: the value is not concrete:
buckets.uploads.encrypted: incomplete value bool:
./estate.cue:14:19
buckets.uploads.retention_days: incomplete value >=1:
./estate.cue:15:19
buckets.uploads.tags.owner: incomplete value string:
./estate.cue:16:16
Read the error from left to right.
- Stage.
the value is not concretesays that-crefused the file. The CUE is valid. - Path. Each message starts with the path of a field:
buckets.uploads.encrypted. There are three, one for each constraint left inuploads. - Message.
incomplete value boolsays that the field holds the constraintbool. It names the constraint after the wordvalue. - Location.
./estate.cue:14:19is the file, the line and the column of the constraint.
Incomplete does not mean wrong. It means not finished. Why is my value incomplete? lists the causes.
Exercise
Finish the uploads bucket
The web team replies: encrypted, kept for 30 days, owned by web. Replace the three constraints in uploads with these concrete values.
The check passes when pravo eval -c succeeds.
pravo eval -c > /dev/null 2>&1 || { echo "a value is still not concrete"; exit 1; }
echo ok
Run it on the start state. It fails.
a value is still not concrete
Hint 1
Replace each constraint with one value of the same kind. Use a boolean, a whole number from 1 upward and a string.
Hint 2
pravo eval -c lists every field that is still open. See concrete for the definition.
Solution
package estate
buckets: {
logs: {
name: "logs"
versioning: true // keep old versions
encrypted: true
retention_days: 365
tags: owner: "platform"
}
uploads: {
name: "uploads"
versioning: false
encrypted: true
retention_days: 30
tags: owner: "web"
}
}
rules: {
https: {
port: 443
protocol: "tcp"
}
ssh: {
port: 22
protocol: "tcp"
}
}
Recap
- A type such as
intis a value that stands for every value of its kind.30stands for one. - A constraint allows many values. A concrete value allows one.
pravo evalprints constraints as they are.pravo eval -cfails while any remain.
Check yourself
Is string a value?
Yes. It is the value that stands for every string. "web" is a narrower value that stands for one.
What does incomplete value bool tell you?
The field holds the constraint bool and not a concrete value. It is not wrong. It is not finished.
The next lesson writes encrypted: bool and encrypted: true for the same field.