mirror of
https://github.com/hashicorp/terraform.git
synced 2026-03-27 12:54:12 -04:00
Previously our raw plan data structure only included information about resource instances that have planned actions, which meant we were missing those which only get their state updated during refresh and don't actually need any real work done. Now we'll track everything, accepting that some "planned changes" for resource instance objects will not actually include a planned change in the typical sense, and instead only represent a state update.
223 lines
9.8 KiB
Protocol Buffer
223 lines
9.8 KiB
Protocol Buffer
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
syntax = "proto3";
|
|
package tfstackdata1;
|
|
|
|
import "planfile.proto"; // tfplan, from internal/plans/planproto
|
|
import "google/protobuf/any.proto";
|
|
|
|
// These definitions describe the PRIVATE raw format that we use to persist
|
|
// stack and plan information for stacks between operations.
|
|
//
|
|
// Nothing outside of this codebase should attempt to produce or consume
|
|
// these formats. They are subject to change at any time.
|
|
|
|
///////////// PLAN SEQUENCE MESSAGES
|
|
//
|
|
// A "stack plan" consists of a sequence of messages emitted gradually from
|
|
// the streaming Stacks.PlanStackChanges RPC in the Terraform Core RPC API.
|
|
//
|
|
// From the perspective of that protocol the objects in the sequence are
|
|
// opaque and to be preserved byte-for-byte without any external interpretation,
|
|
// in the same order they were emitted from Terraform Core.
|
|
//
|
|
// Internally, we decode each one based on the type field of google.protobuf.Any,
|
|
// treating each one as some kind of mutation of our in-memory plan data
|
|
// structure.
|
|
//
|
|
// These message types only cover the data that Terraform needs to apply the
|
|
// plan, and so don't cover any information that Terraform Core might emit
|
|
// only for the caller's benefit.
|
|
//////////////
|
|
|
|
// Appears early in a raw plan sequence to capture some metadata that we need
|
|
// to process subsequent messages, or to abort if we're being asked to decode
|
|
// a plan created by a different version of Terraform.
|
|
message PlanHeader {
|
|
// The canonical version string for the version of Terraform that created
|
|
// the plan sequence that this message belongs to.
|
|
//
|
|
// The raw plan sequence loader will fail if it finds a message of this
|
|
// type with a version string that disagrees with the version of Terraform
|
|
// decoding the message, because we always expect plans to be applied by
|
|
// the same version of Terraform that created them.
|
|
string terraform_version = 1;
|
|
|
|
// A verbatim copy of the state that was provided with the request to
|
|
// create the plan.
|
|
map<string, google.protobuf.Any> prev_run_state_raw = 2;
|
|
}
|
|
|
|
// Confirms whether the overall plan whose raw plan sequence includes this
|
|
// message is complete enough and valid enough to be applied.
|
|
//
|
|
// If a the sequence of raw plan messages includes multiple messages of this
|
|
// type then the one with the latest position in the list "wins" during
|
|
// decoding of the overall sequence, although in practice there isn't yet
|
|
// any clear reason to include more than one instance of this message type in a
|
|
// plan.
|
|
message PlanApplyable {
|
|
bool applyable = 1;
|
|
}
|
|
|
|
// Records the value of one of the main stack's input values during planning.
|
|
//
|
|
// These values get fixed during the plan phase so that we can ensure that we
|
|
// use identical values when subsequently applying the plan.
|
|
message PlanRootInputValue {
|
|
string name = 1;
|
|
tfplan.DynamicValue value = 2;
|
|
}
|
|
|
|
// Represents the existence of a particular component instance, and so must
|
|
// always appear before any messages representing objects that belong to that
|
|
// component instance.
|
|
//
|
|
// This message type exists to avoid the ambiguity between a component instance
|
|
// existing with zero resource instances inside vs. a component instance
|
|
// not existing at all.
|
|
message PlanComponentInstance {
|
|
string component_instance_addr = 1;
|
|
|
|
// plan_timestamp records the time when the plan for this component
|
|
// instance was created, exclusively for making sure that the
|
|
// "plantimestamp" function can return the same value during the apply
|
|
// phase. It must not be used for any other purpose.
|
|
string plan_timestamp = 2;
|
|
|
|
// Captures an approximation of the input values for this component with
|
|
// as much detail as we knew during the planning phase. This might
|
|
// contain unknown values as placeholders for values that won't be
|
|
// determined until the apply phase, so this isn't usable directly as
|
|
// the input to subsequently applying the component plan but the final
|
|
// input values should be a valid concretization of what's described here.
|
|
map<string, tfplan.DynamicValue> planned_input_values = 3;
|
|
}
|
|
|
|
// Represents a planned change to a particular resource instance within a
|
|
// particular component instance.
|
|
message PlanResourceInstanceChangePlanned {
|
|
// The same string must previously have been announced with a
|
|
// PlanComponentInstance message, or the overall plan sequence is invalid.
|
|
string component_instance_addr = 1;
|
|
string resource_instance_addr = 4;
|
|
string deposed_key = 5;
|
|
|
|
// Description of the planned change in the standard "tfplan" (planproto)
|
|
// format.
|
|
tfplan.ResourceInstanceChange change = 2;
|
|
|
|
// A snapshot of the "prior state", which is the result of upgrading and
|
|
// refreshing the previous run's state.
|
|
//
|
|
// The very first action on applying this plan should be to update the
|
|
// raw state for the resource instance to match this value, since
|
|
// the main apply phase for each component instance assumes that the
|
|
// prior state has already been updated to match the "old" value from
|
|
// the "change" message.
|
|
StateResourceInstanceObjectV1 prior_state = 3;
|
|
}
|
|
|
|
// Represents that we need to emit "delete" requests for one or more raw
|
|
// state and/or state description objects during the apply phase.
|
|
//
|
|
// This situation arises if the previous state (given as input to the apply
|
|
// phase) contains keys that are of a type unrecognized by the current
|
|
// version of Terraform and that are marked as "discard if unrecognized",
|
|
// suggesting that their content is likely to become somehow invalid if
|
|
// other parts of the state were to get updated.
|
|
message PlanDiscardStateMapKeys {
|
|
// A set of keys to delete from the "raw state".
|
|
repeated string raw_state_keys = 1;
|
|
|
|
// A set of keys to delete from the "state description".
|
|
repeated string description_keys = 2;
|
|
}
|
|
|
|
///////////// STATE MAP MESSAGES
|
|
//
|
|
// A "stack state snapshot" is a mapping from arbitrary keys to messages
|
|
// emitted gradually from the streaming Stacks.ApplyStackChanges RPC in the
|
|
// Terraform Core RPC API.
|
|
//
|
|
// From the perspective of that protocol the keys and values in the map are
|
|
// opaque and to be preserved verbatim without any external interpretation,
|
|
// overwriting any previous value that had the same key.
|
|
//
|
|
// Internally, we decode each one based on the type field of google.protobuf.Any,
|
|
// treating each one as some kind of mutation of our in-memory plan data
|
|
// structure.
|
|
//
|
|
// These message types only cover the data that Terraform needs to produce
|
|
// a future plan based on this snapshot, and don't cover any information that
|
|
// Terraform Core might emit only for the caller's benefit.
|
|
//
|
|
// Because state messages survive from one run to the next, all top-level
|
|
// messages used for state snapshots have a format version suffix that is
|
|
// currently always 1. The functions that load a state map into the in-memory
|
|
// state structure will fail if any of the messages are of an unknown type, so
|
|
// we should increment the format version only as a last resort because this
|
|
// will prevent users from downgrading to an earlier version of Terraform once
|
|
// they've got at least one state map message that is of a newer version.
|
|
//////////////
|
|
|
|
// Represents the existence of a particular component instance.
|
|
//
|
|
// This is here just to remove the ambiguity between a component instance that
|
|
// exists but contains no resource instances vs. a component instance that
|
|
// doesn't exist at all.
|
|
//
|
|
// Because the state map is updated on a per-element basis rather than
|
|
// atomically, it's possible that the state map might contain resource instances
|
|
// which belong to a component instance that is not tracked by a message of
|
|
// this type. In that case, the state loader will just assume an implied
|
|
// message of this type with a matching component instance address and with
|
|
// all other fields unset.
|
|
message StateComponentInstanceV1 {
|
|
// No details to track yet. The presence of an instance of this message
|
|
// at all is the signal of the component instance's existence.
|
|
}
|
|
|
|
// Represents the existence of a particular resource instance object in a
|
|
// particular component instance.
|
|
//
|
|
// A resource instance message object should typically be accompanied by a
|
|
// StateComponentInstanceV1 (or later version) that represents the existence
|
|
// of the component itself, but for robustness we tolerate the absense of
|
|
// such a message and just assume that all of its fields (other than the
|
|
// component instance address) are unset.
|
|
message StateResourceInstanceObjectV1 {
|
|
// value_json is a JSON representation of the object value representing
|
|
// this resource instance object.
|
|
//
|
|
// This is JSON-serialized rather than MessagePack serialized (as we do
|
|
// for everything else in this format and in the RPC API) because
|
|
// the provider protocol only supports legacy flatmap and JSON as input
|
|
// to the state upgrade process, and we won't be able to transcode from
|
|
// MessagePack to JSON once we decode this because we won't know the
|
|
// schema that the value was encoded with.
|
|
//
|
|
// This is a pragmatic exception for this particular quirk of Terraform's
|
|
// provider API design. Other parts of this format and associated protocol
|
|
// should use tfplan.DynamicValue and MessagePack encoding for consistency.
|
|
bytes value_json = 1;
|
|
repeated tfplan.Path sensitive_paths = 2;
|
|
uint64 schema_version = 3;
|
|
|
|
Status status = 4;
|
|
repeated string dependencies = 5;
|
|
bool create_before_destroy = 6;
|
|
string provider_config_addr = 7;
|
|
|
|
// provider_specific_data is arbitrary bytes produced by the provider
|
|
// in its apply response which we preserve and pass back to it in any
|
|
// subsequent plan operation.
|
|
bytes provider_specific_data = 8;
|
|
|
|
enum Status {
|
|
UNKNOWN = 0;
|
|
READY = 1;
|
|
DAMAGED = 2; // (formerly known as "tainted")
|
|
}
|
|
}
|