mirror of
https://github.com/hashicorp/terraform.git
synced 2026-03-22 18:33:08 -04:00
Previously we were directly using the planproto.DynamicValue message type, but that's symmetrical with plans.DynamicValue in that it encodes only the value itself and not associated metadata such as the paths that have sensitive value marks. This new tfstackdata1.DynamicValue therefore echoes terraform1.DynamicValue by carrying both the value and the metadata together. This implies a slight change to one of the existing message types that was encoding a map of planned input values for each component instance, but in practice we're not currently making use of that data anyway -- it's there to enable a hypothetical extra correctness check in the stacks runtime so that we can detect inconsistency problems closer to their source -- and so this change doesn't affect anything in practice. Before we make use of it we'll probably want to change the internal API a little so that we can preserve the sensitive value metadata on those values, but that's beyond the scope of this PR. The main point of adding this is to track the output values for a component instance as part of the raw state, and so the new field for that is also added here although nothing will read or write it yet. Actual use of that new field will follow in future commits.
240 lines
11 KiB
Protocol Buffer
240 lines
11 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, 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;
|
|
|
|
// The address of the provider configuration that planned this change,
|
|
// or that produced the prior state for messages where "change" is
|
|
// unpopulated. This is a module-centric view relative to the root module
|
|
// of the component identified in component_instance_addr.
|
|
string provider_config_addr = 6;
|
|
|
|
// 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 mainly 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 {
|
|
// The component instance's output values as reported from the most recent
|
|
// apply action. We retain this only so that we have some values to use
|
|
// in cases where the values in the configuration are unavailable or
|
|
// insufficient, such as when we're making a destroy-mode plan and therefore
|
|
// the desired state would be for the component instance to cease existing
|
|
// but yet we still need to have _some_ output values to use when planning
|
|
// and applying other component instances that refer to this one.
|
|
map<string, DynamicValue> output_values = 1;
|
|
}
|
|
|
|
// 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")
|
|
}
|
|
}
|
|
|
|
message DynamicValue {
|
|
tfplan.DynamicValue value = 1;
|
|
repeated tfplan.Path sensitive_paths = 2;
|
|
}
|