This commit is contained in:
Pat Gavlin 2020-11-30 14:19:38 -08:00
parent 2818c9888d
commit 6de090c540
20 changed files with 65 additions and 58 deletions

View file

@ -27,6 +27,7 @@ import (
"github.com/pulumi/pulumi/pkg/v3/backend/display" "github.com/pulumi/pulumi/pkg/v3/backend/display"
"github.com/pulumi/pulumi/pkg/v3/engine" "github.com/pulumi/pulumi/pkg/v3/engine"
"github.com/pulumi/pulumi/pkg/v3/resource/deploy"
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype" "github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors" "github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi/sdk/v3/go/common/resource"
@ -45,7 +46,7 @@ type ApplierOptions struct {
// Applier applies the changes specified by this update operation against the target stack. // Applier applies the changes specified by this update operation against the target stack.
type Applier func(ctx context.Context, kind apitype.UpdateKind, stack Stack, op UpdateOperation, type Applier func(ctx context.Context, kind apitype.UpdateKind, stack Stack, op UpdateOperation,
opts ApplierOptions, events chan<- engine.Event) (engine.Plan, engine.ResourceChanges, result.Result) opts ApplierOptions, events chan<- engine.Event) (deploy.Plan, engine.ResourceChanges, result.Result)
func ActionLabel(kind apitype.UpdateKind, dryRun bool) string { func ActionLabel(kind apitype.UpdateKind, dryRun bool) string {
v := updateTextMap[kind] v := updateTextMap[kind]
@ -80,7 +81,7 @@ const (
) )
func PreviewThenPrompt(ctx context.Context, kind apitype.UpdateKind, stack Stack, func PreviewThenPrompt(ctx context.Context, kind apitype.UpdateKind, stack Stack,
op UpdateOperation, apply Applier) (engine.Plan, engine.ResourceChanges, result.Result) { op UpdateOperation, apply Applier) (deploy.Plan, engine.ResourceChanges, result.Result) {
// create a channel to hear about the update events from the engine. this will be used so that // create a channel to hear about the update events from the engine. this will be used so that
// we can build up the diff display in case the user asks to see the details of the diff // we can build up the diff display in case the user asks to see the details of the diff

View file

@ -162,7 +162,7 @@ type Backend interface {
RenameStack(ctx context.Context, stack Stack, newName tokens.QName) (StackReference, error) RenameStack(ctx context.Context, stack Stack, newName tokens.QName) (StackReference, error)
// Preview shows what would be updated given the current workspace's contents. // Preview shows what would be updated given the current workspace's contents.
Preview(ctx context.Context, stack Stack, op UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) Preview(ctx context.Context, stack Stack, op UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result)
// Update updates the target stack with the current workspace's contents (config and code). // Update updates the target stack with the current workspace's contents (config and code).
Update(ctx context.Context, stack Stack, op UpdateOperation) (engine.ResourceChanges, result.Result) Update(ctx context.Context, stack Stack, op UpdateOperation) (engine.ResourceChanges, result.Result)
// Import imports resources into a stack. // Import imports resources into a stack.

View file

@ -459,7 +459,7 @@ func (b *localBackend) PackPolicies(
} }
func (b *localBackend) Preview(ctx context.Context, stack backend.Stack, func (b *localBackend) Preview(ctx context.Context, stack backend.Stack,
op backend.UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) { op backend.UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result) {
if cmdutil.IsTruthy(os.Getenv(PulumiFilestateLockingEnvVar)) { if cmdutil.IsTruthy(os.Getenv(PulumiFilestateLockingEnvVar)) {
err := b.Lock(ctx, stack.Ref()) err := b.Lock(ctx, stack.Ref())
@ -546,7 +546,7 @@ func (b *localBackend) Watch(ctx context.Context, stack backend.Stack,
func (b *localBackend) apply( func (b *localBackend) apply(
ctx context.Context, kind apitype.UpdateKind, stack backend.Stack, ctx context.Context, kind apitype.UpdateKind, stack backend.Stack,
op backend.UpdateOperation, opts backend.ApplierOptions, op backend.UpdateOperation, opts backend.ApplierOptions,
events chan<- engine.Event) (engine.Plan, engine.ResourceChanges, result.Result) { events chan<- engine.Event) (deploy.Plan, engine.ResourceChanges, result.Result) {
stackRef := stack.Ref() stackRef := stack.Ref()
stackName := stackRef.Name() stackName := stackRef.Name()
@ -602,7 +602,7 @@ func (b *localBackend) apply(
// Perform the update // Perform the update
start := time.Now().Unix() start := time.Now().Unix()
var plan engine.Plan var plan deploy.Plan
var changes engine.ResourceChanges var changes engine.ResourceChanges
var updateRes result.Result var updateRes result.Result
switch kind { switch kind {

View file

@ -64,7 +64,7 @@ func (s *localStack) Rename(ctx context.Context, newName tokens.QName) (backend.
return backend.RenameStack(ctx, s, newName) return backend.RenameStack(ctx, s, newName)
} }
func (s *localStack) Preview(ctx context.Context, op backend.UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) { func (s *localStack) Preview(ctx context.Context, op backend.UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result) {
return backend.PreviewStack(ctx, s, op) return backend.PreviewStack(ctx, s, op)
} }

View file

@ -824,7 +824,7 @@ func (b *cloudBackend) RenameStack(ctx context.Context, stack backend.Stack,
} }
func (b *cloudBackend) Preview(ctx context.Context, stack backend.Stack, func (b *cloudBackend) Preview(ctx context.Context, stack backend.Stack,
op backend.UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) { op backend.UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result) {
// We can skip PreviewtThenPromptThenExecute, and just go straight to Execute. // We can skip PreviewtThenPromptThenExecute, and just go straight to Execute.
opts := backend.ApplierOptions{ opts := backend.ApplierOptions{
DryRun: true, DryRun: true,
@ -927,7 +927,7 @@ func (b *cloudBackend) createAndStartUpdate(
func (b *cloudBackend) apply( func (b *cloudBackend) apply(
ctx context.Context, kind apitype.UpdateKind, stack backend.Stack, ctx context.Context, kind apitype.UpdateKind, stack backend.Stack,
op backend.UpdateOperation, opts backend.ApplierOptions, op backend.UpdateOperation, opts backend.ApplierOptions,
events chan<- engine.Event) (engine.Plan, engine.ResourceChanges, result.Result) { events chan<- engine.Event) (deploy.Plan, engine.ResourceChanges, result.Result) {
actionLabel := backend.ActionLabel(kind, opts.DryRun) actionLabel := backend.ActionLabel(kind, opts.DryRun)
@ -981,7 +981,7 @@ func (b *cloudBackend) query(ctx context.Context, op backend.QueryOperation,
func (b *cloudBackend) runEngineAction( func (b *cloudBackend) runEngineAction(
ctx context.Context, kind apitype.UpdateKind, stackRef backend.StackReference, ctx context.Context, kind apitype.UpdateKind, stackRef backend.StackReference,
op backend.UpdateOperation, update client.UpdateIdentifier, token string, op backend.UpdateOperation, update client.UpdateIdentifier, token string,
callerEventsOpt chan<- engine.Event, dryRun bool) (engine.Plan, engine.ResourceChanges, result.Result) { callerEventsOpt chan<- engine.Event, dryRun bool) (deploy.Plan, engine.ResourceChanges, result.Result) {
contract.Assertf(token != "", "persisted actions require a token") contract.Assertf(token != "", "persisted actions require a token")
u, err := b.newUpdate(ctx, stackRef, op, update, token) u, err := b.newUpdate(ctx, stackRef, op, update, token)
@ -1035,7 +1035,7 @@ func (b *cloudBackend) runEngineAction(
engineCtx.ParentSpan = parentSpan.Context() engineCtx.ParentSpan = parentSpan.Context()
} }
var plan engine.Plan var plan deploy.Plan
var changes engine.ResourceChanges var changes engine.ResourceChanges
var res result.Result var res result.Result
switch kind { switch kind {

View file

@ -140,7 +140,7 @@ func (s *cloudStack) Rename(ctx context.Context, newName tokens.QName) (backend.
return backend.RenameStack(ctx, s, newName) return backend.RenameStack(ctx, s, newName)
} }
func (s *cloudStack) Preview(ctx context.Context, op backend.UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) { func (s *cloudStack) Preview(ctx context.Context, op backend.UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result) {
return backend.PreviewStack(ctx, s, op) return backend.PreviewStack(ctx, s, op)
} }

View file

@ -57,7 +57,7 @@ type MockBackend struct {
LogoutAllF func() error LogoutAllF func() error
CurrentUserF func() (string, error) CurrentUserF func() (string, error)
PreviewF func(context.Context, Stack, PreviewF func(context.Context, Stack,
UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result)
UpdateF func(context.Context, Stack, UpdateF func(context.Context, Stack,
UpdateOperation) (engine.ResourceChanges, result.Result) UpdateOperation) (engine.ResourceChanges, result.Result)
ImportF func(context.Context, Stack, ImportF func(context.Context, Stack,
@ -180,7 +180,7 @@ func (be *MockBackend) GetStackCrypter(stackRef StackReference) (config.Crypter,
} }
func (be *MockBackend) Preview(ctx context.Context, stack Stack, func (be *MockBackend) Preview(ctx context.Context, stack Stack,
op UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) { op UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result) {
if be.PreviewF != nil { if be.PreviewF != nil {
return be.PreviewF(ctx, stack, op) return be.PreviewF(ctx, stack, op)
@ -335,7 +335,7 @@ type MockStack struct {
ConfigF func() config.Map ConfigF func() config.Map
SnapshotF func(ctx context.Context) (*deploy.Snapshot, error) SnapshotF func(ctx context.Context) (*deploy.Snapshot, error)
BackendF func() Backend BackendF func() Backend
PreviewF func(ctx context.Context, op UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) PreviewF func(ctx context.Context, op UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result)
UpdateF func(ctx context.Context, op UpdateOperation) (engine.ResourceChanges, result.Result) UpdateF func(ctx context.Context, op UpdateOperation) (engine.ResourceChanges, result.Result)
ImportF func(ctx context.Context, op UpdateOperation, ImportF func(ctx context.Context, op UpdateOperation,
imports []deploy.Import) (engine.ResourceChanges, result.Result) imports []deploy.Import) (engine.ResourceChanges, result.Result)
@ -381,7 +381,7 @@ func (ms *MockStack) Backend() Backend {
panic("not implemented") panic("not implemented")
} }
func (ms *MockStack) Preview(ctx context.Context, op UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) { func (ms *MockStack) Preview(ctx context.Context, op UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result) {
if ms.PreviewF != nil { if ms.PreviewF != nil {
return ms.PreviewF(ctx, op) return ms.PreviewF(ctx, op)
} }

View file

@ -40,7 +40,7 @@ type Stack interface {
Backend() Backend // the backend this stack belongs to. Backend() Backend // the backend this stack belongs to.
// Preview changes to this stack. // Preview changes to this stack.
Preview(ctx context.Context, op UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) Preview(ctx context.Context, op UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result)
// Update this stack. // Update this stack.
Update(ctx context.Context, op UpdateOperation) (engine.ResourceChanges, result.Result) Update(ctx context.Context, op UpdateOperation) (engine.ResourceChanges, result.Result)
// Import resources into this stack. // Import resources into this stack.
@ -75,7 +75,7 @@ func RenameStack(ctx context.Context, s Stack, newName tokens.QName) (StackRefer
} }
// PreviewStack previews changes to this stack. // PreviewStack previews changes to this stack.
func PreviewStack(ctx context.Context, s Stack, op UpdateOperation) (engine.Plan, engine.ResourceChanges, result.Result) { func PreviewStack(ctx context.Context, s Stack, op UpdateOperation) (deploy.Plan, engine.ResourceChanges, result.Result) {
return s.Backend().Preview(ctx, s, op) return s.Backend().Preview(ctx, s, op)
} }

View file

@ -20,7 +20,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/pulumi/pulumi/pkg/v2/backend/display" "github.com/pulumi/pulumi/pkg/v2/backend/display"
"github.com/pulumi/pulumi/pkg/v2/engine"
"github.com/pulumi/pulumi/pkg/v2/resource/deploy" "github.com/pulumi/pulumi/pkg/v2/resource/deploy"
"github.com/pulumi/pulumi/sdk/v2/go/common/diag/colors" "github.com/pulumi/pulumi/sdk/v2/go/common/diag/colors"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource" "github.com/pulumi/pulumi/sdk/v2/go/common/resource"
@ -150,7 +149,7 @@ func pruneSames(root *planNode) *planNode {
return root return root
} }
func renderPlan(plan engine.Plan, showSames bool, color colors.Colorization) []cmdutil.TableRow { func renderPlan(plan deploy.Plan, showSames bool, color colors.Colorization) []cmdutil.TableRow {
var root *planNode var root *planNode
var orphans []*planNode var orphans []*planNode
nodes := map[resource.URN]*planNode{} nodes := map[resource.URN]*planNode{}

View file

@ -41,6 +41,7 @@ import (
"github.com/pulumi/pulumi/pkg/v3/backend/httpstate" "github.com/pulumi/pulumi/pkg/v3/backend/httpstate"
"github.com/pulumi/pulumi/pkg/v3/backend/state" "github.com/pulumi/pulumi/pkg/v3/backend/state"
"github.com/pulumi/pulumi/pkg/v3/engine" "github.com/pulumi/pulumi/pkg/v3/engine"
"github.com/pulumi/pulumi/pkg/v3/resource/deploy"
"github.com/pulumi/pulumi/pkg/v3/resource/stack" "github.com/pulumi/pulumi/pkg/v3/resource/stack"
"github.com/pulumi/pulumi/pkg/v3/secrets/passphrase" "github.com/pulumi/pulumi/pkg/v3/secrets/passphrase"
"github.com/pulumi/pulumi/pkg/v3/util/cancel" "github.com/pulumi/pulumi/pkg/v3/util/cancel"
@ -864,7 +865,7 @@ func getRefreshOption(proj *workspace.Project, refresh string) (bool, error) {
return false, nil return false, nil
} }
func writePlan(path string, plan engine.Plan, enc config.Encrypter, showSecrets bool) error { func writePlan(path string, plan deploy.Plan, enc config.Encrypter, showSecrets bool) error {
f, err := os.Create(path) f, err := os.Create(path)
if err != nil { if err != nil {
return err return err
@ -878,7 +879,7 @@ func writePlan(path string, plan engine.Plan, enc config.Encrypter, showSecrets
return json.NewEncoder(f).Encode(deploymentPlan) return json.NewEncoder(f).Encode(deploymentPlan)
} }
func readPlan(path string, dec config.Decrypter, enc config.Encrypter) (engine.Plan, error) { func readPlan(path string, dec config.Decrypter, enc config.Encrypter) (deploy.Plan, error) {
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -165,7 +165,7 @@ func newDeployment(ctx *Context, info *deploymentContext, opts deploymentOptions
var depl *deploy.Deployment var depl *deploy.Deployment
if !opts.isImport { if !opts.isImport {
depl, err = deploy.NewDeployment( depl, err = deploy.NewDeployment(
plugctx, target, target.Snapshot, source, localPolicyPackPaths, dryRun, ctx.BackendClient) plugctx, target, target.Snapshot, opts.Plan, source, localPolicyPackPaths, dryRun, ctx.BackendClient)
} else { } else {
_, defaultProviderVersions, pluginErr := installPlugins(proj, pwd, main, target, plugctx, _, defaultProviderVersions, pluginErr := installPlugins(proj, pwd, main, target, plugctx,
false /*returnInstallErrors*/) false /*returnInstallErrors*/)
@ -216,12 +216,12 @@ type runActions interface {
// run executes the deployment. It is primarily responsible for handling cancellation. // run executes the deployment. It is primarily responsible for handling cancellation.
func (deployment *deployment) run(cancelCtx *Context, actions runActions, policyPacks map[string]string, func (deployment *deployment) run(cancelCtx *Context, actions runActions, policyPacks map[string]string,
preview bool) (ResourceChanges, result.Result) { preview bool) (deploy.Plan, ResourceChanges, result.Result) {
// Change into the plugin context's working directory. // Change into the plugin context's working directory.
chdir, err := fsutil.Chdir(deployment.Plugctx.Pwd) chdir, err := fsutil.Chdir(deployment.Plugctx.Pwd)
if err != nil { if err != nil {
return nil, result.FromError(err) return nil, nil, result.FromError(err)
} }
defer chdir() defer chdir()
@ -240,6 +240,7 @@ func (deployment *deployment) run(cancelCtx *Context, actions runActions, policy
start := time.Now() start := time.Now()
done := make(chan bool) done := make(chan bool)
var newPlan deploy.Plan
var walkResult result.Result var walkResult result.Result
go func() { go func() {
opts := deploy.Options{ opts := deploy.Options{
@ -257,7 +258,7 @@ func (deployment *deployment) run(cancelCtx *Context, actions runActions, policy
DisableResourceReferences: deployment.Options.DisableResourceReferences, DisableResourceReferences: deployment.Options.DisableResourceReferences,
DisableOutputValues: deployment.Options.DisableOutputValues, DisableOutputValues: deployment.Options.DisableOutputValues,
} }
walkResult = deployment.Deployment.Execute(ctx, opts, preview) newPlan, walkResult = deployment.Deployment.Execute(ctx, opts, preview)
close(done) close(done)
}() }()
@ -288,7 +289,7 @@ func (deployment *deployment) run(cancelCtx *Context, actions runActions, policy
// Emit a summary event. // Emit a summary event.
deployment.Options.Events.summaryEvent(preview, actions.MaybeCorrupt(), duration, changes, policyPacks) deployment.Options.Events.summaryEvent(preview, actions.MaybeCorrupt(), duration, changes, policyPacks)
return changes, res return newPlan, changes, res
} }
func (deployment *deployment) Close() error { func (deployment *deployment) Close() error {

View file

@ -23,7 +23,7 @@ import (
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace" "github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
) )
func Destroy(u UpdateInfo, ctx *Context, opts UpdateOptions, dryRun bool) (Plan, ResourceChanges, result.Result) { func Destroy(u UpdateInfo, ctx *Context, opts UpdateOptions, dryRun bool) (deploy.Plan, ResourceChanges, result.Result) {
contract.Require(u != nil, "u") contract.Require(u != nil, "u")
contract.Require(ctx != nil, "ctx") contract.Require(ctx != nil, "ctx")

View file

@ -21,7 +21,7 @@ import (
) )
func Import(u UpdateInfo, ctx *Context, opts UpdateOptions, imports []deploy.Import, func Import(u UpdateInfo, ctx *Context, opts UpdateOptions, imports []deploy.Import,
dryRun bool) (Plan, ResourceChanges, result.Result) { dryRun bool) (deploy.Plan, ResourceChanges, result.Result) {
contract.Require(u != nil, "u") contract.Require(u != nil, "u")
contract.Require(ctx != nil, "ctx") contract.Require(ctx != nil, "ctx")

View file

@ -23,7 +23,7 @@ import (
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace" "github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
) )
func Refresh(u UpdateInfo, ctx *Context, opts UpdateOptions, dryRun bool) (Plan, ResourceChanges, result.Result) { func Refresh(u UpdateInfo, ctx *Context, opts UpdateOptions, dryRun bool) (deploy.Plan, ResourceChanges, result.Result) {
contract.Require(u != nil, "u") contract.Require(u != nil, "u")
contract.Require(ctx != nil, "ctx") contract.Require(ctx != nil, "ctx")

View file

@ -147,7 +147,7 @@ type UpdateOptions struct {
Host plugin.Host Host plugin.Host
// The plan to use for the update, if any. // The plan to use for the update, if any.
Plan Plan Plan deploy.Plan
} }
// ResourceChanges contains the aggregate resource changes by operation type. // ResourceChanges contains the aggregate resource changes by operation type.
@ -167,10 +167,7 @@ func (changes ResourceChanges) HasChanges() bool {
return c > 0 return c > 0
} }
// Plan records planned resource changes. func Update(u UpdateInfo, ctx *Context, opts UpdateOptions, dryRun bool) (deploy.Plan, ResourceChanges, result.Result) {
type Plan map[resource.URN]*deploy.ResourcePlan
func Update(u UpdateInfo, ctx *Context, opts UpdateOptions, dryRun bool) (Plan, ResourceChanges, result.Result) {
contract.Require(u != nil, "update") contract.Require(u != nil, "update")
contract.Require(ctx != nil, "ctx") contract.Require(ctx != nil, "ctx")
@ -425,7 +422,7 @@ func newUpdateSource(
} }
func update(ctx *Context, info *deploymentContext, opts deploymentOptions, func update(ctx *Context, info *deploymentContext, opts deploymentOptions,
preview bool) (Plan, ResourceChanges, result.Result) { preview bool) (deploy.Plan, ResourceChanges, result.Result) {
// Refresh and Import do not execute Policy Packs. // Refresh and Import do not execute Policy Packs.
policies := map[string]string{} policies := map[string]string{}

View file

@ -153,7 +153,7 @@ type Deployment struct {
target *Target // the deployment target. target *Target // the deployment target.
prev *Snapshot // the old resource snapshot for comparison. prev *Snapshot // the old resource snapshot for comparison.
olds map[resource.URN]*resource.State // a map of all old resources. olds map[resource.URN]*resource.State // a map of all old resources.
resourcePlans map[resource.URN]*ResourcePlan // a map of all planned resource changes, if any. plan Plan // a map of all planned resource changes, if any.
imports []Import // resources to import, if this is an import deployment. imports []Import // resources to import, if this is an import deployment.
isImport bool // true if this is an import deployment. isImport bool // true if this is an import deployment.
schemaLoader schema.Loader // the schema cache for this deployment, if any. schemaLoader schema.Loader // the schema cache for this deployment, if any.
@ -164,7 +164,7 @@ type Deployment struct {
providers *providers.Registry // the provider registry for this deployment. providers *providers.Registry // the provider registry for this deployment.
goals *goalMap // the set of resource goals generated by the deployment. goals *goalMap // the set of resource goals generated by the deployment.
news *resourceMap // the set of new resources generated by the deployment news *resourceMap // the set of new resources generated by the deployment
newResourcePlans map[resource.URN]*ResourcePlan // the set of new resource plans. newPlan map[resource.URN]*ResourcePlan // the set of new resource plans.
} }
// addDefaultProviders adds any necessary default provider definitions and references to the given snapshot. Version // addDefaultProviders adds any necessary default provider definitions and references to the given snapshot. Version
@ -301,7 +301,7 @@ func buildResourceMap(prev *Snapshot, preview bool) ([]*resource.State, map[reso
// //
// Note that a deployment uses internal concurrency and parallelism in various ways, so it must be closed if for some // Note that a deployment uses internal concurrency and parallelism in various ways, so it must be closed if for some
// reason it isn't carried out to its final conclusion. This will result in cancellation and reclamation of resources. // reason it isn't carried out to its final conclusion. This will result in cancellation and reclamation of resources.
func NewDeployment(ctx *plugin.Context, target *Target, prev *Snapshot, plans map[resource.URN]*ResourcePlan, source Source, func NewDeployment(ctx *plugin.Context, target *Target, prev *Snapshot, plan Plan, source Source,
localPolicyPackPaths []string, preview bool, backendClient BackendClient) (*Deployment, error) { localPolicyPackPaths []string, preview bool, backendClient BackendClient) (*Deployment, error) {
contract.Assert(ctx != nil) contract.Assert(ctx != nil)
@ -345,7 +345,7 @@ func NewDeployment(ctx *plugin.Context, target *Target, prev *Snapshot, plans ma
ctx: ctx, ctx: ctx,
target: target, target: target,
prev: prev, prev: prev,
resourcePlans: plans, plan: plan,
olds: olds, olds: olds,
source: source, source: source,
localPolicyPackPaths: localPolicyPackPaths, localPolicyPackPaths: localPolicyPackPaths,
@ -354,7 +354,7 @@ func NewDeployment(ctx *plugin.Context, target *Target, prev *Snapshot, plans ma
providers: reg, providers: reg,
goals: newGoals, goals: newGoals,
news: newResources, news: newResources,
newResourcePlans: map[resource.URN]*ResourcePlan{}, newPlan: Plan{},
}, nil }, nil
} }
@ -409,7 +409,7 @@ func (d *Deployment) generateEventURN(event SourceEvent) resource.URN {
} }
// Execute executes a deployment to completion, using the given cancellation context and running a preview or update. // Execute executes a deployment to completion, using the given cancellation context and running a preview or update.
func (d *Deployment) Execute(ctx context.Context, opts Options, preview bool) (map[resource.URN]*ResourcePlan, result.Result) { func (d *Deployment) Execute(ctx context.Context, opts Options, preview bool) (Plan, result.Result) {
deploymentExec := &deploymentExecutor{deployment: d} deploymentExec := &deploymentExecutor{deployment: d}
return deploymentExec.Execute(ctx, opts, preview) return deploymentExec.Execute(ctx, opts, preview)
} }

View file

@ -114,7 +114,7 @@ func (ex *deploymentExecutor) reportError(urn resource.URN, err error) {
// Execute executes a deployment to completion, using the given cancellation context and running a preview // Execute executes a deployment to completion, using the given cancellation context and running a preview
// or update. // or update.
func (ex *deploymentExecutor) Execute(callerCtx context.Context, opts Options, preview bool) (map[resource.URN]*ResourcePlan, result.Result) { func (ex *deploymentExecutor) Execute(callerCtx context.Context, opts Options, preview bool) (Plan, result.Result) {
// Set up a goroutine that will signal cancellation to the deployment's plugins if the caller context is cancelled. // Set up a goroutine that will signal cancellation to the deployment's plugins if the caller context is cancelled.
// We do not hang this off of the context we create below because we do not want the failure of a single step to // We do not hang this off of the context we create below because we do not want the failure of a single step to
// cause other steps to fail. // cause other steps to fail.
@ -295,7 +295,7 @@ func (ex *deploymentExecutor) Execute(callerCtx context.Context, opts Options, p
return nil, result.Bail() return nil, result.Bail()
} }
return pe.plan.newResourcePlans, res return ex.deployment.newPlan, res
} }
func (ex *deploymentExecutor) performDeletes( func (ex *deploymentExecutor) performDeletes(
@ -433,7 +433,7 @@ func (ex *deploymentExecutor) retirePendingDeletes(callerCtx context.Context, op
} }
// import imports a list of resources into a stack. // import imports a list of resources into a stack.
func (ex *deploymentExecutor) importResources(callerCtx context.Context, opts Options, preview bool) (map[resource.URN]*ResourcePlan, result.Result) { func (ex *deploymentExecutor) importResources(callerCtx context.Context, opts Options, preview bool) (Plan, result.Result) {
if len(ex.deployment.imports) == 0 { if len(ex.deployment.imports) == 0 {
return nil, nil return nil, nil
} }
@ -466,7 +466,7 @@ func (ex *deploymentExecutor) importResources(callerCtx context.Context, opts Op
ex.reportExecResult("canceled", preview) ex.reportExecResult("canceled", preview)
return nil, result.Bail() return nil, result.Bail()
} }
return pe.plan.newResourcePlans, nil return ex.deployment.newPlan, nil
} }
// refresh refreshes the state of the base checkpoint file for the current deployment in memory. // refresh refreshes the state of the base checkpoint file for the current deployment in memory.

View file

@ -10,6 +10,14 @@ import (
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract" "github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
) )
// A Plan is a mapping from URNs to ResourcePlans. The plan defines an expected set of resources and the expected
// inputs and operations for each. The inputs and operations are treated as constraints, and may allow for inputs or
// operations that do not exactly match those recorded in the plan. In the case of inputs, unknown values in the plan
// accept any value (including no value) as valid. For operations, a same step is allowed in place of an update or
// a replace step, and an update is allowed in place of a replace step. All resource options are required to match
// exactly.
type Plan map[resource.URN]*ResourcePlan
// A ResourcePlan represents the planned goal state and resource operations for a single resource. The operations are // A ResourcePlan represents the planned goal state and resource operations for a single resource. The operations are
// ordered. // ordered.
type ResourcePlan struct { type ResourcePlan struct {

View file

@ -158,7 +158,7 @@ func (sg *stepGenerator) GenerateSteps(event RegisterResourceEvent) ([]Step, res
// Check each proposed step against the relevant resource plan, if any, and generate any output resource plans. // Check each proposed step against the relevant resource plan, if any, and generate any output resource plans.
for _, s := range steps { for _, s := range steps {
if resourcePlan, ok := sg.plan.resourcePlans[s.URN()]; ok { if resourcePlan, ok := sg.deployment.plan[s.URN()]; ok {
if len(resourcePlan.Ops) == 0 { if len(resourcePlan.Ops) == 0 {
return nil, result.Errorf("%v is not allowed by the plan: no more steps were expected for this resource", s.Op()) return nil, result.Errorf("%v is not allowed by the plan: no more steps were expected for this resource", s.Op())
} }
@ -170,12 +170,12 @@ func (sg *stepGenerator) GenerateSteps(event RegisterResourceEvent) ([]Step, res
resourcePlan.Ops = resourcePlan.Ops[1:] resourcePlan.Ops = resourcePlan.Ops[1:]
} }
resourcePlan, ok := sg.plan.newResourcePlans[s.URN()] resourcePlan, ok := sg.deployment.newPlan[s.URN()]
if !ok { if !ok {
// TODO(pdg-plan): using the program inputs means that non-determinism could sneak in as part of default // TODO(pdg-plan): using the program inputs means that non-determinism could sneak in as part of default
// application. However, it is necessary in the face of computed inputs. // application. However, it is necessary in the face of computed inputs.
resourcePlan = &ResourcePlan{Goal: event.Goal()} resourcePlan = &ResourcePlan{Goal: event.Goal()}
sg.plan.newResourcePlans[s.URN()] = resourcePlan sg.deployment.newPlan[s.URN()] = resourcePlan
} }
resourcePlan.Ops = append(resourcePlan.Ops, s.Op()) resourcePlan.Ops = append(resourcePlan.Ops, s.Op())
} }
@ -237,8 +237,8 @@ func (sg *stepGenerator) generateSteps(event RegisterResourceEvent) ([]Step, res
sg.urns[urn] = true sg.urns[urn] = true
// If there is a plan for this resource, validate that the program goal conforms to the plan. // If there is a plan for this resource, validate that the program goal conforms to the plan.
if len(sg.plan.resourcePlans) != 0 { if len(sg.deployment.plan) != 0 {
resourcePlan, ok := sg.plan.resourcePlans[urn] resourcePlan, ok := sg.deployment.plan[urn]
if !ok { if !ok {
return nil, result.Errorf("resource not found in plan") return nil, result.Errorf("resource not found in plan")
} }

View file

@ -42,7 +42,7 @@ func SerializeResourcePlan(plan *deploy.ResourcePlan, enc config.Encrypter, show
}, nil }, nil
} }
func SerializePlan(plan map[resource.URN]*deploy.ResourcePlan, enc config.Encrypter, showSecrets bool) (apitype.DeploymentPlanV1, error) { func SerializePlan(plan deploy.Plan, enc config.Encrypter, showSecrets bool) (apitype.DeploymentPlanV1, error) {
resourcePlans := map[resource.URN]apitype.ResourcePlanV1{} resourcePlans := map[resource.URN]apitype.ResourcePlanV1{}
for urn, plan := range plan { for urn, plan := range plan {
serializedPlan, err := SerializeResourcePlan(plan, enc, showSecrets) serializedPlan, err := SerializeResourcePlan(plan, enc, showSecrets)
@ -89,14 +89,14 @@ func DeserializeResourcePlan(plan apitype.ResourcePlanV1, dec config.Decrypter,
}, nil }, nil
} }
func DeserializePlan(plan apitype.DeploymentPlanV1, dec config.Decrypter, enc config.Encrypter) (map[resource.URN]*deploy.ResourcePlan, error) { func DeserializePlan(plan apitype.DeploymentPlanV1, dec config.Decrypter, enc config.Encrypter) (deploy.Plan, error) {
resourcePlans := map[resource.URN]*deploy.ResourcePlan{} deserializedPlan := deploy.Plan{}
for urn, plan := range plan.ResourcePlans { for urn, resourcePlan := range plan.ResourcePlans {
deserializedPlan, err := DeserializeResourcePlan(plan, dec, enc) deserializedResourcePlan, err := DeserializeResourcePlan(resourcePlan, dec, enc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resourcePlans[urn] = deserializedPlan deserializedPlan[urn] = deserializedResourcePlan
} }
return resourcePlans, nil return deserializedPlan, nil
} }