pulumi/pkg/resource/resource_state.go
pat@pulumi.com 6b66437fae Track resources that are pending deletion in checkpoints.
During the course of a `pulumi update`, it is possible for a resource to
become slated for deletion. In the case that this deletion is part of a
replacement, another resource with the same URN as the to-be-deleted
resource will have been created earlier. If the `update` fails after the
replacement resource is created but before the original resource has been
deleted, the snapshot must capture that the original resource still exists
and should be deleted in a future update without losing track of the order
in which the deletion must occur relative to other deletes. Currently, we
are unable to track this information because the our checkpoints require
that no two resources have the same URN.

To fix this, these changes introduce to the update engine the notion of a
resource that is pending deletion and change checkpoint serialization to
use an array of resources rather than a map. The meaning of the former is
straightforward: a resource that is pending deletion should be deleted
during the next update.

This is a fairly major breaking change to our checkpoint files, as the
map of resources is no more. Happily, though, it makes our checkpoint
files a bit more "obvious" to any tooling that might want to grovel
or rewrite them.

Fixes #432, #387.
2017-10-18 17:09:00 -07:00

60 lines
2.6 KiB
Go

// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
package resource
import (
"github.com/pulumi/pulumi/pkg/tokens"
"github.com/pulumi/pulumi/pkg/util/contract"
)
// State is a structure containing state associated with a resource. This resource may have been serialized and
// deserialized, or snapshotted from a live graph of resource objects. The value's state is not, however, associated
// with any runtime objects in memory that may be actively involved in ongoing computations.
type State struct {
Type tokens.Type // the resource's type.
URN URN // the resource's object urn, a human-friendly, unique name for the resource.
Custom bool // true if the resource is custom, managed by a plugin.
Delete bool // true if this resource is pending deletion due to a replacement.
ID ID // the resource's unique ID, assigned by the resource provider (or blank if none/uncreated).
Inputs PropertyMap // the resource's input properties (as specified by the program).
Defaults PropertyMap // the resource's default property values (if any, given by the provider).
Outputs PropertyMap // the resource's complete output state (as returned by the resource provider).
Children []URN // an optional list of children belonging to this parent resource.
}
// NewState creates a new resource value from existing resource state information.
func NewState(t tokens.Type, urn URN, custom bool, del bool, id ID,
inputs PropertyMap, defaults PropertyMap, outputs PropertyMap, children []URN) *State {
contract.Assert(t != "")
contract.Assert(custom || id == "")
contract.Assert(inputs != nil)
return &State{
Type: t,
URN: urn,
Custom: custom,
Delete: del,
ID: id,
Inputs: inputs,
Defaults: defaults,
Outputs: outputs,
Children: children,
}
}
// All returns all resource state, including the inputs, defaults, and outputs, overlaid in that order.
func (s *State) All() PropertyMap {
return s.AllInputs().Merge(s.Outputs)
}
// AllInputs returns just the resource state's inputs plus any defaults supplied by the provider. This is to be used
// when diffing resource states that are entirely under the control of the developer, instead of a cloud provider.
func (s *State) AllInputs() PropertyMap {
return s.Defaults.Merge(s.Inputs)
}
// Synthesized returns all of the resource's "synthesized" state; this includes all properties that appeared in the
// default and output set, which may or may not override some or all of those that appeared in the input set.
func (s *State) Synthesized() PropertyMap {
return s.Defaults.Merge(s.Outputs)
}