pulumi/pkg/engine/deployment.go

415 lines
14 KiB
Go
Raw Permalink Normal View History

2021-09-21 17:00:44 +00:00
// Copyright 2016-2021, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package engine
import (
"context"
"errors"
"fmt"
"time"
"github.com/opentracing/opentracing-go"
2022-11-01 15:15:09 +00:00
"google.golang.org/grpc"
"github.com/pulumi/pulumi/pkg/v3/display"
"github.com/pulumi/pulumi/pkg/v3/resource/deploy"
"github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers"
2022-11-01 15:15:09 +00:00
interceptors "github.com/pulumi/pulumi/pkg/v3/util/rpcdebug"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/env"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/config"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
ctrl-c should cause Pulumi to call Cancel operation on providers (#14057) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description Fixes #14054 This PR fixes a problem that the engine cannot forward a cancellation signal to the provider, because the plugin context is already closed. An [earlier commit](https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114) made the plugin context be closed too eagerly, with the intent of cancelling plugin installation. This PR attempts to decouple the cancellation of plugin installation from the lifecycle of the plugin context, so that plugin installation may be cancelled during the cancelation phase as opposed to the termination phase. Then, it closes the plugin context in termination phase. There's an existing test case in the engine lifecycle tests called `TestProviderCancellation`, but it didn't catch the problem because it uses a fake plugin host that behaves differently after being closed. The issue was fixed in https://github.com/pulumi/pulumi/pull/14063 and the test was temporarily disabled. This PR re-enables the test case. A new test case `TestSourceFuncCancellation` is added to test cancellation of the source func (where plugin installation happens, see [update.go](https://github.com/pulumi/pulumi/pull/14057/files#diff-7d2ca3e83a05073b332435271496050e28466b4f7af8c0c91bbc77947a75a3a2R378)), as this was the original motivation of https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] ~Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version~ <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-09-29 22:12:35 +00:00
"github.com/pulumi/pulumi/sdk/v3/go/common/util/logging"
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
)
const clientRuntimeName = "client"
// ProjectInfoContext returns information about the current project, including its pwd, main, and plugin context.
func ProjectInfoContext(projinfo *Projinfo, host plugin.Host,
diag, statusDiag diag.Sink, disableProviderPreview bool,
tracingSpan opentracing.Span, config map[config.Key]string,
all: Reformat with gofumpt Per team discussion, switching to gofumpt. [gofumpt][1] is an alternative, stricter alternative to gofmt. It addresses other stylistic concerns that gofmt doesn't yet cover. [1]: https://github.com/mvdan/gofumpt See the full list of [Added rules][2], but it includes: - Dropping empty lines around function bodies - Dropping unnecessary variable grouping when there's only one variable - Ensuring an empty line between multi-line functions - simplification (`-s` in gofmt) is always enabled - Ensuring multi-line function signatures end with `) {` on a separate line. [2]: https://github.com/mvdan/gofumpt#Added-rules gofumpt is stricter, but there's no lock-in. All gofumpt output is valid gofmt output, so if we decide we don't like it, it's easy to switch back without any code changes. gofumpt support is built into the tooling we use for development so this won't change development workflows. - golangci-lint includes a gofumpt check (enabled in this PR) - gopls, the LSP for Go, includes a gofumpt option (see [installation instrutions][3]) [3]: https://github.com/mvdan/gofumpt#installation This change was generated by running: ```bash gofumpt -w $(rg --files -g '*.go' | rg -v testdata | rg -v compilation_error) ``` The following files were manually tweaked afterwards: - pkg/cmd/pulumi/stack_change_secrets_provider.go: one of the lines overflowed and had comments in an inconvenient place - pkg/cmd/pulumi/destroy.go: `var x T = y` where `T` wasn't necessary - pkg/cmd/pulumi/policy_new.go: long line because of error message - pkg/backend/snapshot_test.go: long line trying to assign three variables in the same assignment I have included mention of gofumpt in the CONTRIBUTING.md.
2023-03-03 16:36:39 +00:00
) (string, string, *plugin.Context, error) {
contract.Requiref(projinfo != nil, "projinfo", "must not be nil")
// If the package contains an override for the main entrypoint, use it.
pwd, main, err := projinfo.GetPwdMain()
if err != nil {
return "", "", nil, err
}
// Create a context for plugins.
ctx, err := plugin.NewContextWithRoot(diag, statusDiag, host, pwd, projinfo.Root,
projinfo.Proj.Runtime.Options(), disableProviderPreview, tracingSpan, projinfo.Proj.Plugins, config)
if err != nil {
return "", "", nil, err
}
if logFile := env.DebugGRPC.Value(); logFile != "" {
2022-11-01 15:15:09 +00:00
di, err := interceptors.NewDebugInterceptor(interceptors.DebugInterceptorOptions{
LogFile: logFile,
Mutex: ctx.DebugTraceMutex,
})
if err != nil {
return "", "", nil, err
}
ctx.DialOptions = func(metadata interface{}) []grpc.DialOption {
return di.DialOptions(interceptors.LogOptions{
Metadata: metadata,
})
}
}
// If the project wants to connect to an existing language runtime, do so now.
if projinfo.Proj.Runtime.Name() == clientRuntimeName {
addressValue, ok := projinfo.Proj.Runtime.Options()["address"]
if !ok {
return "", "", nil, errors.New("missing address of language runtime service")
}
address, ok := addressValue.(string)
if !ok {
return "", "", nil, errors.New("address of language runtime service must be a string")
}
host, err := connectToLanguageRuntime(ctx, address)
if err != nil {
return "", "", nil, err
}
ctx.Host = host
}
return pwd, main, ctx, nil
}
// newDeploymentContext creates a context for a subsequent deployment. Callers must call Close on the context after the
// associated deployment completes.
func newDeploymentContext(u UpdateInfo, opName string, parentSpan opentracing.SpanContext) (*deploymentContext, error) {
contract.Requiref(u != nil, "u", "must not be nil")
// Create a root span for the operation
opts := []opentracing.StartSpanOption{}
if opName != "" {
opts = append(opts, opentracing.Tag{Key: "operation", Value: opName})
}
if parentSpan != nil {
opts = append(opts, opentracing.ChildOf(parentSpan))
}
tracingSpan := opentracing.StartSpan("pulumi-plan", opts...)
return &deploymentContext{
Update: u,
TracingSpan: tracingSpan,
}, nil
}
type deploymentContext struct {
Update UpdateInfo // The update being processed.
TracingSpan opentracing.Span // An OpenTracing span to parent deployment operations within.
}
func (ctx *deploymentContext) Close() {
ctx.TracingSpan.Finish()
}
// deploymentOptions includes a full suite of options for performing a deployment.
type deploymentOptions struct {
UpdateOptions
// SourceFunc is a factory that returns an EvalSource to use during deployment. This is the thing that
// creates resources to compare against the current checkpoint state (e.g., by evaluating a program, etc).
SourceFunc deploymentSourceFunc
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
// true if we should print the DOT file for this deployment.
DOT bool
// the channel to write events from the engine to.
Events eventEmitter
// the sink to use for diag'ing.
Diag diag.Sink
// the sink to use for diag'ing status messages.
StatusDiag diag.Sink
// True if this is an import operation.
isImport bool
// Resources to import, if this is an import.
imports []deploy.Import
// true if this deployment is (only) a refresh operation. This should not be
// confused with UpdateOptions.Refresh, which will be true whenever a refresh
// is happening as part of an operation (e.g. `up --refresh`).
isRefresh bool
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
// true if this deployment is a dry run, such as a preview action or a preview
// operation preceding e.g. a refresh or destroy.
DryRun bool
}
// deploymentSourceFunc is a callback that will be used to prepare for, and evaluate, the "new" state for a stack.
type deploymentSourceFunc func(
ctrl-c should cause Pulumi to call Cancel operation on providers (#14057) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description Fixes #14054 This PR fixes a problem that the engine cannot forward a cancellation signal to the provider, because the plugin context is already closed. An [earlier commit](https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114) made the plugin context be closed too eagerly, with the intent of cancelling plugin installation. This PR attempts to decouple the cancellation of plugin installation from the lifecycle of the plugin context, so that plugin installation may be cancelled during the cancelation phase as opposed to the termination phase. Then, it closes the plugin context in termination phase. There's an existing test case in the engine lifecycle tests called `TestProviderCancellation`, but it didn't catch the problem because it uses a fake plugin host that behaves differently after being closed. The issue was fixed in https://github.com/pulumi/pulumi/pull/14063 and the test was temporarily disabled. This PR re-enables the test case. A new test case `TestSourceFuncCancellation` is added to test cancellation of the source func (where plugin installation happens, see [update.go](https://github.com/pulumi/pulumi/pull/14057/files#diff-7d2ca3e83a05073b332435271496050e28466b4f7af8c0c91bbc77947a75a3a2R378)), as this was the original motivation of https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] ~Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version~ <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-09-29 22:12:35 +00:00
ctx context.Context,
client deploy.BackendClient, opts *deploymentOptions, proj *workspace.Project, pwd, main, projectRoot string,
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
target *deploy.Target, plugctx *plugin.Context) (deploy.Source, error)
// newDeployment creates a new deployment with the given context and options.
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
func newDeployment(
ctx *Context,
info *deploymentContext,
actions runActions,
opts *deploymentOptions,
all: Reformat with gofumpt Per team discussion, switching to gofumpt. [gofumpt][1] is an alternative, stricter alternative to gofmt. It addresses other stylistic concerns that gofmt doesn't yet cover. [1]: https://github.com/mvdan/gofumpt See the full list of [Added rules][2], but it includes: - Dropping empty lines around function bodies - Dropping unnecessary variable grouping when there's only one variable - Ensuring an empty line between multi-line functions - simplification (`-s` in gofmt) is always enabled - Ensuring multi-line function signatures end with `) {` on a separate line. [2]: https://github.com/mvdan/gofumpt#Added-rules gofumpt is stricter, but there's no lock-in. All gofumpt output is valid gofmt output, so if we decide we don't like it, it's easy to switch back without any code changes. gofumpt support is built into the tooling we use for development so this won't change development workflows. - golangci-lint includes a gofumpt check (enabled in this PR) - gopls, the LSP for Go, includes a gofumpt option (see [installation instrutions][3]) [3]: https://github.com/mvdan/gofumpt#installation This change was generated by running: ```bash gofumpt -w $(rg --files -g '*.go' | rg -v testdata | rg -v compilation_error) ``` The following files were manually tweaked afterwards: - pkg/cmd/pulumi/stack_change_secrets_provider.go: one of the lines overflowed and had comments in an inconvenient place - pkg/cmd/pulumi/destroy.go: `var x T = y` where `T` wasn't necessary - pkg/cmd/pulumi/policy_new.go: long line because of error message - pkg/backend/snapshot_test.go: long line trying to assign three variables in the same assignment I have included mention of gofumpt in the CONTRIBUTING.md.
2023-03-03 16:36:39 +00:00
) (*deployment, error) {
contract.Assertf(info != nil, "a deployment context must be provided")
contract.Assertf(info.Update != nil, "update info cannot be nil")
contract.Assertf(opts.SourceFunc != nil, "a source factory must be provided")
// First, load the package metadata and the deployment target in preparation for executing the package's program
// and creating resources. This includes fetching its pwd and main overrides.
proj, target := info.Update.GetProject(), info.Update.GetTarget()
contract.Assertf(proj != nil, "update project cannot be nil")
contract.Assertf(target != nil, "update target cannot be nil")
projinfo := &Projinfo{Proj: proj, Root: info.Update.GetRoot()}
// Decrypt the configuration.
config, err := target.Config.Decrypt(target.Decrypter)
if err != nil {
return nil, fmt.Errorf("failed to decrypt config: %w", err)
}
pwd, main, plugctx, err := ProjectInfoContext(projinfo, opts.Host,
opts.Diag, opts.StatusDiag, opts.DisableProviderPreview, info.TracingSpan, config)
if err != nil {
return nil, err
}
ctrl-c should cause Pulumi to call Cancel operation on providers (#14057) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description Fixes #14054 This PR fixes a problem that the engine cannot forward a cancellation signal to the provider, because the plugin context is already closed. An [earlier commit](https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114) made the plugin context be closed too eagerly, with the intent of cancelling plugin installation. This PR attempts to decouple the cancellation of plugin installation from the lifecycle of the plugin context, so that plugin installation may be cancelled during the cancelation phase as opposed to the termination phase. Then, it closes the plugin context in termination phase. There's an existing test case in the engine lifecycle tests called `TestProviderCancellation`, but it didn't catch the problem because it uses a fake plugin host that behaves differently after being closed. The issue was fixed in https://github.com/pulumi/pulumi/pull/14063 and the test was temporarily disabled. This PR re-enables the test case. A new test case `TestSourceFuncCancellation` is added to test cancellation of the source func (where plugin installation happens, see [update.go](https://github.com/pulumi/pulumi/pull/14057/files#diff-7d2ca3e83a05073b332435271496050e28466b4f7af8c0c91bbc77947a75a3a2R378)), as this was the original motivation of https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] ~Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version~ <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-09-29 22:12:35 +00:00
// Keep the plugin context open until the context is terminated, to allow for graceful provider cancellation.
plugctx = plugctx.WithCancelChannel(ctx.Cancel.Terminated())
// Set up a goroutine that will signal cancellation to the source if the caller context
// is cancelled.
cancelCtx, cancelFunc := context.WithCancel(context.Background())
go func() {
<-ctx.Cancel.Canceled()
logging.V(7).Infof("engine.newDeployment(...): received cancellation signal")
cancelFunc()
}()
// Now create the state source. This may issue an error if it can't create the source. This entails,
// for example, loading any plugins which will be required to execute a program, among other things.
ctrl-c should cause Pulumi to call Cancel operation on providers (#14057) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description Fixes #14054 This PR fixes a problem that the engine cannot forward a cancellation signal to the provider, because the plugin context is already closed. An [earlier commit](https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114) made the plugin context be closed too eagerly, with the intent of cancelling plugin installation. This PR attempts to decouple the cancellation of plugin installation from the lifecycle of the plugin context, so that plugin installation may be cancelled during the cancelation phase as opposed to the termination phase. Then, it closes the plugin context in termination phase. There's an existing test case in the engine lifecycle tests called `TestProviderCancellation`, but it didn't catch the problem because it uses a fake plugin host that behaves differently after being closed. The issue was fixed in https://github.com/pulumi/pulumi/pull/14063 and the test was temporarily disabled. This PR re-enables the test case. A new test case `TestSourceFuncCancellation` is added to test cancellation of the source func (where plugin installation happens, see [update.go](https://github.com/pulumi/pulumi/pull/14057/files#diff-7d2ca3e83a05073b332435271496050e28466b4f7af8c0c91bbc77947a75a3a2R378)), as this was the original motivation of https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] ~Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version~ <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-09-29 22:12:35 +00:00
source, err := opts.SourceFunc(
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
cancelCtx, ctx.BackendClient, opts, proj, pwd, main, projinfo.Root, target, plugctx)
if err != nil {
contract.IgnoreClose(plugctx)
return nil, err
}
localPolicyPackPaths := ConvertLocalPolicyPacksToPaths(opts.LocalPolicyPacks)
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
deplOpts := &deploy.Options{
DryRun: opts.DryRun,
Parallel: opts.Parallel,
Refresh: opts.Refresh,
RefreshOnly: opts.isRefresh,
ReplaceTargets: opts.ReplaceTargets,
Targets: opts.Targets,
TargetDependents: opts.TargetDependents,
UseLegacyDiff: opts.UseLegacyDiff,
Change `pulumi refresh` to report diff relative to desired state instead of relative to only output changes (#16146) Presently, the behaviour of diffing during refresh steps is incomplete, returning only an "output diff" that presents the changes in outputs. This commit changes refresh steps so that: * they compute a diff similar to the one that would be computed if a `preview` were run immediately after the refresh, which is more typically what users expect and want; and * `IgnoreChanges` resource options are respected when performing the new desired-state diffs, so that property additions or changes reported by a refresh can be ignored. In particular, `IgnoreChanges` can now be used to acknowledge that part or all of a resource may change in the provider, but the user is OK with this and doesn't want to be notified about it during a refresh. Importantly, this means that the diff won't be reported, but also that the changes won't be applied to state. The implementation covers the following: * A diff is computed using the inputs from the program and then inverting the result, since in the case of a refresh the diff is being driven by the provider side and not the program. This doesn't change what is stored back into the state, but it does produce a diff that is more aligned with the "true changes to the desired state". * `IgnoreChanges` resource options are now stored in state, so that this information can be used in refresh operations that do not have access to/run the program. * In the context of a refresh operation, `IgnoreChanges` applies to *both* input and output properties. This differs from the behaviour of a normal update operation, where `IgnoreChanges` only considers input properties. * The special `"*"` value for `IgnoreChanges` can be used to ignore all properties. It _also_ ignores the case where the resource cannot be found in the provider, and instead keeps the resource intact in state with its existing input and output properties. Because the program is not run for refresh operations, `IgnoreChanges` options must be applied separately before a refresh takes place. This can be accomplished using e.g. a `pulumi up` that applies the options prior to a refresh. We should investigate perhaps providing a `pulumi state set ...`-like CLI to make these sorts of changes directly to a state. For use cases relying on the legacy refresh diff provider, the `PULUMI_USE_LEGACY_REFRESH_DIFF` environment variable can be set, which will disable desired-state diff computation. We only need to perform checks in `RefreshStep.{ResultOp,Apply}`, since downstream code will work correctly based on the presence or absence of a `DetailedDiff` in the step. ### Notes - https://github.com/pulumi/pulumi/issues/16144 affects some of these cases - though its technically orthogonal - https://github.com/pulumi/pulumi/issues/11279 is another technically orthogonal issue that many providers (at least TFBridge ones) - do not report back changes to input properties on Read when the input property (or property path) was missing on the inputs. This is again technically orthogonal - but leads to cases that appear "wrong" in terms of what is stored back into the state still - though the same as before this change. - Azure Native doesn't seem to handle `ignoreChanges` passed to Diff, so the ability to ignore changes on refresh doesn't currently work for Azure Native. ### Fixes * Fixes #16072 * Fixes #16278 * Fixes #16334 * Not quite #12346, but likely replaces the need for that Co-authored-by: Will Jones <will@sacharissa.co.uk>
2024-06-12 16:17:05 +00:00
UseLegacyRefreshDiff: opts.UseLegacyRefreshDiff,
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
DisableResourceReferences: opts.DisableResourceReferences,
DisableOutputValues: opts.DisableOutputValues,
GeneratePlan: opts.UpdateOptions.GeneratePlan,
ContinueOnError: opts.ContinueOnError,
}
var depl *deploy.Deployment
if !opts.isImport {
depl, err = deploy.NewDeployment(
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
plugctx, deplOpts, actions, target, target.Snapshot, opts.Plan, source,
localPolicyPackPaths, ctx.BackendClient)
} else {
ctrl-c should cause Pulumi to call Cancel operation on providers (#14057) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description Fixes #14054 This PR fixes a problem that the engine cannot forward a cancellation signal to the provider, because the plugin context is already closed. An [earlier commit](https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114) made the plugin context be closed too eagerly, with the intent of cancelling plugin installation. This PR attempts to decouple the cancellation of plugin installation from the lifecycle of the plugin context, so that plugin installation may be cancelled during the cancelation phase as opposed to the termination phase. Then, it closes the plugin context in termination phase. There's an existing test case in the engine lifecycle tests called `TestProviderCancellation`, but it didn't catch the problem because it uses a fake plugin host that behaves differently after being closed. The issue was fixed in https://github.com/pulumi/pulumi/pull/14063 and the test was temporarily disabled. This PR re-enables the test case. A new test case `TestSourceFuncCancellation` is added to test cancellation of the source func (where plugin installation happens, see [update.go](https://github.com/pulumi/pulumi/pull/14057/files#diff-7d2ca3e83a05073b332435271496050e28466b4f7af8c0c91bbc77947a75a3a2R378)), as this was the original motivation of https://github.com/pulumi/pulumi/pull/9793/commits/a9ae602867834efc9821abd866ef388c1b051114. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] ~Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version~ <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-09-29 22:12:35 +00:00
_, defaultProviderInfo, pluginErr := installPlugins(cancelCtx, proj, pwd, main, target, plugctx,
false /*returnInstallErrors*/)
if pluginErr != nil {
return nil, pluginErr
}
for i := range opts.imports {
imp := &opts.imports[i]
Allow `import` to create empty component resources (#14467) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> Fixes https://github.com/pulumi/pulumi/issues/14444. This adds two new flags to the import file to signal that a resource is a component, and also if that is a remote (MLC) component. The import system will create empty resources for those import descriptions, but importantly they can then be used as parents for other resources in the import deployment. We need to know if it's a remote component to know if a provider should be looked up for it. We could probably get away with _just_ knowing if it's a component at import time and not doing any validation that the type token is well formed and the provider exists for MLCs. That makes import a little simpler for users (no need to set if it's remote or not) but pushes error cases downstream to when they actually try to `up` their program. It also means we can't lookup and fill in the default providers for these resources, resulting in a provider diff at `up` time. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-11-13 17:58:35 +00:00
if imp.Component {
if imp.ID != "" {
return nil, fmt.Errorf("import %s cannot specify an ID as it's a component", imp.Name)
}
}
Allow `import` to create empty component resources (#14467) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> Fixes https://github.com/pulumi/pulumi/issues/14444. This adds two new flags to the import file to signal that a resource is a component, and also if that is a remote (MLC) component. The import system will create empty resources for those import descriptions, but importantly they can then be used as parents for other resources in the import deployment. We need to know if it's a remote component to know if a provider should be looked up for it. We could probably get away with _just_ knowing if it's a component at import time and not doing any validation that the type token is well formed and the provider exists for MLCs. That makes import a little simpler for users (no need to set if it's remote or not) but pushes error cases downstream to when they actually try to `up` their program. It also means we can't lookup and fill in the default providers for these resources, resulting in a provider diff at `up` time. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-11-13 17:58:35 +00:00
if !imp.Component || imp.Remote {
_, err := tokens.ParseTypeToken(imp.Type.String())
if err != nil {
return nil, fmt.Errorf("import type %q is not a valid resource type token. "+
"Type tokens must be of the format <package>:<module>:<type> - "+
"refer to the import section of the provider resource documentation.", imp.Type.String())
}
}
if imp.Provider == "" && (!imp.Component || imp.Remote) {
if imp.Version == nil {
imp.Version = defaultProviderInfo[imp.Type.Package()].Version
}
if imp.PluginDownloadURL == "" {
imp.PluginDownloadURL = defaultProviderInfo[imp.Type.Package()].PluginDownloadURL
}
Pass provider checksums in requests and save to state (#13789) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> This extends the resource monitor interface with fields for plugin checksums (on top of the existing plugin version and download url fields). These fields are threaded through the engine and are persisted in resource state. The sent or saved data is then used when installing plugins to ensure that the checksums match what was recorded at the time the SDK was built. Similar to https://github.com/pulumi/pulumi/pull/13776 nothing is using this yet, but this lays the engine side plumbing for them. ## Checklist - [ ] I have run `make tidy` to update any new dependencies - [ ] I have run `make lint` to verify my code passes the lint check - [ ] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [x] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [x] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-09-11 15:54:07 +00:00
if imp.PluginChecksums == nil {
imp.PluginChecksums = defaultProviderInfo[imp.Type.Package()].Checksums
}
}
}
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
depl, err = deploy.NewImportDeployment(
plugctx, deplOpts, actions, target, proj.Name, opts.imports)
}
if err != nil {
contract.IgnoreClose(plugctx)
return nil, err
}
return &deployment{
Ctx: info,
Plugctx: plugctx,
Deployment: depl,
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
Actions: actions,
Options: opts,
}, nil
}
type deployment struct {
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
// deployment context information.
Ctx *deploymentContext
// the context containing plugins and their state.
Plugctx *plugin.Context
// the deployment created by this command.
Deployment *deploy.Deployment
// the actions to run during the deployment.
Actions runActions
// the options used while deploying.
Options *deploymentOptions
}
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
// runActions represents a set of actions to run as part of a deployment,
// including callbacks that will be used to emit events at various points in the
// deployment process.
type runActions interface {
deploy.Events
Changes() display.ResourceChanges
MaybeCorrupt() bool
}
// run executes the deployment. It is primarily responsible for handling cancellation.
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
func (deployment *deployment) run(cancelCtx *Context) (*deploy.Plan, display.ResourceChanges, error) {
// Create a new context for cancellation and tracing.
ctx, cancelFunc := context.WithCancel(context.Background())
// Inject our opentracing span into the context.
if deployment.Ctx.TracingSpan != nil {
ctx = opentracing.ContextWithSpan(ctx, deployment.Ctx.TracingSpan)
}
// Emit an appropriate prelude event.
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
deployment.Options.Events.preludeEvent(
deployment.Options.DryRun, deployment.Ctx.Update.GetTarget().Config)
// Execute the deployment.
start := time.Now()
done := make(chan bool)
Preview of update plans (#8448) * Implement resource plans in the engine * Plumb plans through the CLI. * Update wording * plan renderer * constraints * Renames * Update message * fixes for rebase breaks and diffs * WIP: outputs in plans * fix diff * fixup * Liniting and test fixing * Test and fix PropertyPath.String() * Fix colors * Fix cmdutil.PrintTable to handle non-simple strings * More tests * Readd test_plan.go * lint * Test expected deletes * Test expected delete * Test missing create * Fix test for missing creates * rm Paths() * property set shrink test * notes * More tests * Pop op before constraint check * Delete plan cmd, rename arguments to preview and up * Hide behind envvars * typo * Better constraint diffs * Adds/Deletes/Updates * Fix aliased * Check more constraints * fix test * revert stack changes * Resource sames test * Fix same resource test * Fix more tests * linting * Update pkg/cmd/pulumi/up.go Co-authored-by: Alex Mullans <a.mullans@pulumi.com> * Update pkg/cmd/pulumi/preview.go Co-authored-by: Alex Mullans <a.mullans@pulumi.com> * Auto refresh if using plans * Fix TestGetRefreshOption * Fix TestExplicitDeleteBeforeReplace * lint * More copying in tests because I do not trust myself to get mutation correct * Small preview plan test * Add TestPlannedUpdateChangedStack * Revert auto-refresh changes * Validate outputs don't change * omitempty * Add manifest to plan * Add proper Plan type * wip config work * Config and manifest serder * linting * Asset NoError * Actually check error * Fix clone * Test diag message * Start on more tests * Add String and GoString to Result I got fed up assert errors in tests that looked like: ``` Expected nil, but got: &result.simpleResult{err:(*errors.fundamental)(0xc0002fa5d0)} ``` It was very hard to work out at a glance what had gone wrong and I kept having to hook a debugger just to look at what the error was. With GoString these now print something like: ``` Expected nil, but got: &simpleResult{err: Unexpected diag message: <{%reset%}>resource violates plan: properties changed: -zed, -baz, -foo<{%reset%}> } ``` Which is much more ussful. * Add test error text * Fix reporting of unseen op errors * Fix unneeded deletes * Fix unexpected deletes * Fix up tests * Fix merge conflict * lint * Fix nil map error * Fix serialisation typo * Diff against old inputs * Diff against checked goal * Diff against empty for creates * Fix test * inputs not outputs * Seperate PlanDiff type * Add properties * Fix input diffs * Handle creates * lint * Add plan message * Clone plan for update preview * Save and serialise env vars in plans * lint * pretty print json * input output difference test * test alias * fix typo in for loop * Handle resource plans with nil goal * go mod tidy * typo * Auto use plans from up previews in experimental mode * Don't preview if we have plan * Don't run previews with plans now * fixing tests * Handle diffs and goals * Update copystructure * tests/go.sum * Revert mod changes * Add copystructure to tests/go.sum * includeUnknowns * go mod tidy * Make plans for imports * Remove unused function * Move code more locally * Handle nil in serialize * Handle empty output diffs * Add test for dropping computed values * Allow computed properties to become deletes * if out the generation of plans unless experimental mode is opt'd into * lint * typo * Revert back to plans not skipping previews, this is orthognal to --skip-preview * Trying to work out non-determinism * Remove notes.txt * Hacking with check idea * Pass checked inputs back to Check from plan file * Include resource urn in constraint error * Give much more informative errors when plans fail * lint * Update expected diag strings in tests * Remove unused code * Duplicate Diff and DeepEquals methods for plans * Add comment about check ops with failures * Fix CheckedInputs comment * OutputDiff doesn't need to be a pointer * Fix checks against computed * diffStringSets * lint * lint pkg * Use 4 space indent * Don't wrap Buffer in Writer * Mark flags hidden rather than disabled * Remove envvars from plans * Assert MarkHidden error * Add to changelog * Note plan/save-plan is experimental Co-authored-by: Pat Gavlin <pat@pulumi.com> Co-authored-by: Alex Mullans <a.mullans@pulumi.com>
2022-01-31 10:31:51 +00:00
var newPlan *deploy.Plan
var walkError error
go func() {
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
newPlan, walkError = deployment.Deployment.Execute(ctx)
close(done)
}()
// Asynchronously listen for cancellation, and deliver that signal to the deployment.
go func() {
select {
case <-cancelCtx.Cancel.Canceled():
// Cancel the deployment's execution context, so it begins to shut down.
cancelFunc()
case <-done:
return
}
}()
var err error
// Wait for the deployment to finish executing or for the user to terminate the run.
select {
case <-cancelCtx.Cancel.Terminated():
err = cancelCtx.Cancel.TerminateErr()
case <-done:
err = walkError
}
duration := time.Since(start)
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
changes := deployment.Actions.Changes()
// Refresh and Import do not execute Policy Packs.
policies := map[string]string{}
if !deployment.Options.isRefresh && !deployment.Options.isImport {
for _, p := range deployment.Options.RequiredPolicies {
policies[p.Name()] = p.Version()
}
for _, pack := range deployment.Options.LocalPolicyPacks {
packName := pack.NameForEvents()
policies[packName] = pack.Version
}
}
// Emit a summary event.
Clean up deployment options (#16357) # Description There are a number of parts of the deployment process that require context about and configuration for the operation being executed. For instance: * Source evaluation -- evaluating programs in order to emit resource registrations * Step generation -- processing resource registrations in order to generate steps (create this, update that, delete the other, etc.) * Step execution -- executing steps in order to action a deployment. Presently, these pieces all take some form of `Options` struct or pass explicit arguments. This is problematic for a couple of reasons: * It could be possible for different parts of the codebase to end up operating in different contexts/with different configurations, whether due to different values being passed explicitly or due to missed copying/instantiation. * Some parts need less context/configuration than others, but still accept full `Options`, making it hard to discern what information is actually necessary in any given part of the process. This commit attempts to clean things up by moving deployment options directly into the `Deployment` itself. Since step generation and execution already refer to a `Deployment`, they get a consistent view of the options for free. For source evaluation, we introduce an `EvalSourceOptions` struct for configuring just the options necessary there. At the top level, the engine configures a single set of options to flow through the deployment steps later on. As part of this work, a few other things have been changed: * Preview/dry-run parameters have been incorporated into options. This lets up lop off another argument and mitigate a bit of "boolean blindness". We don't appear to flip this flag within a deployment process (indeed, all options seem to be immutable) and so having it as a separate flag doesn't seem to buy us anything. * Several methods representing parts of the deployment process have lost arguments in favour of state that is already being carried on (or can be carried on) their receiver. For instance, `deployment.run` no longer takes actions or preview configuration. While doing so means that a `deployment` could be run multiple times with different actions/preview arguments, we don't currently exploit this fact anywhere, so moving this state to the point of construction both simplifies things considerably and reduces the possibility for error (e.g. passing different values of `preview` when instantiating a `deployment` and subsequently calling `run`). * Event handlers have been split out of the options object and attached to `Deployment` separately. This means we can talk about options at a higher level without having to `nil` out/worry about this field and mutate it correctly later on. * Options are no longer mutated during deployment. Presently there appears to be only one case of this -- when handling `ContinueOnError` in the presence of `IgnoreChanges` (e.g. when performing a refresh). This case has been refactored so that the mutation is no longer necessary. # Notes * This change is in preparation for #16146, where we'd like to add an environment variable to control behaviour and having a single unified `Options` struct would make it easier to pass this configuration down with introducing (more) global state into deployments. Indeed, this change should make it easier to factor global state into `Options` so that it can be controlled and tested more easily/is less susceptible to bugs, race conditions, etc. * I've tweaked/extended some comments while I'm here and have learned things the hard way (e.g. `Refresh` vs `isRefresh`). Feedback welcome on this if we'd rather not conflate. * This change does mean that if in future we wanted e.g. to be able to run a `Deployment` in multiple different ways with multiple sets of actions, we'd have to refactor. Pushing state to the point of object construction reduces the flexibility of the code. However, since we are not presently using that flexibility (nor is there an obvious [to my mind] use case in the near future), this seems like a good trade-off to guard against bugs/make it simpler to move that state around. * I've left some other review comments in the code around questions/changes that might be a bad idea; happy to receive feedback on it all though!
2024-06-11 13:37:57 +00:00
deployment.Options.Events.summaryEvent(
deployment.Options.DryRun, deployment.Actions.MaybeCorrupt(), duration, changes, policies)
return newPlan, changes, err
}
func (deployment *deployment) Close() error {
return deployment.Plugctx.Close()
}
func assertSeen(seen map[resource.URN]deploy.Step, step deploy.Step) {
_, has := seen[step.URN()]
contract.Assertf(has, "URN '%v' had not been marked as seen", step.URN())
}
func isDefaultProviderStep(step deploy.Step) bool {
return providers.IsDefaultProvider(step.URN())
}
func checkTargets(targetUrns deploy.UrnTargets, snap *deploy.Snapshot) error {
if !targetUrns.IsConstrained() {
return nil
}
if snap == nil {
Enable perfsprint linter (#14813) <!--- Thanks so much for your contribution! If this is your first time contributing, please ensure that you have read the [CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) documentation. --> # Description <!--- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. --> Prompted by a comment in another review: https://github.com/pulumi/pulumi/pull/14654#discussion_r1419995945 This lints that we don't use `fmt.Errorf` when `errors.New` will suffice, it also covers a load of other cases where `Sprintf` is sub-optimal. Most of these edits were made by running `perfsprint --fix`. ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [x] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
2023-12-12 12:19:42 +00:00
return errors.New("targets specified, but snapshot was nil")
}
urns := map[resource.URN]struct{}{}
for _, res := range snap.Resources {
urns[res.URN] = struct{}{}
}
for _, target := range targetUrns.Literals() {
if _, ok := urns[target]; !ok {
return fmt.Errorf("no resource named '%s' found", target)
}
}
return nil
}