§ Migrate · Annexes

Construct matrix

Which OpenTofu constructs pravo supports, supports in part, or does not support, with the replacement for each.

Time
10 min
Level
beginner
Needs
Before you start read.
You will learn
Which of the constructs in my configuration have a counterpart?
Done when
Every construct in your preflight list has a status here.

View as Markdown

On this page

Three words state the status of a construct.

Status Meaning
Supported The construct has a counterpart that does the same job. The form differs.
Partial Part of the construct has a counterpart. The note says which part.
Not supported There is no counterpart. The note gives the replacement.

Use the matrix to read your preflight list from M1. The steps that translate the supported constructs are in M4. The lookup of absent features is Not in pravo.

Blocks

Construct Status In pravo
terraform { required_providers } Supported A provider struct. $version holds the constraint. The source is the import path.
terraform { required_version } Not supported Pin pravo version in the pipeline image.
terraform { backend } Partial A local directory or an S3-compatible bucket. No other backend. No lock table.
terraform { cloud } Not supported A pipeline that runs pravo plan and pravo apply <planfile>.
terraform { encryption } Not supported Encrypt the bucket or the volume.
provider, alias Supported One struct for each configuration. The resource is built through its struct.
variable Partial A field with a constraint and @tag. -t takes scalars. No error_message. A secret is a restricted ephemeral value.
locals Supported A hidden field.
resource Supported A struct built through a provider.
data Supported A struct built from #Data.
ephemeral Supported A struct built from #Ephemeral.
output Partial pravo.#Output with value, description and sensitive. No depends_on, no precondition.
module Partial A definition, or a CUE package, that contains resources. No registry or git:: source. No depends_on on a module.
moved Supported $from on the resource, or on a group for a whole module.
import Supported $import: "id" on the resource. pravo import for one object. No generated configuration.
removed Not supported pravo state rm addr.
check Not supported A constraint on a field, or a plan policy.

Meta-arguments and nested blocks

Construct Status In pravo
count Supported A list comprehension. The address has the index.
for_each Supported A struct comprehension. The address has the key.
depends_on Partial $depends_on on a resource, a data source or an ephemeral resource. Name each instance.
provider = aws.west Supported Build the resource through the struct $west.
lifecycle.create_before_destroy Supported $lifecycle: create_before_destroy: true.
lifecycle.prevent_destroy Supported $lifecycle: prevent_destroy: true.
lifecycle.ignore_changes Supported $lifecycle: ignore_changes: ["attr"], or ["*"].
lifecycle.replace_triggered_by Not supported -replace addr, or an attribute that depends on the trigger.
lifecycle.precondition, postcondition Not supported A constraint on the field.
provisioner, connection Not supported Cloud-init, a shell provider, an SSH provider.
dynamic Supported A list comprehension in the body.

Expressions

Construct Status In pravo
for expression Supported A comprehension.
Splat [*] Supported A comprehension: [for p in ports {p.result}].
a ? b : c Supported An if clause, or [if a {b}, c][0].
"${expr}" Supported "\(expr)".
%{ if } and %{ for } in a string Not supported A comprehension and strings.Join.
Heredoc Supported A multi-line string with """.
each.key, each.value, count.index Supported The loop variables of the comprehension.
var.x, local.x, module.m.o Supported The field name: x, _x, m.o.
Built-in function Partial Most have an equivalent. See the Function map.
provider::name::fn() Supported A declaration built from #Function, with args and result.
terraform.workspace Not supported A tag: -t env=prod.
path.module, path.root Not supported Paths are relative to the root. -T supplies cwd as a tag.
optional() and object() types Supported Optional fields (a?: string) and structs.
validation Supported A constraint on the field. The message is the one CUE prints.
sensitive Partial sensitive: true on an output. The provider schema marks attributes. No sensitive() function.

State and operation

Construct Status In pravo
State format 4 Supported pravo state import-tfstate. Taint, deposed objects, check results and records of the built-in provider are not carried over.
State locking Supported A lock for each resource, on every apply.
terraform_remote_state Partial pravo.#RemoteOutputs reads the outputs.json of another pravo root. It does not read an OpenTofu state.
terraform_data Not supported null_resource of hashicorp/null.
Workspaces Not supported A tag and a state path that depends on it.
-target Not supported Scoped plans, and apply <planfile> -only addr.
-refresh-only Not supported pravo drift.
Taint Not supported -replace addr.
Saved plan Supported pravo plan -out f, pravo apply f.
JSON plan Partial pravo plan --json prints pravo's plan document. It is not the OpenTofu JSON. See M6.
Providers on the OpenTofu registry Supported Plugin protocol 5 and 6.
Providers from another registry host Supported The host is part of the import path.
Providers from a container registry Supported pravo providers copy publishes a provider version to one. See providers from a registry.
Modules from a registry Not supported CUE modules: pravo mod get, import.
tofu test Not supported pravo validate, pravo eval -c, a policy on a saved plan.

Spot check

A few supported rows have no example elsewhere in the runbook. This root declares:

  • a resource with every supported lifecycle field;
  • an ephemeral resource;
  • an import;
  • a definition, instantiated for each element of a list.
spot/main.cue
package spot

import (
	rnd "pravo.dev/providers/hashicorp/random"
	loc "pravo.dev/providers/hashicorp/local"
)

$random: rnd.#Provider
$local:  loc.#Provider

keep: $random.#Resource.random_pet & {
	length: 1
	$lifecycle: {
		create_before_destroy: true
		prevent_destroy:       true
		ignore_changes: ["prefix"]
		refresh: "1h"
	}
}

secret: $random.#Ephemeral.random_password & {length: 16}

port: $random.#Resource.random_integer & {min: 1, max: 5, $import: "3,1,5"}

#Site: {
	name: string
	file: $local.#Resource.local_file & {
		filename: "out/\(name).txt"
		content:  "\(name)\n"
	}
}

sites: {
	for s in ["a", "b"] {
		"\(s)": #Site & {name: s}
	}
}
terminal
$pravo -C spot init > /dev/null
$pravo -C spot validate
$pravo -C spot plan 2>&1 | grep -E '^( # |Plan:|Graph:)'
Success! 4 resources, 0 data sources, 1 ephemeral, 0 function calls, 0 outputs across 2 providers.
  # keep (random_pet) will be created
  # port was imported from id "3,1,5" and matches the specification
  # sites.a.file (local_file) will be created
  # sites.b.file (local_file) will be created
Plan: 3 to add, 0 to change, 0 to destroy.
Graph: planned 4 of 5, 1 ephemeral opened, 1 imported.

The plan creates the pet and the two files, imports port, and opens the ephemeral resource without recording it.

Recap

  • A supported construct has the same job and another form. A partial one says which part is missing.
  • An unsupported construct has a replacement in the same row.
  • The runbook translates the supported constructs in M4, and the absent ones are collected in Not in pravo.

Check yourself

Which status does count have, and what form does it take?

Supported. It is a list comprehension, and the address of each instance carries its index.

Does pravo read an OpenTofu state through pravo.#RemoteOutputs?

No. It reads the outputs.json of another pravo root. Convert the other root first, as M7 orders.

Back to the Migrate overview.