2022-07-18 13:36:31 +00:00
|
|
|
// Copyright 2016-2022, Pulumi Corporation.
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2020-10-15 17:35:09 +00:00
|
|
|
package lifecycletest
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2021-11-13 02:37:17 +00:00
|
|
|
"errors"
|
2020-12-23 21:25:48 +00:00
|
|
|
"flag"
|
2018-08-14 22:32:23 +00:00
|
|
|
"fmt"
|
2020-12-23 21:25:48 +00:00
|
|
|
"os"
|
2022-04-05 11:43:04 +00:00
|
|
|
"regexp"
|
2023-12-12 12:19:42 +00:00
|
|
|
"strconv"
|
2018-08-13 20:41:01 +00:00
|
|
|
"strings"
|
2018-09-10 22:18:25 +00:00
|
|
|
"sync"
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
"testing"
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
"time"
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
|
|
|
"github.com/blang/semver"
|
2024-01-17 09:35:20 +00:00
|
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
2021-11-13 02:37:17 +00:00
|
|
|
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2021-08-11 00:44:15 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2020-09-15 00:40:17 +00:00
|
|
|
"google.golang.org/grpc"
|
2018-09-07 22:19:18 +00:00
|
|
|
"google.golang.org/grpc/codes"
|
2023-01-11 19:54:31 +00:00
|
|
|
"google.golang.org/grpc/credentials/insecure"
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2023-09-18 11:01:28 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/display"
|
2022-01-31 10:31:51 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/engine"
|
2023-11-21 15:16:13 +00:00
|
|
|
. "github.com/pulumi/pulumi/pkg/v3/engine" //nolint:revive
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/deploy"
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/deploy/deploytest"
|
2023-04-12 09:35:20 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers"
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/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"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/rpcutil"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/rpcutil/rpcerror"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
|
|
|
|
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
)
|
|
|
|
|
2020-10-15 17:35:09 +00:00
|
|
|
func SuccessfulSteps(entries JournalEntries) []deploy.Step {
|
2019-01-31 22:27:53 +00:00
|
|
|
var steps []deploy.Step
|
2020-10-15 17:35:09 +00:00
|
|
|
for _, entry := range entries {
|
2019-01-31 22:27:53 +00:00
|
|
|
if entry.Kind == JournalEntrySuccess {
|
|
|
|
steps = append(steps, entry.Step)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return steps
|
|
|
|
}
|
|
|
|
|
|
|
|
type StepSummary struct {
|
2022-06-27 14:08:06 +00:00
|
|
|
Op display.StepOp
|
2019-01-31 22:27:53 +00:00
|
|
|
URN resource.URN
|
|
|
|
}
|
|
|
|
|
|
|
|
func AssertSameSteps(t *testing.T, expected []StepSummary, actual []deploy.Step) bool {
|
|
|
|
assert.Equal(t, len(expected), len(actual))
|
|
|
|
for _, exp := range expected {
|
|
|
|
act := actual[0]
|
|
|
|
actual = actual[1:]
|
|
|
|
|
2020-07-09 14:19:12 +00:00
|
|
|
if !assert.Equal(t, exp.Op, act.Op()) || !assert.Equal(t, exp.URN, act.URN()) {
|
2019-01-31 22:27:53 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
func ExpectDiagMessage(t *testing.T, messagePattern string) ValidateFunc {
|
|
|
|
validate := func(
|
|
|
|
project workspace.Project, target deploy.Target,
|
|
|
|
entries JournalEntries, events []Event,
|
2024-05-06 17:34:24 +00:00
|
|
|
err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2022-10-11 15:30:58 +00:00
|
|
|
|
|
|
|
for i := range events {
|
|
|
|
if events[i].Type == "diag" {
|
|
|
|
payload := events[i].Payload().(engine.DiagEventPayload)
|
|
|
|
match, err := regexp.MatchString(messagePattern, payload.Message)
|
|
|
|
if err != nil {
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2022-10-11 15:30:58 +00:00
|
|
|
}
|
|
|
|
if match {
|
|
|
|
return nil
|
|
|
|
}
|
2023-10-11 14:44:09 +00:00
|
|
|
return fmt.Errorf("Unexpected diag message: %s", payload.Message)
|
2022-10-11 15:30:58 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-12 12:19:42 +00:00
|
|
|
return errors.New("Expected a diagnostic message, got none")
|
2022-10-11 15:30:58 +00:00
|
|
|
}
|
|
|
|
return validate
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func pickURN(t *testing.T, urns []resource.URN, names []string, target string) resource.URN {
|
|
|
|
assert.Equal(t, len(urns), len(names))
|
|
|
|
assert.Contains(t, names, target)
|
|
|
|
|
|
|
|
for i, name := range names {
|
|
|
|
if name == target {
|
|
|
|
return urns[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Fatalf("Could not find target: %v in %v", target, names)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2020-12-23 21:25:48 +00:00
|
|
|
func TestMain(m *testing.M) {
|
2022-01-11 17:20:43 +00:00
|
|
|
grpcDefault := flag.Bool("grpc-plugins", false, "enable or disable gRPC providers by default")
|
2020-12-23 21:25:48 +00:00
|
|
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
if *grpcDefault {
|
2022-01-11 17:20:43 +00:00
|
|
|
deploytest.UseGrpcPluginsByDefault = true
|
2020-12-23 21:25:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
os.Exit(m.Run())
|
|
|
|
}
|
|
|
|
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
func TestEmptyProgramLifecycle(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, _ *deploytest.ResourceMonitor) error {
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 0),
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestSingleResourceDiffUnavailable(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return &deploytest.Provider{
|
|
|
|
DiffF: func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return plugin.DiffResult{}, plugin.DiffUnavailable("diff unavailable")
|
|
|
|
},
|
|
|
|
}, nil
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
inputs := resource.PropertyMap{}
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: inputs,
|
|
|
|
})
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
resURN := p.NewURN("pkgA:m:typA", "resA", "")
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Run the initial update.
|
|
|
|
project := p.GetProject()
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2020-12-18 21:45:52 +00:00
|
|
|
// Now run a preview. Expect a warning because the diff is unavailable.
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, true, p.BackendClient,
|
2020-12-15 22:24:46 +00:00
|
|
|
func(_ workspace.Project, _ deploy.Target, _ JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
found := false
|
|
|
|
for _, e := range events {
|
|
|
|
if e.Type == DiagEvent {
|
|
|
|
p := e.Payload().(DiagEventPayload)
|
2021-11-24 22:13:29 +00:00
|
|
|
if p.URN == resURN && p.Severity == diag.Warning && p.Message == "<{%reset%}>diff unavailable<{%reset%}>\n" {
|
2020-12-15 22:24:46 +00:00
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.True(t, found)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2019-07-25 18:18:40 +00:00
|
|
|
})
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Test that ensures that we log diagnostics for resources that receive an error from Check. (Note that this
|
|
|
|
// is distinct from receiving non-error failures from Check.)
|
|
|
|
func TestCheckFailureRecord(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return &deploytest.Provider{
|
|
|
|
CheckF: func(urn resource.URN,
|
2023-03-03 16:36:39 +00:00
|
|
|
olds, news resource.PropertyMap, randomSeed []byte,
|
|
|
|
) (resource.PropertyMap, []plugin.CheckFailure, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return nil, nil, errors.New("oh no, check had an error")
|
|
|
|
},
|
|
|
|
}, nil
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
return err
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
})
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
Steps: []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
sawFailure := false
|
|
|
|
for _, evt := range evts {
|
|
|
|
if evt.Type == DiagEvent {
|
|
|
|
e := evt.Payload().(DiagEventPayload)
|
|
|
|
msg := colors.Never.Colorize(e.Message)
|
|
|
|
sawFailure = msg == "oh no, check had an error\n" && e.Severity == diag.Error
|
|
|
|
}
|
|
|
|
}
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, sawFailure)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}},
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Run(t, nil)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Test that checks that we emit diagnostics for properties that check says are invalid.
|
|
|
|
func TestCheckFailureInvalidPropertyRecord(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2020-12-15 22:24:46 +00:00
|
|
|
CheckF: func(urn resource.URN,
|
2023-03-03 16:36:39 +00:00
|
|
|
olds, news resource.PropertyMap, randomSeed []byte,
|
|
|
|
) (resource.PropertyMap, []plugin.CheckFailure, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return nil, []plugin.CheckFailure{{
|
|
|
|
Property: "someprop",
|
|
|
|
Reason: "field is not valid",
|
|
|
|
}}, nil
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
return err
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
})
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
Steps: []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
sawFailure := false
|
|
|
|
for _, evt := range evts {
|
|
|
|
if evt.Type == DiagEvent {
|
|
|
|
e := evt.Payload().(DiagEventPayload)
|
|
|
|
msg := colors.Never.Colorize(e.Message)
|
|
|
|
sawFailure = strings.Contains(msg, "field is not valid") && e.Severity == diag.Error
|
|
|
|
if sawFailure {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, sawFailure)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
|
|
|
}},
|
|
|
|
}
|
2018-09-10 23:48:14 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Run(t, nil)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Tests that errors returned directly from the language host get logged by the engine.
|
|
|
|
func TestLanguageHostDiagnostics(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return &deploytest.Provider{}, nil
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
errorText := "oh no"
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, _ *deploytest.ResourceMonitor) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
// Exiting immediately with an error simulates a language exiting immediately with a non-zero exit code.
|
|
|
|
return errors.New(errorText)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
})
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
Steps: []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
sawExitCode := false
|
|
|
|
for _, evt := range evts {
|
|
|
|
if evt.Type == DiagEvent {
|
|
|
|
e := evt.Payload().(DiagEventPayload)
|
|
|
|
msg := colors.Never.Colorize(e.Message)
|
|
|
|
sawExitCode = strings.Contains(msg, errorText) && e.Severity == diag.Error
|
|
|
|
if sawExitCode {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, sawExitCode)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
|
|
|
}},
|
|
|
|
}
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
type brokenDecrypter struct {
|
|
|
|
ErrorMessage string
|
|
|
|
}
|
|
|
|
|
2022-07-18 13:36:31 +00:00
|
|
|
func (b brokenDecrypter) DecryptValue(_ context.Context, _ string) (string, error) {
|
2023-12-12 12:19:42 +00:00
|
|
|
return "", errors.New(b.ErrorMessage)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-18 13:36:31 +00:00
|
|
|
func (b brokenDecrypter) BulkDecrypt(_ context.Context, _ []string) (map[string]string, error) {
|
2023-12-12 12:19:42 +00:00
|
|
|
return nil, errors.New(b.ErrorMessage)
|
2022-04-11 07:59:46 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Tests that the engine presents a reasonable error message when a decrypter fails to decrypt a config value.
|
|
|
|
func TestBrokenDecrypter(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return &deploytest.Provider{}, nil
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, _ *deploytest.ResourceMonitor) error {
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-12-15 22:24:46 +00:00
|
|
|
key := config.MustMakeKey("foo", "bar")
|
|
|
|
msg := "decryption failed"
|
|
|
|
configMap := make(config.Map)
|
|
|
|
configMap[key] = config.NewSecureValue("hunter2")
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
Decrypter: brokenDecrypter{ErrorMessage: msg},
|
|
|
|
Config: configMap,
|
|
|
|
Steps: []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2023-10-11 14:44:09 +00:00
|
|
|
decryptErr := err.(DecryptError)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Equal(t, key, decryptErr.Key)
|
2023-12-15 17:45:32 +00:00
|
|
|
assert.ErrorContains(t, decryptErr.Err, msg)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
|
|
|
}},
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2023-10-20 10:44:16 +00:00
|
|
|
func TestConfigPropertyMapMatches(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
|
|
|
// Check that the config property map matches what we expect.
|
|
|
|
assert.Equal(t, 8, len(info.Config))
|
|
|
|
assert.Equal(t, 8, len(info.ConfigPropertyMap))
|
|
|
|
|
|
|
|
assert.Equal(t, "hunter2", info.Config[config.MustMakeKey("pkgA", "secret")])
|
|
|
|
assert.True(t, info.ConfigPropertyMap["pkgA:secret"].IsSecret())
|
|
|
|
assert.Equal(t, "hunter2", info.ConfigPropertyMap["pkgA:secret"].SecretValue().Element.StringValue())
|
|
|
|
|
|
|
|
assert.Equal(t, "all I see is ******", info.Config[config.MustMakeKey("pkgA", "plain")])
|
|
|
|
assert.False(t, info.ConfigPropertyMap["pkgA:plain"].IsSecret())
|
|
|
|
assert.Equal(t, "all I see is ******", info.ConfigPropertyMap["pkgA:plain"].StringValue())
|
|
|
|
|
|
|
|
assert.Equal(t, "1234", info.Config[config.MustMakeKey("pkgA", "int")])
|
|
|
|
assert.Equal(t, 1234.0, info.ConfigPropertyMap["pkgA:int"].NumberValue())
|
|
|
|
|
|
|
|
assert.Equal(t, "12.34", info.Config[config.MustMakeKey("pkgA", "float")])
|
|
|
|
// This is a string because adjustObjectValue only parses integers, not floats.
|
|
|
|
assert.Equal(t, "12.34", info.ConfigPropertyMap["pkgA:float"].StringValue())
|
|
|
|
|
|
|
|
assert.Equal(t, "012345", info.Config[config.MustMakeKey("pkgA", "string")])
|
|
|
|
assert.Equal(t, "012345", info.ConfigPropertyMap["pkgA:string"].StringValue())
|
|
|
|
|
|
|
|
assert.Equal(t, "true", info.Config[config.MustMakeKey("pkgA", "bool")])
|
|
|
|
assert.Equal(t, true, info.ConfigPropertyMap["pkgA:bool"].BoolValue())
|
|
|
|
|
|
|
|
assert.Equal(t, "[1,2,3]", info.Config[config.MustMakeKey("pkgA", "array")])
|
|
|
|
assert.Equal(t, 1.0, info.ConfigPropertyMap["pkgA:array"].ArrayValue()[0].NumberValue())
|
|
|
|
assert.Equal(t, 2.0, info.ConfigPropertyMap["pkgA:array"].ArrayValue()[1].NumberValue())
|
|
|
|
assert.Equal(t, 3.0, info.ConfigPropertyMap["pkgA:array"].ArrayValue()[2].NumberValue())
|
|
|
|
|
|
|
|
assert.Equal(t, `{"bar":"02","foo":1}`, info.Config[config.MustMakeKey("pkgA", "map")])
|
|
|
|
assert.Equal(t, 1.0, info.ConfigPropertyMap["pkgA:map"].ObjectValue()["foo"].NumberValue())
|
|
|
|
assert.Equal(t, "02", info.ConfigPropertyMap["pkgA:map"].ObjectValue()["bar"].StringValue())
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF)
|
|
|
|
|
|
|
|
crypter := config.NewSymmetricCrypter(make([]byte, 32))
|
|
|
|
secret, err := crypter.EncryptValue(context.Background(), "hunter2")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2023-10-20 10:44:16 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 0),
|
|
|
|
Config: config.Map{
|
|
|
|
config.MustMakeKey("pkgA", "secret"): config.NewSecureValue(secret),
|
|
|
|
config.MustMakeKey("pkgA", "plain"): config.NewValue("all I see is ******"),
|
|
|
|
config.MustMakeKey("pkgA", "int"): config.NewValue("1234"),
|
|
|
|
config.MustMakeKey("pkgA", "float"): config.NewValue("12.34"),
|
|
|
|
config.MustMakeKey("pkgA", "string"): config.NewValue("012345"),
|
|
|
|
config.MustMakeKey("pkgA", "bool"): config.NewValue("true"),
|
|
|
|
config.MustMakeKey("pkgA", "array"): config.NewObjectValue("[1, 2, 3]"),
|
|
|
|
config.MustMakeKey("pkgA", "map"): config.NewObjectValue(`{"foo": 1, "bar": "02"}`),
|
|
|
|
},
|
|
|
|
Decrypter: crypter,
|
|
|
|
}
|
|
|
|
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestBadResourceType(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := mon.RegisterResource("very:bad", "resA", true)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
rpcerr, ok := rpcerror.FromError(err)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, codes.InvalidArgument, rpcerr.Code())
|
|
|
|
assert.Contains(t, rpcerr.Message(), "Type 'very:bad' is not a valid type token")
|
2019-03-19 23:21:50 +00:00
|
|
|
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
_, _, err = mon.ReadResource("very:bad", "someResource", "someId", "", resource.PropertyMap{}, "", "", "")
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
rpcerr, ok = rpcerror.FromError(err)
|
|
|
|
assert.True(t, ok)
|
|
|
|
assert.Equal(t, codes.InvalidArgument, rpcerr.Code())
|
|
|
|
assert.Contains(t, rpcerr.Message(), "Type 'very:bad' is not a valid type token")
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Component resources may have any format type.
|
2024-04-19 11:08:56 +00:00
|
|
|
_, noErr := mon.RegisterResource("a:component", "resB", false)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.NoError(t, noErr)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, noErr = mon.RegisterResource("singlename", "resC", false)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.NoError(t, noErr)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
return err
|
|
|
|
})
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
Steps: []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
|
|
|
|
p.Run(t, nil)
|
Implement first-class providers. (#1695)
### First-Class Providers
These changes implement support for first-class providers. First-class
providers are provider plugins that are exposed as resources via the
Pulumi programming model so that they may be explicitly and multiply
instantiated. Each instance of a provider resource may be configured
differently, and configuration parameters may be source from the
outputs of other resources.
### Provider Plugin Changes
In order to accommodate the need to verify and diff provider
configuration and configure providers without complete configuration
information, these changes adjust the high-level provider plugin
interface. Two new methods for validating a provider's configuration
and diffing changes to the same have been added (`CheckConfig` and
`DiffConfig`, respectively), and the type of the configuration bag
accepted by `Configure` has been changed to a `PropertyMap`.
These changes have not yet been reflected in the provider plugin gRPC
interface. We will do this in a set of follow-up changes. Until then,
these methods are implemented by adapters:
- `CheckConfig` validates that all configuration parameters are string
or unknown properties. This is necessary because existing plugins
only accept string-typed configuration values.
- `DiffConfig` either returns "never replace" if all configuration
values are known or "must replace" if any configuration value is
unknown. The justification for this behavior is given
[here](https://github.com/pulumi/pulumi/pull/1695/files#diff-a6cd5c7f337665f5bb22e92ca5f07537R106)
- `Configure` converts the config bag to a legacy config map and
configures the provider plugin if all config values are known. If any
config value is unknown, the underlying plugin is not configured and
the provider may only perform `Check`, `Read`, and `Invoke`, all of
which return empty results. We justify this behavior becuase it is
only possible during a preview and provides the best experience we
can manage with the existing gRPC interface.
### Resource Model Changes
Providers are now exposed as resources that participate in a stack's
dependency graph. Like other resources, they are explicitly created,
may have multiple instances, and may have dependencies on other
resources. Providers are referred to using provider references, which
are a combination of the provider's URN and its ID. This design
addresses the need during a preview to refer to providers that have not
yet been physically created and therefore have no ID.
All custom resources that are not themselves providers must specify a
single provider via a provider reference. The named provider will be
used to manage that resource's CRUD operations. If a resource's
provider reference changes, the resource must be replaced. Though its
URN is not present in the resource's dependency list, the provider
should be treated as a dependency of the resource when topologically
sorting the dependency graph.
Finally, `Invoke` operations must now specify a provider to use for the
invocation via a provider reference.
### Engine Changes
First-class providers support requires a few changes to the engine:
- The engine must have some way to map from provider references to
provider plugins. It must be possible to add providers from a stack's
checkpoint to this map and to register new/updated providers during
the execution of a plan in response to CRUD operations on provider
resources.
- In order to support updating existing stacks using existing Pulumi
programs that may not explicitly instantiate providers, the engine
must be able to manage the "default" providers for each package
referenced by a checkpoint or Pulumi program. The configuration for
a "default" provider is taken from the stack's configuration data.
The former need is addressed by adding a provider registry type that is
responsible for managing all of the plugins required by a plan. In
addition to loading plugins froma checkpoint and providing the ability
to map from a provider reference to a provider plugin, this type serves
as the provider plugin for providers themselves (i.e. it is the
"provider provider").
The latter need is solved via two relatively self-contained changes to
plan setup and the eval source.
During plan setup, the old checkpoint is scanned for custom resources
that do not have a provider reference in order to compute the set of
packages that require a default provider. Once this set has been
computed, the required default provider definitions are conjured and
prepended to the checkpoint's resource list. Each resource that
requires a default provider is then updated to refer to the default
provider for its package.
While an eval source is running, each custom resource registration,
resource read, and invoke that does not name a provider is trapped
before being returned by the source iterator. If no default provider
for the appropriate package has been registered, the eval source
synthesizes an appropriate registration, waits for it to complete, and
records the registered provider's reference. This reference is injected
into the original request, which is then processed as usual. If a
default provider was already registered, the recorded reference is
used and no new registration occurs.
### SDK Changes
These changes only expose first-class providers from the Node.JS SDK.
- A new abstract class, `ProviderResource`, can be subclassed and used
to instantiate first-class providers.
- A new field in `ResourceOptions`, `provider`, can be used to supply
a particular provider instance to manage a `CustomResource`'s CRUD
operations.
- A new type, `InvokeOptions`, can be used to specify options that
control the behavior of a call to `pulumi.runtime.invoke`. This type
includes a `provider` field that is analogous to
`ResourceOptions.provider`.
2018-08-07 00:50:29 +00:00
|
|
|
}
|
2018-08-07 18:01:08 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Tests that provider cancellation occurs as expected.
|
|
|
|
func TestProviderCancellation(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
const resourceCount = 4
|
|
|
|
|
|
|
|
// Set up a cancelable context for the refresh operation.
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
// Wait for our resource ops, then cancel.
|
|
|
|
var ops sync.WaitGroup
|
|
|
|
ops.Add(resourceCount)
|
|
|
|
go func() {
|
|
|
|
ops.Wait()
|
|
|
|
cancel()
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Set up an independent cancelable context for the provider's operations.
|
|
|
|
provCtx, provCancel := context.WithCancel(context.Background())
|
2018-11-22 00:53:29 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2020-12-15 22:24:46 +00:00
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
// Inform the waiter that we've entered a provider op and wait for cancellation.
|
|
|
|
ops.Done()
|
|
|
|
<-provCtx.Done()
|
|
|
|
|
|
|
|
return resource.ID(urn.Name()), resource.PropertyMap{}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
CancelF: func() error {
|
|
|
|
provCancel()
|
|
|
|
return nil
|
2018-11-22 00:53:29 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
done := make(chan bool)
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
errors := make([]error, resourceCount)
|
|
|
|
var resources sync.WaitGroup
|
|
|
|
resources.Add(resourceCount)
|
|
|
|
for i := 0; i < resourceCount; i++ {
|
|
|
|
go func(idx int) {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, errors[idx] = monitor.RegisterResource("pkgA:m:typA", fmt.Sprintf("res%d", idx), true)
|
2020-12-15 22:24:46 +00:00
|
|
|
resources.Done()
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
resources.Wait()
|
|
|
|
for _, err := range errors {
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
close(done)
|
2018-11-22 00:53:29 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{}
|
|
|
|
op := TestOp(Update)
|
2023-09-28 21:50:18 +00:00
|
|
|
options := TestUpdateOptions{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
T: t,
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...),
|
|
|
|
UpdateOptions: UpdateOptions{
|
|
|
|
Parallel: resourceCount,
|
|
|
|
},
|
2018-11-22 00:53:29 +00:00
|
|
|
}
|
2021-12-09 09:09:48 +00:00
|
|
|
project, target := p.GetProject(), p.GetTarget(t, nil)
|
2018-11-22 00:53:29 +00:00
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err := op.RunWithContext(ctx, project, target, options, false, nil, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2019-03-19 23:21:50 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Wait for the program to finish.
|
|
|
|
<-done
|
2018-11-22 00:53:29 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Tests that a preview works for a stack with pending operations.
|
|
|
|
func TestPreviewWithPendingOperations(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{}
|
2018-08-07 18:01:08 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
const resType = "pkgA:m:typA"
|
|
|
|
urnA := p.NewURN(resType, "resA", "")
|
2018-08-07 18:01:08 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
newResource := func(urn resource.URN, id resource.ID, delete bool, dependencies ...resource.URN) *resource.State {
|
|
|
|
return &resource.State{
|
|
|
|
Type: urn.Type(),
|
|
|
|
URN: urn,
|
|
|
|
Custom: true,
|
|
|
|
Delete: delete,
|
|
|
|
ID: id,
|
|
|
|
Inputs: resource.PropertyMap{},
|
|
|
|
Outputs: resource.PropertyMap{},
|
|
|
|
Dependencies: dependencies,
|
|
|
|
}
|
2018-08-07 18:01:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
old := &deploy.Snapshot{
|
2020-12-15 22:24:46 +00:00
|
|
|
PendingOperations: []resource.Operation{{
|
|
|
|
Resource: newResource(urnA, "0", false),
|
|
|
|
Type: resource.OperationTypeUpdating,
|
|
|
|
}},
|
2018-08-07 18:01:08 +00:00
|
|
|
Resources: []*resource.State{
|
2020-12-15 22:24:46 +00:00
|
|
|
newResource(urnA, "0", false),
|
2018-08-07 18:01:08 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-08-08 20:45:48 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2018-08-08 20:45:48 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
op := TestOp(Update)
|
2023-09-28 21:50:18 +00:00
|
|
|
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
options := TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2021-12-09 09:09:48 +00:00
|
|
|
project, target := p.GetProject(), p.GetTarget(t, old)
|
2018-08-08 20:45:48 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// A preview should succeed despite the pending operations.
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err := op.Run(project, target, options, true, nil, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2018-08-08 20:45:48 +00:00
|
|
|
}
|
2018-08-09 19:45:39 +00:00
|
|
|
|
2022-03-25 09:59:19 +00:00
|
|
|
// Tests that a refresh works for a stack with pending operations.
|
|
|
|
func TestRefreshWithPendingOperations(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
p := &TestPlan{}
|
|
|
|
|
|
|
|
const resType = "pkgA:m:typA"
|
|
|
|
urnA := p.NewURN(resType, "resA", "")
|
|
|
|
|
|
|
|
newResource := func(urn resource.URN, id resource.ID, delete bool, dependencies ...resource.URN) *resource.State {
|
|
|
|
return &resource.State{
|
|
|
|
Type: urn.Type(),
|
|
|
|
URN: urn,
|
|
|
|
Custom: true,
|
|
|
|
Delete: delete,
|
|
|
|
ID: id,
|
|
|
|
Inputs: resource.PropertyMap{},
|
|
|
|
Outputs: resource.PropertyMap{},
|
|
|
|
Dependencies: dependencies,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
old := &deploy.Snapshot{
|
|
|
|
PendingOperations: []resource.Operation{{
|
|
|
|
Resource: newResource(urnA, "0", false),
|
|
|
|
Type: resource.OperationTypeUpdating,
|
|
|
|
}},
|
|
|
|
Resources: []*resource.State{
|
|
|
|
newResource(urnA, "0", false),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2022-03-25 09:59:19 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
op := TestOp(Update)
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
options := TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2022-03-25 09:59:19 +00:00
|
|
|
project, target := p.GetProject(), p.GetTarget(t, old)
|
|
|
|
|
|
|
|
// With a refresh, the update should succeed.
|
|
|
|
withRefresh := options
|
|
|
|
withRefresh.Refresh = true
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
new, err := op.RunStep(project, target, withRefresh, false, nil, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-03-25 09:59:19 +00:00
|
|
|
assert.Len(t, new.PendingOperations, 0)
|
|
|
|
|
|
|
|
// Similarly, the update should succeed if performed after a separate refresh.
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
new, err = TestOp(Refresh).RunStep(project, target, options, false, nil, nil, "1")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-03-25 09:59:19 +00:00
|
|
|
assert.Len(t, new.PendingOperations, 0)
|
|
|
|
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
_, err = op.RunStep(project, p.GetTarget(t, new), options, false, nil, nil, "2")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-03-25 09:59:19 +00:00
|
|
|
}
|
|
|
|
|
2022-04-05 20:44:11 +00:00
|
|
|
// Test to make sure that if we pulumi refresh
|
|
|
|
// while having pending CREATE operations,
|
|
|
|
// that these are preserved after the refresh.
|
|
|
|
func TestRefreshPreservesPendingCreateOperations(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
p := &TestPlan{}
|
|
|
|
|
|
|
|
const resType = "pkgA:m:typA"
|
|
|
|
urnA := p.NewURN(resType, "resA", "")
|
|
|
|
urnB := p.NewURN(resType, "resB", "")
|
|
|
|
|
|
|
|
newResource := func(urn resource.URN, id resource.ID, delete bool, dependencies ...resource.URN) *resource.State {
|
|
|
|
return &resource.State{
|
|
|
|
Type: urn.Type(),
|
|
|
|
URN: urn,
|
|
|
|
Custom: true,
|
|
|
|
Delete: delete,
|
|
|
|
ID: id,
|
|
|
|
Inputs: resource.PropertyMap{},
|
|
|
|
Outputs: resource.PropertyMap{},
|
|
|
|
Dependencies: dependencies,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notice here, we have two pending operations: update and create
|
|
|
|
// After a refresh, only the pending CREATE operation should
|
|
|
|
// be in the updated snapshot
|
|
|
|
resA := newResource(urnA, "0", false)
|
|
|
|
resB := newResource(urnB, "0", false)
|
|
|
|
old := &deploy.Snapshot{
|
|
|
|
PendingOperations: []resource.Operation{
|
|
|
|
{
|
|
|
|
Resource: resA,
|
|
|
|
Type: resource.OperationTypeUpdating,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Resource: resB,
|
|
|
|
Type: resource.OperationTypeCreating,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
Resources: []*resource.State{
|
|
|
|
resA,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2022-04-05 20:44:11 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
op := TestOp(Update)
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
options := TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2022-04-05 20:44:11 +00:00
|
|
|
project, target := p.GetProject(), p.GetTarget(t, old)
|
|
|
|
|
|
|
|
// With a refresh, the update should succeed.
|
|
|
|
withRefresh := options
|
|
|
|
withRefresh.Refresh = true
|
2023-10-11 14:44:09 +00:00
|
|
|
new, err := op.Run(project, target, withRefresh, false, nil, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-04-05 20:44:11 +00:00
|
|
|
// Assert that pending CREATE operation was preserved
|
|
|
|
assert.Len(t, new.PendingOperations, 1)
|
|
|
|
assert.Equal(t, resource.OperationTypeCreating, new.PendingOperations[0].Type)
|
|
|
|
assert.Equal(t, urnB, new.PendingOperations[0].Resource.URN)
|
|
|
|
}
|
|
|
|
|
|
|
|
func findPendingOperationsByType(opType resource.OperationType, snapshot *deploy.Snapshot) []resource.Operation {
|
|
|
|
var operations []resource.Operation
|
|
|
|
for _, operation := range snapshot.PendingOperations {
|
|
|
|
if operation.Type == opType {
|
|
|
|
operations = append(operations, operation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return operations
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update succeeds but gives a warning when there are pending operations
|
|
|
|
func TestUpdateShowsWarningWithPendingOperations(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
p := &TestPlan{}
|
|
|
|
|
|
|
|
const resType = "pkgA:m:typA"
|
|
|
|
urnA := p.NewURN(resType, "resA", "")
|
|
|
|
urnB := p.NewURN(resType, "resB", "")
|
|
|
|
|
|
|
|
newResource := func(urn resource.URN, id resource.ID, delete bool, dependencies ...resource.URN) *resource.State {
|
|
|
|
return &resource.State{
|
|
|
|
Type: urn.Type(),
|
|
|
|
URN: urn,
|
|
|
|
Custom: true,
|
|
|
|
Delete: delete,
|
|
|
|
ID: id,
|
|
|
|
Inputs: resource.PropertyMap{},
|
|
|
|
Outputs: resource.PropertyMap{},
|
|
|
|
Dependencies: dependencies,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
old := &deploy.Snapshot{
|
|
|
|
PendingOperations: []resource.Operation{
|
|
|
|
{
|
|
|
|
Resource: newResource(urnA, "0", false),
|
|
|
|
Type: resource.OperationTypeUpdating,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Resource: newResource(urnB, "1", false),
|
|
|
|
Type: resource.OperationTypeCreating,
|
2023-03-03 16:36:39 +00:00
|
|
|
},
|
|
|
|
},
|
2022-04-05 20:44:11 +00:00
|
|
|
Resources: []*resource.State{
|
|
|
|
newResource(urnA, "0", false),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2022-04-05 20:44:11 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
op := TestOp(Update)
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
options := TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2022-04-05 20:44:11 +00:00
|
|
|
project, target := p.GetProject(), p.GetTarget(t, old)
|
|
|
|
|
|
|
|
// The update should succeed but give a warning
|
|
|
|
initialPartOfMessage := "Attempting to deploy or update resources with 1 pending operations from previous deployment."
|
|
|
|
validate := func(
|
|
|
|
project workspace.Project, target deploy.Target,
|
|
|
|
entries JournalEntries, events []Event,
|
2024-05-06 17:34:24 +00:00
|
|
|
err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2022-04-05 20:44:11 +00:00
|
|
|
for i := range events {
|
|
|
|
if events[i].Type == "diag" {
|
|
|
|
payload := events[i].Payload().(engine.DiagEventPayload)
|
|
|
|
|
|
|
|
if payload.Severity == "warning" && strings.Contains(payload.Message, initialPartOfMessage) {
|
|
|
|
return nil
|
|
|
|
}
|
2023-10-11 14:44:09 +00:00
|
|
|
return fmt.Errorf("Unexpected warning diag message: %s", payload.Message)
|
2022-04-05 20:44:11 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-12 12:19:42 +00:00
|
|
|
return errors.New("Expected a diagnostic message, got none")
|
2022-04-05 20:44:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
new, _ := op.Run(project, target, options, false, nil, validate)
|
|
|
|
assert.NotNil(t, new)
|
|
|
|
|
|
|
|
assert.Equal(t, resource.OperationTypeCreating, new.PendingOperations[0].Type)
|
|
|
|
|
|
|
|
// Assert that CREATE pending operations are retained
|
|
|
|
// TODO: should revisit whether non-CREATE pending operations should also be retained
|
|
|
|
assert.Equal(t, 1, len(new.PendingOperations))
|
|
|
|
createOperations := findPendingOperationsByType(resource.OperationTypeCreating, new)
|
|
|
|
assert.Equal(t, 1, len(createOperations))
|
|
|
|
assert.Equal(t, urnB, createOperations[0].Resource.URN)
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Tests that a failed partial update causes the engine to persist the resource's old inputs and new outputs.
|
|
|
|
func TestUpdatePartialFailure(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2018-08-09 19:45:39 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return &deploytest.Provider{
|
2023-05-29 15:41:36 +00:00
|
|
|
DiffF: func(urn resource.URN, id resource.ID, oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
ignoreChanges []string,
|
|
|
|
) (plugin.DiffResult, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
}, nil
|
|
|
|
},
|
2018-09-05 21:00:28 +00:00
|
|
|
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
outputs := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"output_prop": 42,
|
|
|
|
})
|
2018-08-07 07:40:43 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
return outputs, resource.StatusPartialFailure, errors.New("update failed to apply")
|
2018-08-07 07:40:43 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := mon.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"input_prop": "new inputs",
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
return err
|
2018-08-07 07:40:43 +00:00
|
|
|
})
|
2020-12-15 22:24:46 +00:00
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p := &TestPlan{Options: TestUpdateOptions{T: t, HostF: hostF}}
|
2018-08-07 07:40:43 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
resURN := p.NewURN("pkgA:m:typA", "resA", "")
|
|
|
|
p.Steps = []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
for _, entry := range entries {
|
|
|
|
switch urn := entry.Step.URN(); urn {
|
|
|
|
case resURN:
|
|
|
|
assert.Equal(t, deploy.OpUpdate, entry.Step.Op())
|
turn on the golangci-lint exhaustive linter (#15028)
Turn on the golangci-lint exhaustive linter. This is the first step
towards catching more missing cases during development rather than
in tests, or in production.
This might be best reviewed commit-by-commit, as the first commit turns
on the linter with the `default-signifies-exhaustive: true` option set,
which requires a lot less changes in the current codebase.
I think it's probably worth doing the second commit as well, as that
will get us the real benefits, even though we end up with a little bit
more churn. However it means all the `switch` statements are covered,
which isn't the case after the first commit, since we do have a lot of
`default` statements that just call `assert.Fail`.
Fixes #14601
## 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. -->
2024-01-17 16:50:41 +00:00
|
|
|
//nolint:exhaustive // default case signifies testing failure
|
2020-12-15 22:24:46 +00:00
|
|
|
switch entry.Kind {
|
|
|
|
case JournalEntryBegin:
|
|
|
|
continue
|
|
|
|
case JournalEntrySuccess:
|
|
|
|
inputs := entry.Step.New().Inputs
|
|
|
|
outputs := entry.Step.New().Outputs
|
|
|
|
assert.Len(t, inputs, 1)
|
|
|
|
assert.Len(t, outputs, 1)
|
|
|
|
assert.Equal(t,
|
|
|
|
resource.NewStringProperty("old inputs"), inputs[resource.PropertyKey("input_prop")])
|
|
|
|
assert.Equal(t,
|
|
|
|
resource.NewNumberProperty(42), outputs[resource.PropertyKey("output_prop")])
|
|
|
|
default:
|
|
|
|
t.Fatalf("unexpected journal operation: %d", entry.Kind)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
|
|
|
}}
|
2018-08-07 07:40:43 +00:00
|
|
|
|
|
|
|
old := &deploy.Snapshot{
|
2018-09-05 21:00:28 +00:00
|
|
|
Resources: []*resource.State{
|
|
|
|
{
|
2020-12-15 22:24:46 +00:00
|
|
|
Type: resURN.Type(),
|
|
|
|
URN: resURN,
|
|
|
|
Custom: true,
|
|
|
|
ID: "1",
|
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"input_prop": "old inputs",
|
|
|
|
}),
|
|
|
|
Outputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"output_prop": 1,
|
|
|
|
}),
|
2018-09-05 21:00:28 +00:00
|
|
|
},
|
|
|
|
},
|
2018-08-07 07:40:43 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Run(t, old)
|
2018-08-07 07:40:43 +00:00
|
|
|
}
|
2018-08-13 20:41:01 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Tests that the StackReference resource works as intended,
|
|
|
|
func TestStackReference(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{}
|
2018-08-13 20:41:01 +00:00
|
|
|
|
2023-12-03 08:46:37 +00:00
|
|
|
// Test that the normal lifecycle works correctly.
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
|
|
|
_, state, err := mon.ReadResource("pulumi:pulumi:StackReference", "other", "other", "",
|
|
|
|
resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other",
|
|
|
|
}), "", "", "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
if !info.DryRun {
|
|
|
|
assert.Equal(t, "bar", state["outputs"].ObjectValue()["foo"].StringValue())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
p := &TestPlan{
|
|
|
|
BackendClient: &deploytest.BackendClient{
|
|
|
|
GetStackOutputsF: func(ctx context.Context, name string) (resource.PropertyMap, error) {
|
|
|
|
switch name {
|
|
|
|
case "other":
|
|
|
|
return resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
}), nil
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unknown stack \"%s\"", name)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)},
|
2023-12-03 08:46:37 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 2),
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
|
|
|
|
// Test that changes to `name` cause replacement.
|
|
|
|
resURN := p.NewURN("pulumi:pulumi:StackReference", "other", "")
|
|
|
|
old := &deploy.Snapshot{
|
|
|
|
Resources: []*resource.State{
|
|
|
|
{
|
|
|
|
Type: resURN.Type(),
|
|
|
|
URN: resURN,
|
|
|
|
Custom: true,
|
|
|
|
ID: "1",
|
|
|
|
External: true,
|
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other2",
|
|
|
|
}),
|
|
|
|
Outputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other2",
|
|
|
|
"outputs": resource.PropertyMap{},
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
p.Steps = []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-12-03 08:46:37 +00:00
|
|
|
) error {
|
|
|
|
assert.NoError(t, err)
|
|
|
|
for _, entry := range entries {
|
|
|
|
switch urn := entry.Step.URN(); urn {
|
|
|
|
case resURN:
|
|
|
|
switch entry.Step.Op() {
|
|
|
|
case deploy.OpRead:
|
|
|
|
// OK
|
|
|
|
default:
|
|
|
|
t.Fatalf("unexpected journal operation: %v", entry.Step.Op())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
},
|
|
|
|
}}
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p.Options.SkipDisplayTests = true
|
2023-12-03 08:46:37 +00:00
|
|
|
p.Run(t, old)
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p.Options.SkipDisplayTests = false
|
2023-12-03 08:46:37 +00:00
|
|
|
|
|
|
|
// Test that unknown stacks are handled appropriately.
|
|
|
|
programF = deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
|
|
|
_, _, err := mon.ReadResource("pulumi:pulumi:StackReference", "other", "other", "",
|
|
|
|
resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "rehto",
|
|
|
|
}), "", "", "")
|
|
|
|
assert.Error(t, err)
|
|
|
|
return err
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p.Options = TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2023-12-03 08:46:37 +00:00
|
|
|
p.Steps = []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
}}
|
|
|
|
p.Run(t, nil)
|
|
|
|
|
|
|
|
// Test that unknown properties cause errors.
|
|
|
|
programF = deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
|
|
|
_, _, err := mon.ReadResource("pulumi:pulumi:StackReference", "other", "other", "",
|
|
|
|
resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other",
|
|
|
|
"foo": "bar",
|
|
|
|
}), "", "", "")
|
|
|
|
assert.Error(t, err)
|
|
|
|
return err
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p.Options = TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2023-12-03 08:46:37 +00:00
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tests that registering (rather than reading) a StackReference resource works as intended, but warns the user that
|
|
|
|
// it's deprecated.
|
|
|
|
func TestStackReferenceRegister(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Test that the normal lifecycle works correctly.
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := mon.RegisterResource("pulumi:pulumi:StackReference", "other", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other",
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
if !info.DryRun {
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.Equal(t, "bar", resp.Outputs["outputs"].ObjectValue()["foo"].StringValue())
|
2020-12-15 22:24:46 +00:00
|
|
|
}
|
|
|
|
return nil
|
2018-08-13 20:41:01 +00:00
|
|
|
})
|
2023-12-03 08:46:37 +00:00
|
|
|
|
|
|
|
steps := MakeBasicLifecycleSteps(t, 2)
|
|
|
|
// Add an extra validate stage to each step to check we get the diagnostic that this use of stack reference is
|
|
|
|
// obsolete if a stack resource was registered.
|
|
|
|
for i := range steps {
|
|
|
|
v := steps[i].Validate
|
|
|
|
steps[i].Validate = func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-12-03 08:46:37 +00:00
|
|
|
) error {
|
|
|
|
// Check if we registered a stack reference resource (i.e. same/update/create). Ideally we'd warn on refresh
|
|
|
|
// as well but that's just a Read so it's hard to tell in the built-in provider if that's a Read for a
|
|
|
|
// ReadResource or a Read for a refresh, so we don't worry about that case.
|
|
|
|
registered := false
|
|
|
|
for _, entry := range entries {
|
|
|
|
if entry.Step.URN().Type() == "pulumi:pulumi:StackReference" &&
|
|
|
|
(entry.Step.Op() == deploy.OpCreate ||
|
|
|
|
entry.Step.Op() == deploy.OpUpdate ||
|
|
|
|
entry.Step.Op() == deploy.OpSame) {
|
|
|
|
registered = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if registered {
|
|
|
|
found := false
|
|
|
|
for _, evt := range evts {
|
|
|
|
if evt.Type == DiagEvent {
|
|
|
|
payload := evt.Payload().(DiagEventPayload)
|
|
|
|
|
|
|
|
ok := payload.Severity == "warning" &&
|
|
|
|
payload.URN.Type() == "pulumi:pulumi:StackReference" &&
|
|
|
|
strings.Contains(
|
|
|
|
payload.Message,
|
|
|
|
"The \"pulumi:pulumi:StackReference\" resource type is deprecated.")
|
|
|
|
found = found || ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.True(t, found, "diagnostic warning not found in: %+v", evts)
|
|
|
|
}
|
|
|
|
|
2024-05-06 17:34:24 +00:00
|
|
|
return v(project, target, entries, evts, err)
|
2023-12-03 08:46:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-13 20:41:01 +00:00
|
|
|
p := &TestPlan{
|
2020-12-15 22:24:46 +00:00
|
|
|
BackendClient: &deploytest.BackendClient{
|
|
|
|
GetStackOutputsF: func(ctx context.Context, name string) (resource.PropertyMap, error) {
|
|
|
|
switch name {
|
|
|
|
case "other":
|
|
|
|
return resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
}), nil
|
|
|
|
default:
|
2021-11-13 02:37:17 +00:00
|
|
|
return nil, fmt.Errorf("unknown stack \"%s\"", name)
|
2018-08-13 20:41:01 +00:00
|
|
|
}
|
|
|
|
},
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)},
|
2023-12-03 08:46:37 +00:00
|
|
|
Steps: steps,
|
2018-08-13 20:41:01 +00:00
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Test that changes to `name` cause replacement.
|
|
|
|
resURN := p.NewURN("pulumi:pulumi:StackReference", "other", "")
|
|
|
|
old := &deploy.Snapshot{
|
|
|
|
Resources: []*resource.State{
|
|
|
|
{
|
|
|
|
Type: resURN.Type(),
|
|
|
|
URN: resURN,
|
|
|
|
Custom: true,
|
|
|
|
ID: "1",
|
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other2",
|
|
|
|
}),
|
|
|
|
Outputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other2",
|
|
|
|
"outputs": resource.PropertyMap{},
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
},
|
2018-08-13 20:41:01 +00:00
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Steps = []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
for _, entry := range entries {
|
|
|
|
switch urn := entry.Step.URN(); urn {
|
|
|
|
case resURN:
|
|
|
|
switch entry.Step.Op() {
|
|
|
|
case deploy.OpCreateReplacement, deploy.OpDeleteReplaced, deploy.OpReplace:
|
|
|
|
// OK
|
|
|
|
default:
|
|
|
|
t.Fatalf("unexpected journal operation: %v", entry.Step.Op())
|
2018-08-13 20:41:01 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-14 22:32:23 +00:00
|
|
|
}
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
|
|
|
}}
|
|
|
|
p.Run(t, old)
|
2018-08-14 22:32:23 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Test that unknown stacks are handled appropriately.
|
2023-09-28 21:50:18 +00:00
|
|
|
programF = deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := mon.RegisterResource("pulumi:pulumi:StackReference", "other", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "rehto",
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
return err
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p.Options = TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Steps = []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
ExpectFailure: true,
|
|
|
|
SkipPreview: true,
|
|
|
|
}}
|
|
|
|
p.Run(t, nil)
|
2018-08-14 22:32:23 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Test that unknown properties cause errors.
|
2023-09-28 21:50:18 +00:00
|
|
|
programF = deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, mon *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := mon.RegisterResource("pulumi:pulumi:StackReference", "other", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"name": "other",
|
|
|
|
"foo": "bar",
|
|
|
|
}),
|
2018-08-14 22:32:23 +00:00
|
|
|
})
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
return err
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p.Options = TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(nil, nil, programF, loaders...)}
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Run(t, nil)
|
2018-08-14 22:32:23 +00:00
|
|
|
}
|
2018-08-20 23:41:07 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
type channelWriter struct {
|
|
|
|
channel chan []byte
|
2019-09-18 01:14:10 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func (cw *channelWriter) Write(d []byte) (int, error) {
|
|
|
|
cw.channel <- d
|
|
|
|
return len(d), nil
|
2019-09-18 01:14:10 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Tests that a failed plugin load correctly shuts down the host.
|
|
|
|
func TestLoadFailureShutdown(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
2019-09-18 01:14:10 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Note that the setup here is a bit baroque, and is intended to replicate the CLI architecture that lead to
|
|
|
|
// issue #2170. That issue--a panic on a closed channel--was caused by the intersection of several design choices:
|
|
|
|
//
|
|
|
|
// - The provider registry loads and configures the set of providers necessary for the resources currently in the
|
|
|
|
// checkpoint it is processing at plan creation time. Registry creation fails promptly if a provider plugin
|
|
|
|
// fails to load (e.g. because is binary is missing).
|
|
|
|
// - Provider configuration in the CLI's host happens asynchronously. This is meant to allow the engine to remain
|
|
|
|
// responsive while plugins configure.
|
|
|
|
// - Providers may call back into the CLI's host for logging. Callbacks are processed as long as the CLI's plugin
|
|
|
|
// context is open.
|
|
|
|
// - Log events from the CLI's host are delivered to the CLI's diagnostic streams via channels. The CLI closes
|
|
|
|
// these channels once the engine operation it initiated completes.
|
|
|
|
//
|
|
|
|
// These choices gave rise to the following situation:
|
|
|
|
// 1. The provider registry loads a provider for package A and kicks off its configuration.
|
|
|
|
// 2. The provider registry attempts to load a provider for package B. The load fails, and the provider registry
|
|
|
|
// creation call fails promptly.
|
|
|
|
// 3. The engine operation requested by the CLI fails promptly because provider registry creation failed.
|
|
|
|
// 4. The CLI shuts down its diagnostic channels.
|
|
|
|
// 5. The provider for package A calls back in to the host to log a message. The host then attempts to deliver
|
|
|
|
// the message to the CLI's diagnostic channels, causing a panic.
|
|
|
|
//
|
|
|
|
// The fix was to properly close the plugin host during step (3) s.t. the host was no longer accepting callbacks
|
|
|
|
// and would not attempt to send messages to the CLI's diagnostic channels.
|
|
|
|
//
|
|
|
|
// As such, this test attempts to replicate the CLI architecture by using one provider that configures
|
|
|
|
// asynchronously and attempts to call back into the engine and a second provider that fails to load.
|
2023-04-12 09:35:20 +00:00
|
|
|
//
|
|
|
|
// The engine architecture has changed since this issue was discovered, and the test has been updated to
|
|
|
|
// reflect that. Registry creation no longer configures providers up front, so the program below tries to
|
|
|
|
// register two providers instead.
|
2019-09-18 01:14:10 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
release, done := make(chan bool), make(chan bool)
|
|
|
|
sinkWriter := &channelWriter{channel: make(chan []byte)}
|
2018-08-23 00:52:46 +00:00
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
2020-12-15 22:24:46 +00:00
|
|
|
deploytest.NewProviderLoaderWithHost("pkgA", semver.MustParse("1.0.0"),
|
|
|
|
func(host plugin.Host) (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
ConfigureF: func(news resource.PropertyMap) error {
|
|
|
|
go func() {
|
|
|
|
<-release
|
|
|
|
host.Log(diag.Info, "", "configuring pkgA provider...", 0)
|
|
|
|
close(done)
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
deploytest.NewProviderLoader("pkgB", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return nil, errors.New("pkgB load failure")
|
2018-08-23 00:52:46 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource(providers.MakeProviderType("pkgA"), "provA", true)
|
2023-04-12 09:35:20 +00:00
|
|
|
assert.NoError(t, err)
|
2019-09-18 01:14:10 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource(providers.MakeProviderType("pkgB"), "provB", true)
|
2023-04-12 09:35:20 +00:00
|
|
|
assert.NoError(t, err)
|
2019-09-18 01:14:10 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
return nil
|
|
|
|
})
|
2018-08-23 00:52:46 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
op := TestOp(Update)
|
|
|
|
sink := diag.DefaultSink(sinkWriter, sinkWriter, diag.FormatOptions{Color: colors.Raw})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
options := TestUpdateOptions{T: t, HostF: deploytest.NewPluginHostF(sink, sink, programF, loaders...)}
|
2023-04-12 09:35:20 +00:00
|
|
|
p := &TestPlan{}
|
|
|
|
project, target := p.GetProject(), p.GetTarget(t, nil)
|
2019-09-18 01:14:10 +00:00
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err := op.Run(project, target, options, true, nil, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2019-09-18 01:14:10 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
close(sinkWriter.channel)
|
|
|
|
close(release)
|
|
|
|
<-done
|
2018-08-23 00:52:46 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestSingleResourceIgnoreChanges(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
var expectedIgnoreChanges []string
|
2019-09-18 01:14:10 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
DiffF: func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Equal(t, expectedIgnoreChanges, ignoreChanges)
|
|
|
|
return plugin.DiffResult{}, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(
|
|
|
|
urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Equal(t, expectedIgnoreChanges, ignoreChanges)
|
|
|
|
return resource.PropertyMap{}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
2019-09-18 01:14:10 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
updateProgramWithProps := func(snap *deploy.Snapshot, props resource.PropertyMap, ignoreChanges []string,
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
allowedOps []display.StepOp, name string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) *deploy.Snapshot {
|
2020-12-15 22:24:46 +00:00
|
|
|
expectedIgnoreChanges = ignoreChanges
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: props,
|
|
|
|
IgnoreChanges: ignoreChanges,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because secrets are serialized with the blinding crypter and can't be restored
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2020-12-15 22:24:46 +00:00
|
|
|
Steps: []TestStep{
|
|
|
|
{
|
|
|
|
Op: Update,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
for _, event := range events {
|
|
|
|
if event.Type == ResourcePreEvent {
|
|
|
|
payload := event.Payload().(ResourcePreEventPayload)
|
2023-11-20 21:55:59 +00:00
|
|
|
if payload.Metadata.URN == "urn:pulumi:test::test::pkgA:m:typA::resA" {
|
|
|
|
assert.Subset(t,
|
|
|
|
allowedOps, []display.StepOp{payload.Metadata.Op},
|
|
|
|
"event operation unexpected: %v", payload)
|
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
}
|
|
|
|
}
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
return p.RunWithName(t, snap, name)
|
2019-09-18 01:14:10 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
snap := updateProgramWithProps(nil, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 1,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "foo",
|
|
|
|
},
|
2023-05-25 14:57:12 +00:00
|
|
|
"d": []interface{}{1},
|
|
|
|
"e": []interface{}{1},
|
2023-12-01 19:35:37 +00:00
|
|
|
"f": map[string]interface{}{
|
|
|
|
"g": map[string]interface{}{
|
|
|
|
"h": "bar",
|
|
|
|
},
|
|
|
|
},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), []string{"a", "b.c", "d", "e[0]", "f.g[\"h\"]"}, []display.StepOp{deploy.OpCreate}, "initial")
|
2018-08-23 00:52:46 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Ensure that a change to an ignored property results in an OpSame
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 2,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "bar",
|
|
|
|
},
|
2023-05-25 14:57:12 +00:00
|
|
|
"d": []interface{}{2},
|
|
|
|
"e": []interface{}{2},
|
2023-12-01 19:35:37 +00:00
|
|
|
"f": map[string]interface{}{
|
|
|
|
"g": map[string]interface{}{
|
|
|
|
"h": "baz",
|
|
|
|
},
|
|
|
|
},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), []string{"a", "b.c", "d", "e[0]", "f.g[\"h\"]"}, []display.StepOp{deploy.OpSame}, "ignored-property")
|
2018-08-23 00:52:46 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Ensure that a change to an un-ignored property results in an OpUpdate
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 3,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "qux",
|
|
|
|
},
|
2023-05-25 14:57:12 +00:00
|
|
|
"d": []interface{}{3},
|
|
|
|
"e": []interface{}{3},
|
2023-12-01 19:35:37 +00:00
|
|
|
"f": map[string]interface{}{
|
|
|
|
"g": map[string]interface{}{
|
|
|
|
"h": "qux",
|
|
|
|
},
|
|
|
|
},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), nil, []display.StepOp{deploy.OpUpdate}, "unignored-property")
|
2020-12-15 22:24:46 +00:00
|
|
|
|
|
|
|
// Ensure that a removing an ignored property results in an OpSame
|
2023-05-25 14:57:12 +00:00
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"e": []interface{}{},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), []string{"a", "b", "d", "e", "f"}, []display.StepOp{deploy.OpSame}, "ignored-property-removed")
|
2018-08-23 00:52:46 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Ensure that a removing an un-ignored property results in an OpUpdate
|
2023-05-25 14:57:12 +00:00
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"e": []interface{}{},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), nil, []display.StepOp{deploy.OpUpdate}, "unignored-property-removed")
|
2019-03-11 20:50:00 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Ensure that adding an ignored property results in an OpSame
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 4,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "zed",
|
2019-03-11 20:50:00 +00:00
|
|
|
},
|
2023-05-25 14:57:12 +00:00
|
|
|
"d": []interface{}{4},
|
|
|
|
"e": []interface{}{},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), []string{"a", "b", "d", "e[0]", "f"}, []display.StepOp{deploy.OpSame}, "ignored-property-added")
|
2018-08-23 00:52:46 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Ensure that adding an un-ignored property results in an OpUpdate
|
2023-05-23 08:36:13 +00:00
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
2023-05-25 14:57:12 +00:00
|
|
|
"e": []interface{}{},
|
2023-12-01 19:35:37 +00:00
|
|
|
"i": 4,
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), []string{"a", "b", "d", "e", "f"}, []display.StepOp{deploy.OpUpdate}, "unignored-property-added")
|
2023-05-23 08:36:13 +00:00
|
|
|
|
|
|
|
// Ensure that sub-elements of arrays can be ignored, first reset to a simple state
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 3,
|
|
|
|
"b": []string{"foo", "bar"},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), nil, []display.StepOp{deploy.OpUpdate}, "sub-elements-ignored")
|
2023-05-23 08:36:13 +00:00
|
|
|
|
|
|
|
// Check that ignoring a specific sub-element of an array works
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 3,
|
|
|
|
"b": []string{"foo", "baz"},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), []string{"b[1]"}, []display.StepOp{deploy.OpSame}, "ignore-specific-subelement")
|
2023-05-23 08:36:13 +00:00
|
|
|
|
|
|
|
// Check that ignoring all sub-elements of an array works
|
2023-11-15 12:02:34 +00:00
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
2023-05-23 08:36:13 +00:00
|
|
|
"a": 3,
|
|
|
|
"b": []string{"foo", "baz"},
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}), []string{"b[*]"}, []display.StepOp{deploy.OpSame}, "ignore-all-subelements")
|
2023-11-15 12:02:34 +00:00
|
|
|
|
|
|
|
// Check that ignoring a secret value works, first update to make foo, bar secret
|
|
|
|
snap = updateProgramWithProps(snap, resource.PropertyMap{
|
|
|
|
"a": resource.NewNumberProperty(3),
|
|
|
|
"b": resource.MakeSecret(resource.NewArrayProperty([]resource.PropertyValue{
|
|
|
|
resource.NewStringProperty("foo"),
|
|
|
|
resource.NewStringProperty("bar"),
|
|
|
|
})),
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}, nil, []display.StepOp{deploy.OpUpdate}, "ignore-secret")
|
2023-11-15 12:02:34 +00:00
|
|
|
|
|
|
|
// Now check that changing a value (but not secretness) can be ignored
|
|
|
|
_ = updateProgramWithProps(snap, resource.PropertyMap{
|
|
|
|
"a": resource.NewNumberProperty(3),
|
|
|
|
"b": resource.MakeSecret(resource.NewArrayProperty([]resource.PropertyValue{
|
|
|
|
resource.NewStringProperty("foo"),
|
|
|
|
resource.NewStringProperty("baz"),
|
|
|
|
})),
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
}, []string{"b[1]"}, []display.StepOp{deploy.OpSame}, "change-value-not-secretness")
|
2020-12-15 22:24:46 +00:00
|
|
|
}
|
2018-08-23 00:52:46 +00:00
|
|
|
|
2022-01-11 17:20:43 +00:00
|
|
|
func TestIgnoreChangesInvalidPaths(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-01-11 17:20:43 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
program := func(monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-01-11 17:20:43 +00:00
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"foo": resource.NewObjectProperty(resource.PropertyMap{
|
|
|
|
"bar": resource.NewStringProperty("baz"),
|
|
|
|
}),
|
|
|
|
"qux": resource.NewArrayProperty([]resource.PropertyValue{
|
|
|
|
resource.NewStringProperty("zed"),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
runtimeF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2022-01-11 17:20:43 +00:00
|
|
|
return program(monitor)
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, runtimeF, loaders...)
|
2022-01-11 17:20:43 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-01-11 17:20:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-01-11 17:20:43 +00:00
|
|
|
|
|
|
|
program = func(monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-01-11 17:20:43 +00:00
|
|
|
Inputs: resource.PropertyMap{},
|
|
|
|
IgnoreChanges: []string{"foo.bar"},
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
_, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2022-01-11 17:20:43 +00:00
|
|
|
|
2023-05-25 14:57:12 +00:00
|
|
|
program = func(monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2023-05-25 14:57:12 +00:00
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"qux": resource.NewArrayProperty([]resource.PropertyValue{}),
|
|
|
|
},
|
|
|
|
IgnoreChanges: []string{"qux[0]"},
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
_, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "2")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2023-05-25 14:57:12 +00:00
|
|
|
|
2022-01-11 17:20:43 +00:00
|
|
|
program = func(monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-01-11 17:20:43 +00:00
|
|
|
Inputs: resource.PropertyMap{},
|
|
|
|
IgnoreChanges: []string{"qux[0]"},
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
_, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "3")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2023-05-23 08:36:13 +00:00
|
|
|
|
|
|
|
program = func(monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2023-05-23 08:36:13 +00:00
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"qux": resource.NewArrayProperty([]resource.PropertyValue{
|
|
|
|
resource.NewStringProperty("zed"),
|
|
|
|
resource.NewStringProperty("zob"),
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
IgnoreChanges: []string{"qux[1]"},
|
|
|
|
})
|
|
|
|
assert.Error(t, err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
_, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "4")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2022-01-11 17:20:43 +00:00
|
|
|
}
|
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
type DiffFunc = func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string) (plugin.DiffResult, error)
|
2021-07-01 19:32:08 +00:00
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
func replaceOnChangesTest(t *testing.T, name string, diffFunc DiffFunc) {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
DiffF: diffFunc,
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2021-11-30 20:25:27 +00:00
|
|
|
return resource.ID("id123"), inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
2021-07-01 19:32:08 +00:00
|
|
|
}
|
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
updateProgramWithProps := func(snap *deploy.Snapshot, props resource.PropertyMap, replaceOnChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
allowedOps []display.StepOp,
|
|
|
|
) *deploy.Snapshot {
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2021-11-30 20:25:27 +00:00
|
|
|
Inputs: props,
|
|
|
|
ReplaceOnChanges: replaceOnChanges,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
2021-07-01 19:32:08 +00:00
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2021-11-30 20:25:27 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2021-11-30 20:25:27 +00:00
|
|
|
Steps: []TestStep{
|
|
|
|
{
|
|
|
|
Op: Update,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2021-11-30 20:25:27 +00:00
|
|
|
for _, event := range events {
|
|
|
|
if event.Type == ResourcePreEvent {
|
|
|
|
payload := event.Payload().(ResourcePreEventPayload)
|
2023-11-20 21:55:59 +00:00
|
|
|
// Ignore any events for default providers
|
|
|
|
if !payload.Internal {
|
|
|
|
assert.Subset(t, allowedOps, []display.StepOp{payload.Metadata.Op})
|
|
|
|
}
|
2021-11-30 20:25:27 +00:00
|
|
|
}
|
2021-07-01 19:32:08 +00:00
|
|
|
}
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2021-11-30 20:25:27 +00:00
|
|
|
},
|
2021-07-01 19:32:08 +00:00
|
|
|
},
|
|
|
|
},
|
2021-11-30 20:25:27 +00:00
|
|
|
}
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
return p.RunWithName(t, snap, strings.ReplaceAll(fmt.Sprintf("%v", props), " ", "_"))
|
2021-07-01 19:32:08 +00:00
|
|
|
}
|
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
snap := updateProgramWithProps(nil, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 1,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "foo",
|
|
|
|
},
|
2022-06-27 14:08:06 +00:00
|
|
|
}), []string{"a", "b.c"}, []display.StepOp{deploy.OpCreate})
|
2021-07-01 19:32:08 +00:00
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
// Ensure that a change to a replaceOnChange property results in an OpReplace
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 2,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "foo",
|
|
|
|
},
|
2022-06-27 14:08:06 +00:00
|
|
|
}), []string{"a"}, []display.StepOp{deploy.OpReplace, deploy.OpCreateReplacement, deploy.OpDeleteReplaced})
|
2021-07-01 19:32:08 +00:00
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
// Ensure that a change to a nested replaceOnChange property results in an OpReplace
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 2,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "bar",
|
|
|
|
},
|
2022-06-27 14:08:06 +00:00
|
|
|
}), []string{"b.c"}, []display.StepOp{deploy.OpReplace, deploy.OpCreateReplacement, deploy.OpDeleteReplaced})
|
2021-07-01 19:32:08 +00:00
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
// Ensure that a change to any property of a "*" replaceOnChange results in an OpReplace
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 3,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "baz",
|
|
|
|
},
|
2022-06-27 14:08:06 +00:00
|
|
|
}), []string{"*"}, []display.StepOp{deploy.OpReplace, deploy.OpCreateReplacement, deploy.OpDeleteReplaced})
|
2021-07-01 19:32:08 +00:00
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
// Ensure that a change to an non-replaceOnChange property results in an OpUpdate
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 4,
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "qux",
|
|
|
|
},
|
2022-06-27 14:08:06 +00:00
|
|
|
}), nil, []display.StepOp{deploy.OpUpdate})
|
2021-11-30 20:25:27 +00:00
|
|
|
|
|
|
|
// We ensure that we are listing to the engine diff function only when the provider function
|
|
|
|
// is nil. We do this by adding some weirdness to the provider diff function.
|
2022-06-27 14:08:06 +00:00
|
|
|
allowed := []display.StepOp{deploy.OpCreateReplacement, deploy.OpReplace, deploy.OpDeleteReplaced}
|
2021-11-30 20:25:27 +00:00
|
|
|
if diffFunc != nil {
|
2022-06-27 14:08:06 +00:00
|
|
|
allowed = []display.StepOp{deploy.OpSame}
|
2021-11-30 20:25:27 +00:00
|
|
|
}
|
|
|
|
snap = updateProgramWithProps(snap, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"a": 42, // 42 is a special value in the "provider" diff function.
|
|
|
|
"b": map[string]interface{}{
|
|
|
|
"c": "qux",
|
|
|
|
},
|
|
|
|
}), []string{"a"}, allowed)
|
|
|
|
|
|
|
|
_ = snap
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReplaceOnChanges(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
2021-11-30 20:25:27 +00:00
|
|
|
|
|
|
|
// We simulate a provider that has it's own diff function.
|
|
|
|
replaceOnChangesTest(t, "provider diff",
|
|
|
|
func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2021-11-30 20:25:27 +00:00
|
|
|
// To establish a observable difference between the provider and engine diff function,
|
|
|
|
// we treat 42 as an OpSame. We use this to check that the right diff function is being
|
|
|
|
// used.
|
2023-05-29 15:41:36 +00:00
|
|
|
for k, v := range newInputs {
|
2021-11-30 20:25:27 +00:00
|
|
|
if v == resource.NewNumberProperty(42) {
|
2023-05-29 15:41:36 +00:00
|
|
|
newInputs[k] = oldOutputs[k]
|
2021-11-30 20:25:27 +00:00
|
|
|
}
|
|
|
|
}
|
2023-05-29 15:41:36 +00:00
|
|
|
diff := oldOutputs.Diff(newInputs)
|
2021-11-30 20:25:27 +00:00
|
|
|
if diff == nil {
|
|
|
|
return plugin.DiffResult{Changes: plugin.DiffNone}, nil
|
|
|
|
}
|
2023-10-18 10:33:04 +00:00
|
|
|
detailedDiff := plugin.NewDetailedDiffFromObjectDiff(diff, false)
|
2021-11-30 20:25:27 +00:00
|
|
|
changedKeys := diff.ChangedKeys()
|
|
|
|
|
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ChangedKeys: changedKeys,
|
|
|
|
DetailedDiff: detailedDiff,
|
|
|
|
}, nil
|
|
|
|
})
|
2021-07-01 19:32:08 +00:00
|
|
|
|
2021-11-30 20:25:27 +00:00
|
|
|
// We simulate a provider that does not have it's own diff function. This tests the engines diff
|
|
|
|
// function instead.
|
|
|
|
replaceOnChangesTest(t, "engine diff", nil)
|
2021-07-01 19:32:08 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestPersistentDiff(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-03-02 21:59:11 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2020-12-15 22:24:46 +00:00
|
|
|
DiffF: func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return plugin.DiffResult{Changes: plugin.DiffSome}, nil
|
2020-03-02 21:59:11 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
inputs := resource.PropertyMap{}
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: inputs,
|
2020-03-02 21:59:11 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-03-02 21:59:11 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
}
|
|
|
|
resURN := p.NewURN("pkgA:m:typA", "resA", "")
|
2020-03-02 21:59:11 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Run the initial update.
|
|
|
|
project := p.GetProject()
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-03-02 21:59:11 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// First, make no change to the inputs and run a preview. We should see an update to the resource due to
|
|
|
|
// provider diffing.
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, true, p.BackendClient,
|
2020-12-15 22:24:46 +00:00
|
|
|
func(_ workspace.Project, _ deploy.Target, _ JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
found := false
|
|
|
|
for _, e := range events {
|
|
|
|
if e.Type == ResourcePreEvent {
|
|
|
|
p := e.Payload().(ResourcePreEventPayload).Metadata
|
|
|
|
if p.URN == resURN {
|
|
|
|
assert.Equal(t, deploy.OpUpdate, p.Op)
|
|
|
|
found = true
|
2020-03-02 21:59:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, found)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
})
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
|
|
|
|
// Next, enable legacy diff behavior. We should see no changes to the resource.
|
|
|
|
p.Options.UseLegacyDiff = true
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, true, p.BackendClient,
|
2020-12-15 22:24:46 +00:00
|
|
|
func(_ workspace.Project, _ deploy.Target, _ JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
found := false
|
|
|
|
for _, e := range events {
|
|
|
|
if e.Type == ResourcePreEvent {
|
|
|
|
p := e.Payload().(ResourcePreEventPayload).Metadata
|
|
|
|
if p.URN == resURN {
|
|
|
|
assert.Equal(t, deploy.OpSame, p.Op)
|
|
|
|
found = true
|
2020-03-02 21:59:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, found)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
})
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
}
|
2020-03-02 21:59:11 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestDetailedDiffReplace(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
DiffF: func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
DetailedDiff: map[string]plugin.PropertyDiff{
|
|
|
|
"prop": {Kind: plugin.DiffAddReplace},
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
inputs := resource.PropertyMap{}
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: inputs,
|
2020-03-02 21:59:11 +00:00
|
|
|
})
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
2020-03-02 21:59:11 +00:00
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-03-02 21:59:11 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-03-02 21:59:11 +00:00
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
resURN := p.NewURN("pkgA:m:typA", "resA", "")
|
2020-03-02 21:59:11 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Run the initial update.
|
|
|
|
project := p.GetProject()
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
|
|
|
|
// First, make no change to the inputs and run a preview. We should see an update to the resource due to
|
|
|
|
// provider diffing.
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, true, p.BackendClient,
|
2020-12-15 22:24:46 +00:00
|
|
|
func(_ workspace.Project, _ deploy.Target, _ JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
found := false
|
|
|
|
for _, e := range events {
|
|
|
|
if e.Type == ResourcePreEvent {
|
|
|
|
p := e.Payload().(ResourcePreEventPayload).Metadata
|
|
|
|
if p.URN == resURN && p.Op == deploy.OpReplace {
|
|
|
|
found = true
|
|
|
|
}
|
2020-03-02 21:59:11 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, found)
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2020-12-15 22:24:46 +00:00
|
|
|
})
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-03-02 21:59:11 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestCustomTimeouts(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2019-11-19 00:47:19 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return &deploytest.Provider{}, nil
|
2019-11-19 00:47:19 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
CustomTimeouts: &resource.CustomTimeouts{
|
|
|
|
Create: 60, Delete: 60, Update: 240,
|
|
|
|
},
|
2019-11-19 00:47:19 +00:00
|
|
|
})
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2019-11-19 00:47:19 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2019-11-19 00:47:19 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Steps = []TestStep{{Op: Update}}
|
|
|
|
snap := p.Run(t, nil)
|
2019-11-19 00:47:19 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Len(t, snap.Resources, 2)
|
2023-11-20 08:59:00 +00:00
|
|
|
assert.Equal(t, snap.Resources[0].URN.Name(), "default")
|
|
|
|
assert.Equal(t, snap.Resources[1].URN.Name(), "resA")
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.NotNil(t, snap.Resources[1].CustomTimeouts)
|
|
|
|
assert.Equal(t, snap.Resources[1].CustomTimeouts.Create, float64(60))
|
|
|
|
assert.Equal(t, snap.Resources[1].CustomTimeouts.Update, float64(240))
|
|
|
|
assert.Equal(t, snap.Resources[1].CustomTimeouts.Delete, float64(60))
|
2019-11-19 00:47:19 +00:00
|
|
|
}
|
2019-11-25 22:10:06 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestProviderDiffMissingOldOutputs(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2019-11-25 22:10:06 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2023-05-29 15:41:36 +00:00
|
|
|
DiffConfigF: func(urn resource.URN, oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
ignoreChanges []string,
|
|
|
|
) (plugin.DiffResult, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
// Always require replacement if any diff exists.
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs.DeepEquals(newInputs) {
|
2020-12-15 22:24:46 +00:00
|
|
|
keys := []resource.PropertyKey{}
|
2023-05-29 15:41:36 +00:00
|
|
|
for k := range newInputs {
|
2020-12-15 22:24:46 +00:00
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
return plugin.DiffResult{Changes: plugin.DiffSome, ReplaceKeys: keys}, nil
|
2019-11-25 22:10:06 +00:00
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
return plugin.DiffResult{Changes: plugin.DiffNone}, nil
|
2019-11-25 22:10:06 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2019-11-25 22:10:06 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
return nil
|
2019-11-25 22:10:06 +00:00
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2019-11-25 22:10:06 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
Config: config.Map{
|
|
|
|
config.MustMakeKey("pkgA", "foo"): config.NewValue("bar"),
|
|
|
|
},
|
|
|
|
}
|
2019-11-25 22:10:06 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Build a basic lifecycle.
|
|
|
|
steps := MakeBasicLifecycleSteps(t, 2)
|
2019-11-25 22:10:06 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Run the lifecycle through its initial update and refresh.
|
|
|
|
p.Steps = steps[:2]
|
|
|
|
snap := p.Run(t, nil)
|
2019-11-25 22:10:06 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Delete the old provider outputs (if any) from the checkpoint, then run the no-op update.
|
|
|
|
providerURN := p.NewProviderURN("pkgA", "default", "")
|
|
|
|
for _, r := range snap.Resources {
|
|
|
|
if r.URN == providerURN {
|
|
|
|
r.Outputs = nil
|
|
|
|
}
|
|
|
|
}
|
2019-11-25 22:10:06 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Steps = steps[2:3]
|
2019-11-25 22:10:06 +00:00
|
|
|
snap = p.Run(t, snap)
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Change the config, delete the old provider outputs, and run an update. We expect everything to require
|
|
|
|
// replacement.
|
|
|
|
p.Config[config.MustMakeKey("pkgA", "foo")] = config.NewValue("baz")
|
|
|
|
for _, r := range snap.Resources {
|
|
|
|
if r.URN == providerURN {
|
|
|
|
r.Outputs = nil
|
|
|
|
}
|
|
|
|
}
|
2019-11-25 22:10:06 +00:00
|
|
|
p.Steps = []TestStep{{
|
|
|
|
Op: Update,
|
2020-10-15 17:35:09 +00:00
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
_ []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
resURN := p.NewURN("pkgA:m:typA", "resA", "")
|
|
|
|
|
|
|
|
// Look for replace steps on the provider and the resource.
|
|
|
|
replacedProvider, replacedResource := false, false
|
|
|
|
for _, entry := range entries {
|
|
|
|
if entry.Kind != JournalEntrySuccess || entry.Step.Op() != deploy.OpDeleteReplaced {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
switch urn := entry.Step.URN(); urn {
|
|
|
|
case providerURN:
|
|
|
|
replacedProvider = true
|
|
|
|
case resURN:
|
|
|
|
replacedResource = true
|
|
|
|
default:
|
|
|
|
t.Fatalf("unexpected resource %v", urn)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.True(t, replacedProvider)
|
|
|
|
assert.True(t, replacedResource)
|
2019-11-25 22:10:06 +00:00
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2019-11-25 22:10:06 +00:00
|
|
|
},
|
|
|
|
}}
|
|
|
|
p.Run(t, snap)
|
|
|
|
}
|
2019-11-25 23:31:12 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestMissingRead(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2019-11-25 23:31:12 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2020-12-15 22:24:46 +00:00
|
|
|
ReadF: func(_ resource.URN, _ resource.ID, _, _ resource.PropertyMap) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
return plugin.ReadResult{}, resource.StatusOK, nil
|
2019-11-25 23:31:12 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
// Our program reads a resource and exits.
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
_, _, err := monitor.ReadResource("pkgA:m:typA", "resA", "resA-some-id", "", resource.PropertyMap{}, "", "", "")
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Error(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-12-15 22:24:46 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-15 22:24:46 +00:00
|
|
|
Steps: []TestStep{{Op: Update, ExpectFailure: true}},
|
2019-11-25 23:31:12 +00:00
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
p.Run(t, nil)
|
2019-11-25 23:31:12 +00:00
|
|
|
}
|
2019-11-26 21:23:34 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
func TestProviderPreview(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
sawPreview := false
|
2019-11-26 21:23:34 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
return &deploytest.Provider{
|
2020-10-09 20:13:55 +00:00
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
if preview {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
2019-11-26 21:23:34 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.Equal(t, preview, news.ContainsUnknowns())
|
2019-11-26 21:23:34 +00:00
|
|
|
return "created-id", news, resource.StatusOK, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
2020-12-15 22:24:46 +00:00
|
|
|
if preview {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
|
|
|
|
2023-05-29 15:41:36 +00:00
|
|
|
assert.Equal(t, preview, newInputs.ContainsUnknowns())
|
|
|
|
return newInputs, resource.StatusOK, nil
|
2019-11-26 21:23:34 +00:00
|
|
|
},
|
2020-12-15 22:24:46 +00:00
|
|
|
}, nil
|
2019-11-26 21:23:34 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
preview := true
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2020-12-15 22:24:46 +00:00
|
|
|
computed := interface{}(resource.Computed{Element: resource.NewStringProperty("")})
|
|
|
|
if !preview {
|
|
|
|
computed = "alpha"
|
|
|
|
}
|
2019-11-26 21:23:34 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"baz": map[string]interface{}{
|
|
|
|
"a": 42,
|
|
|
|
"b": computed,
|
|
|
|
},
|
|
|
|
"qux": []interface{}{
|
|
|
|
computed,
|
|
|
|
24,
|
|
|
|
},
|
|
|
|
"zed": computed,
|
|
|
|
})
|
2019-11-26 21:23:34 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-15 22:24:46 +00:00
|
|
|
Inputs: ins,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2019-11-26 21:23:34 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.True(t, resp.Outputs.DeepEquals(ins))
|
2019-11-26 21:23:34 +00:00
|
|
|
|
2020-12-15 22:24:46 +00:00
|
|
|
return nil
|
2019-11-26 21:23:34 +00:00
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2019-11-26 21:23:34 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2019-11-26 21:23:34 +00:00
|
|
|
}
|
2020-12-15 22:24:46 +00:00
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run a preview. The inputs should be propagated to the outputs by the provider during the create.
|
|
|
|
preview, sawPreview = true, false
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-23 21:25:48 +00:00
|
|
|
assert.True(t, sawPreview)
|
|
|
|
|
|
|
|
// Run an update.
|
|
|
|
preview, sawPreview = false, false
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-23 21:25:48 +00:00
|
|
|
assert.False(t, sawPreview)
|
|
|
|
|
|
|
|
// Run another preview. The inputs should be propagated to the outputs during the update.
|
|
|
|
preview, sawPreview = true, false
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-23 21:25:48 +00:00
|
|
|
assert.True(t, sawPreview)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProviderPreviewGrpc(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-23 21:25:48 +00:00
|
|
|
sawPreview := false
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2020-12-23 21:25:48 +00:00
|
|
|
if preview {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Equal(t, preview, news.ContainsUnknowns())
|
|
|
|
return "created-id", news, resource.StatusOK, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
2020-12-23 21:25:48 +00:00
|
|
|
if preview {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
|
|
|
|
2023-05-29 15:41:36 +00:00
|
|
|
assert.Equal(t, preview, newInputs.ContainsUnknowns())
|
|
|
|
return newInputs, resource.StatusOK, nil
|
2020-12-23 21:25:48 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, deploytest.WithGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
preview := true
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2020-12-23 21:25:48 +00:00
|
|
|
computed := interface{}(resource.Computed{Element: resource.NewStringProperty("")})
|
|
|
|
if !preview {
|
|
|
|
computed = "alpha"
|
|
|
|
}
|
|
|
|
|
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"baz": map[string]interface{}{
|
|
|
|
"a": 42,
|
|
|
|
"b": computed,
|
|
|
|
},
|
|
|
|
"qux": []interface{}{
|
|
|
|
computed,
|
|
|
|
24,
|
|
|
|
},
|
|
|
|
"zed": computed,
|
|
|
|
})
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2020-12-23 21:25:48 +00:00
|
|
|
Inputs: ins,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.True(t, resp.Outputs.DeepEquals(ins))
|
2020-12-23 21:25:48 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-12-23 21:25:48 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-23 21:25:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run a preview. The inputs should be propagated to the outputs by the provider during the create.
|
|
|
|
preview, sawPreview = true, false
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, sawPreview)
|
|
|
|
|
|
|
|
// Run an update.
|
|
|
|
preview, sawPreview = false, false
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.False(t, sawPreview)
|
|
|
|
|
|
|
|
// Run another preview. The inputs should be propagated to the outputs during the update.
|
|
|
|
preview, sawPreview = true, false
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-12-15 22:24:46 +00:00
|
|
|
assert.True(t, sawPreview)
|
2019-11-26 21:23:34 +00:00
|
|
|
}
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
|
2021-08-11 00:44:15 +00:00
|
|
|
func TestProviderPreviewUnknowns(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2021-08-11 00:44:15 +00:00
|
|
|
sawPreview := false
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
2023-07-25 07:56:37 +00:00
|
|
|
// NOTE: it is important that this test uses a gRPC-wrapped provider. The code that handles previews for unconfigured
|
2021-08-11 00:44:15 +00:00
|
|
|
// providers is specific to the gRPC layer.
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2023-11-17 14:38:37 +00:00
|
|
|
InvokeF: func(
|
|
|
|
tok tokens.ModuleMember, inputs resource.PropertyMap,
|
|
|
|
) (resource.PropertyMap, []plugin.CheckFailure, error) {
|
|
|
|
name := inputs["name"]
|
|
|
|
ret := "unexpected"
|
|
|
|
if name.IsString() {
|
|
|
|
ret = "Hello, " + name.StringValue() + "!"
|
|
|
|
}
|
|
|
|
|
|
|
|
return resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"message": ret,
|
|
|
|
}), nil, nil
|
|
|
|
},
|
2021-08-11 00:44:15 +00:00
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2021-08-11 00:44:15 +00:00
|
|
|
if preview {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return "created-id", news, resource.StatusOK, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
2021-08-11 00:44:15 +00:00
|
|
|
if preview {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
|
|
|
|
2023-05-29 15:41:36 +00:00
|
|
|
return newInputs, resource.StatusOK, nil
|
2021-08-11 00:44:15 +00:00
|
|
|
},
|
2023-11-17 14:38:37 +00:00
|
|
|
CallF: func(monitor *deploytest.ResourceMonitor, tok tokens.ModuleMember,
|
|
|
|
args resource.PropertyMap, info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
|
|
|
if info.DryRun {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
|
|
|
|
2024-02-21 09:15:38 +00:00
|
|
|
assert.Equal(t, []resource.URN{"urn:pulumi:test::test::pkgA:m:typB::resB"}, options.ArgDependencies["name"])
|
|
|
|
|
2023-11-17 14:38:37 +00:00
|
|
|
ret := "unexpected"
|
|
|
|
if args["name"].IsString() {
|
|
|
|
ret = "Hello, " + args["name"].StringValue() + "!"
|
|
|
|
}
|
|
|
|
|
|
|
|
return plugin.CallResult{
|
|
|
|
Return: resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"message": ret,
|
|
|
|
}),
|
|
|
|
}, nil
|
|
|
|
},
|
2023-07-25 07:56:37 +00:00
|
|
|
ConstructF: func(monitor *deploytest.ResourceMonitor,
|
|
|
|
typ string, name string, parent resource.URN,
|
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
|
|
|
) (plugin.ConstructResult, error) {
|
|
|
|
if info.DryRun {
|
|
|
|
sawPreview = true
|
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{
|
2023-07-25 07:56:37 +00:00
|
|
|
Parent: parent,
|
2024-01-26 18:29:22 +00:00
|
|
|
Aliases: aliasesFromAliases(options.Aliases),
|
2023-07-25 07:56:37 +00:00
|
|
|
Protect: options.Protect,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typB", name+"-resB", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
2023-07-25 07:56:37 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
outs := resource.PropertyMap{"foo": inputs["name"]}
|
2024-04-19 11:08:56 +00:00
|
|
|
err = monitor.RegisterResourceOutputs(resp.URN, outs)
|
2023-07-25 07:56:37 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2023-07-25 07:56:37 +00:00
|
|
|
Outputs: outs,
|
|
|
|
}, nil
|
|
|
|
},
|
2021-08-11 00:44:15 +00:00
|
|
|
}, nil
|
|
|
|
}, deploytest.WithGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
preview := true
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2021-08-11 00:44:15 +00:00
|
|
|
computed := interface{}(resource.Computed{Element: resource.NewStringProperty("")})
|
|
|
|
if !preview {
|
|
|
|
computed = "alpha"
|
|
|
|
}
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pulumi:providers:pkgA", "provA", true,
|
2021-08-11 00:44:15 +00:00
|
|
|
deploytest.ResourceOptions{
|
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{"foo": computed}),
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
provID := resp.ID
|
2023-07-25 07:56:37 +00:00
|
|
|
if provID == "" {
|
|
|
|
provID = providers.UnknownID
|
|
|
|
}
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
provRef, err := providers.NewReference(resp.URN, provID)
|
2023-07-25 07:56:37 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2021-08-11 00:44:15 +00:00
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"baz": map[string]interface{}{
|
|
|
|
"a": 42,
|
|
|
|
},
|
|
|
|
"qux": []interface{}{
|
|
|
|
24,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err = monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2021-08-11 00:44:15 +00:00
|
|
|
Inputs: ins,
|
2023-07-25 07:56:37 +00:00
|
|
|
Provider: provRef.String(),
|
2021-08-11 00:44:15 +00:00
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
if preview {
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.True(t, resp.Outputs.DeepEquals(resource.PropertyMap{}))
|
2021-08-11 00:44:15 +00:00
|
|
|
} else {
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.True(t, resp.Outputs.DeepEquals(ins))
|
2021-08-11 00:44:15 +00:00
|
|
|
}
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
respC, err := monitor.RegisterResource("pkgA:m:typB", "resB", false, deploytest.ResourceOptions{
|
2023-07-25 07:56:37 +00:00
|
|
|
Inputs: resource.PropertyMap{
|
2024-04-19 11:08:56 +00:00
|
|
|
"name": resp.Outputs["foo"],
|
2023-07-25 07:56:37 +00:00
|
|
|
},
|
|
|
|
Remote: true,
|
|
|
|
Provider: provRef.String(),
|
|
|
|
})
|
|
|
|
if preview {
|
|
|
|
// We expect construction of remote component resources to fail during previews if the provider is
|
|
|
|
// configured with unknowns.
|
|
|
|
assert.ErrorContains(t, err, "cannot construct components if the provider is configured with unknown values")
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.Nil(t, respC)
|
2023-07-25 07:56:37 +00:00
|
|
|
} else {
|
|
|
|
assert.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.True(t, respC.Outputs.DeepEquals(resource.PropertyMap{
|
2023-07-25 07:56:37 +00:00
|
|
|
"foo": resource.NewStringProperty("bar"),
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2024-02-21 09:15:38 +00:00
|
|
|
var outs resource.PropertyMap
|
|
|
|
if preview {
|
|
|
|
// We can't send any args or dependencies in preview because the RegisterResource call above failed.
|
|
|
|
outs, _, _, err = monitor.Call("pkgA:m:typA/methodA", nil, nil, provRef.String(), "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
} else {
|
|
|
|
outs, _, _, err = monitor.Call("pkgA:m:typA/methodA", resource.PropertyMap{
|
2024-04-19 11:08:56 +00:00
|
|
|
"name": respC.Outputs["foo"],
|
2024-02-21 09:15:38 +00:00
|
|
|
}, map[resource.PropertyKey][]resource.URN{
|
2024-04-19 11:08:56 +00:00
|
|
|
"name": {respC.URN},
|
2024-02-21 09:15:38 +00:00
|
|
|
}, provRef.String(), "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
2023-11-17 14:38:37 +00:00
|
|
|
if preview {
|
|
|
|
assert.True(t, outs.DeepEquals(resource.PropertyMap{}), "outs was %v", outs)
|
|
|
|
} else {
|
|
|
|
assert.True(t, outs.DeepEquals(resource.PropertyMap{
|
|
|
|
"message": resource.NewStringProperty("Hello, bar!"),
|
|
|
|
}), "outs was %v", outs)
|
|
|
|
}
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
if preview {
|
|
|
|
outs, _, err = monitor.Invoke("pkgA:m:invokeA", resource.PropertyMap{
|
|
|
|
"name": resource.PropertyValue{},
|
|
|
|
}, provRef.String(), "")
|
|
|
|
} else {
|
|
|
|
outs, _, err = monitor.Invoke("pkgA:m:invokeA", resource.PropertyMap{
|
|
|
|
"name": respC.Outputs["foo"],
|
|
|
|
}, provRef.String(), "")
|
|
|
|
}
|
2023-11-17 14:38:37 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
if preview {
|
|
|
|
assert.True(t, outs.DeepEquals(resource.PropertyMap{}), "outs was %v", outs)
|
|
|
|
} else {
|
|
|
|
assert.True(t, outs.DeepEquals(resource.PropertyMap{
|
|
|
|
"message": resource.NewStringProperty("Hello, bar!"),
|
|
|
|
}), "outs was %v", outs)
|
|
|
|
}
|
|
|
|
|
2021-08-11 00:44:15 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2021-08-11 00:44:15 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2021-08-11 00:44:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run a preview. The inputs should not be propagated to the outputs by the provider during the create because the
|
|
|
|
// provider has unknown inputs.
|
|
|
|
preview, sawPreview = true, false
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
require.NoError(t, err)
|
2021-08-11 00:44:15 +00:00
|
|
|
assert.False(t, sawPreview)
|
|
|
|
|
|
|
|
// Run an update.
|
|
|
|
preview, sawPreview = false, false
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
require.NoError(t, err)
|
2021-08-11 00:44:15 +00:00
|
|
|
assert.False(t, sawPreview)
|
|
|
|
|
|
|
|
// Run another preview. The inputs should not be propagated to the outputs during the update because the provider
|
|
|
|
// has unknown inputs.
|
|
|
|
preview, sawPreview = true, false
|
2023-10-11 14:44:09 +00:00
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, preview, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
require.NoError(t, err)
|
2021-08-11 00:44:15 +00:00
|
|
|
assert.False(t, sawPreview)
|
|
|
|
}
|
|
|
|
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
func TestSingleComponentDefaultProviderLifecycle(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
construct := func(monitor *deploytest.ResourceMonitor,
|
|
|
|
typ, name string, parent resource.URN, inputs resource.PropertyMap,
|
2023-07-25 08:03:46 +00:00
|
|
|
info plugin.ConstructInfo, options plugin.ConstructOptions,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.ConstructResult, error) {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{
|
2022-06-29 12:18:14 +00:00
|
|
|
Parent: parent,
|
2024-01-26 18:29:22 +00:00
|
|
|
Aliases: aliasesFromAliases(options.Aliases),
|
2022-06-29 12:18:14 +00:00
|
|
|
Protect: options.Protect,
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typB", "resA", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
outs := resource.PropertyMap{"foo": resource.NewStringProperty("bar")}
|
2024-04-19 11:08:56 +00:00
|
|
|
err = monitor.RegisterResourceOutputs(resp.URN, outs)
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
Outputs: outs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &deploytest.Provider{
|
|
|
|
ConstructF: construct,
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
Remote: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.NewStringProperty("bar"),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
|
2020-10-27 17:12:12 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because different ordering makes the colouring different.
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
Initial support for remote component construction. (#5280)
These changes add initial support for the construction of remote
components. For now, this support is limited to the NodeJS SDK;
follow-up changes will implement support for the other SDKs.
Remote components are component resources that are constructed and
managed by plugins rather than by Pulumi programs. In this sense, they
are a bit like cloud resources, and are supported by the same
distribution and plugin loading mechanisms and described by the same
schema system.
The construction of a remote component is initiated by a
`RegisterResourceRequest` with the new `remote` field set to `true`.
When the resource monitor receives such a request, it loads the plugin
that implements the component resource and calls the `Construct`
method added to the resource provider interface as part of these
changes. This method accepts the information necessary to construct the
component and its children: the component's name, type, resource
options, inputs, and input dependencies. It is responsible for
dispatching to the appropriate component factory to create the
component, then returning its URN, resolved output properties, and
output property dependencies. The dependency information is necessary to
support features such as delete-before-replace, which rely on precise
dependency information for custom resources.
These changes also add initial support for more conveniently
implementing resource providers in NodeJS. The interface used to
implement such a provider is similar to the dynamic provider interface
(and may be unified with that interface in the future).
An example of a NodeJS program constructing a remote component resource
also implemented in NodeJS can be found in
`tests/construct_component/nodejs`.
This is the core of #2430.
2020-09-08 02:33:55 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 3),
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
2020-09-15 00:40:17 +00:00
|
|
|
|
|
|
|
type updateContext struct {
|
2022-12-14 19:20:26 +00:00
|
|
|
pulumirpc.UnimplementedLanguageRuntimeServer
|
|
|
|
|
2020-09-15 00:40:17 +00:00
|
|
|
*deploytest.ResourceMonitor
|
|
|
|
|
|
|
|
resmon chan *deploytest.ResourceMonitor
|
|
|
|
programErr chan error
|
|
|
|
snap chan *deploy.Snapshot
|
2023-10-11 14:44:09 +00:00
|
|
|
updateResult chan error
|
2020-09-15 00:40:17 +00:00
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
func startUpdate(t *testing.T, hostF deploytest.PluginHostFactory) (*updateContext, error) {
|
2020-09-15 00:40:17 +00:00
|
|
|
ctx := &updateContext{
|
|
|
|
resmon: make(chan *deploytest.ResourceMonitor),
|
|
|
|
programErr: make(chan error),
|
|
|
|
snap: make(chan *deploy.Snapshot),
|
2023-10-11 14:44:09 +00:00
|
|
|
updateResult: make(chan error),
|
2020-09-15 00:40:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
stop := make(chan bool)
|
|
|
|
port, _, err := rpcutil.Serve(0, stop, []func(*grpc.Server) error{
|
|
|
|
func(srv *grpc.Server) error {
|
|
|
|
pulumirpc.RegisterLanguageRuntimeServer(srv, ctx)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}, nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-09-15 00:40:17 +00:00
|
|
|
Runtime: "client",
|
|
|
|
RuntimeOptions: map[string]interface{}{
|
|
|
|
"address": fmt.Sprintf("127.0.0.1:%d", port),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(p.GetProject(), p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2020-09-15 00:40:17 +00:00
|
|
|
ctx.snap <- snap
|
|
|
|
close(ctx.snap)
|
2023-10-11 14:44:09 +00:00
|
|
|
ctx.updateResult <- err
|
2020-09-15 00:40:17 +00:00
|
|
|
close(ctx.updateResult)
|
|
|
|
stop <- true
|
|
|
|
}()
|
|
|
|
|
|
|
|
ctx.ResourceMonitor = <-ctx.resmon
|
|
|
|
return ctx, nil
|
|
|
|
}
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
func (ctx *updateContext) Finish(err error) (*deploy.Snapshot, error) {
|
2020-09-15 00:40:17 +00:00
|
|
|
ctx.programErr <- err
|
|
|
|
close(ctx.programErr)
|
|
|
|
|
|
|
|
return <-ctx.snap, <-ctx.updateResult
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ctx *updateContext) GetRequiredPlugins(_ context.Context,
|
2023-03-03 16:36:39 +00:00
|
|
|
req *pulumirpc.GetRequiredPluginsRequest,
|
|
|
|
) (*pulumirpc.GetRequiredPluginsResponse, error) {
|
2020-09-15 00:40:17 +00:00
|
|
|
return &pulumirpc.GetRequiredPluginsResponse{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ctx *updateContext) Run(_ context.Context, req *pulumirpc.RunRequest) (*pulumirpc.RunResponse, error) {
|
|
|
|
// Connect to the resource monitor and create an appropriate client.
|
|
|
|
conn, err := grpc.Dial(
|
|
|
|
req.MonitorAddress,
|
2023-01-11 19:54:31 +00:00
|
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
2020-09-15 00:40:17 +00:00
|
|
|
rpcutil.GrpcChannelOptions(),
|
|
|
|
)
|
|
|
|
if err != nil {
|
2021-11-13 02:37:17 +00:00
|
|
|
return nil, fmt.Errorf("could not connect to resource monitor: %w", err)
|
2020-09-15 00:40:17 +00:00
|
|
|
}
|
|
|
|
defer contract.IgnoreClose(conn)
|
|
|
|
|
|
|
|
// Fire up a resource monitor client
|
|
|
|
ctx.resmon <- deploytest.NewResourceMonitor(pulumirpc.NewResourceMonitorClient(conn))
|
|
|
|
close(ctx.resmon)
|
|
|
|
|
|
|
|
// Wait for the program to terminate.
|
|
|
|
if err := <-ctx.programErr; err != nil {
|
|
|
|
return &pulumirpc.RunResponse{Error: err.Error()}, nil
|
|
|
|
}
|
|
|
|
return &pulumirpc.RunResponse{}, nil
|
|
|
|
}
|
|
|
|
|
2024-01-17 09:35:20 +00:00
|
|
|
func (ctx *updateContext) GetPluginInfo(_ context.Context, req *emptypb.Empty) (*pulumirpc.PluginInfo, error) {
|
2020-09-15 00:40:17 +00:00
|
|
|
return &pulumirpc.PluginInfo{
|
|
|
|
Version: "1.0.0",
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2022-04-03 14:54:59 +00:00
|
|
|
func (ctx *updateContext) InstallDependencies(
|
|
|
|
req *pulumirpc.InstallDependenciesRequest,
|
2023-03-03 16:36:39 +00:00
|
|
|
server pulumirpc.LanguageRuntime_InstallDependenciesServer,
|
|
|
|
) error {
|
2022-04-03 14:54:59 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-15 00:40:17 +00:00
|
|
|
func TestLanguageClient(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-09-15 00:40:17 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
update, err := startUpdate(t, deploytest.NewPluginHostF(nil, nil, nil, loaders...))
|
2020-09-15 00:40:17 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to start update: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register resources, etc.
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = update.RegisterResource("pkgA:m:typA", "resA", true)
|
2020-09-15 00:40:17 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := update.Finish(nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-09-15 00:40:17 +00:00
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
}
|
2020-11-02 21:36:12 +00:00
|
|
|
|
|
|
|
func TestSingleComponentGetResourceDefaultProviderLifecycle(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-11-02 21:36:12 +00:00
|
|
|
var urnB resource.URN
|
|
|
|
var idB resource.ID
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
construct := func(monitor *deploytest.ResourceMonitor, typ, name string, parent resource.URN,
|
2023-07-25 08:03:46 +00:00
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.ConstructResult, error) {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{
|
2020-11-02 21:36:12 +00:00
|
|
|
Parent: parent,
|
|
|
|
Protect: options.Protect,
|
2024-01-26 18:29:22 +00:00
|
|
|
Aliases: aliasesFromAliases(options.Aliases),
|
2020-11-02 21:36:12 +00:00
|
|
|
Dependencies: options.Dependencies,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
respB, err := monitor.RegisterResource("pkgA:m:typB", "resB", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
2020-11-02 21:36:12 +00:00
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"bar": resource.NewStringProperty("baz"),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
urnB, idB = respB.URN, respB.ID
|
2020-11-02 21:36:12 +00:00
|
|
|
|
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2020-11-02 21:36:12 +00:00
|
|
|
Outputs: resource.PropertyMap{
|
|
|
|
"foo": resource.NewStringProperty("bar"),
|
2021-01-21 23:40:27 +00:00
|
|
|
"res": resource.MakeCustomResourceReference(urnB, idB, ""),
|
2020-11-02 21:36:12 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2020-11-02 21:36:12 +00:00
|
|
|
return "created-id", inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ReadF: func(urn resource.URN, id resource.ID,
|
2023-03-03 16:36:39 +00:00
|
|
|
inputs, state resource.PropertyMap,
|
|
|
|
) (plugin.ReadResult, resource.Status, error) {
|
2020-11-02 21:36:12 +00:00
|
|
|
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ConstructF: construct,
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2020-11-02 21:36:12 +00:00
|
|
|
Remote: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.NewStringProperty("bar"),
|
2021-01-21 23:40:27 +00:00
|
|
|
"res": resource.MakeCustomResourceReference(urnB, idB, ""),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
2020-11-02 21:36:12 +00:00
|
|
|
|
|
|
|
result, _, err := monitor.Invoke("pulumi:pulumi:getResource", resource.PropertyMap{
|
|
|
|
"urn": resource.NewStringProperty(string(urnB)),
|
|
|
|
}, "", "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"urn": resource.NewStringProperty(string(urnB)),
|
|
|
|
"id": resource.NewStringProperty(string(idB)),
|
|
|
|
"state": resource.NewObjectProperty(resource.PropertyMap{
|
|
|
|
"bar": resource.NewStringProperty("baz"),
|
|
|
|
}),
|
|
|
|
}, result)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-11-02 21:36:12 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because different ordering makes the colouring different.
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2020-11-02 21:36:12 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 4),
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
2020-11-11 05:11:30 +00:00
|
|
|
|
2020-11-12 20:18:12 +00:00
|
|
|
func TestConfigSecrets(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-11-12 20:18:12 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2020-11-12 20:18:12 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2020-11-12 20:18:12 +00:00
|
|
|
|
|
|
|
crypter := config.NewSymmetricCrypter(make([]byte, 32))
|
2022-07-18 13:36:31 +00:00
|
|
|
secret, err := crypter.EncryptValue(context.Background(), "hunter2")
|
2020-11-12 20:18:12 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because secrets are serialized with the blinding crypter and can't be restored
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2020-11-12 20:18:12 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 2),
|
|
|
|
Config: config.Map{
|
|
|
|
config.MustMakeKey("pkgA", "secret"): config.NewSecureValue(secret),
|
|
|
|
},
|
|
|
|
Decrypter: crypter,
|
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2020-11-12 20:18:12 +00:00
|
|
|
|
|
|
|
if !assert.Len(t, snap.Resources, 2) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
provider := snap.Resources[0]
|
|
|
|
assert.True(t, provider.Inputs["secret"].IsSecret())
|
|
|
|
assert.True(t, provider.Outputs["secret"].IsSecret())
|
|
|
|
}
|
2020-12-18 21:45:52 +00:00
|
|
|
|
|
|
|
func TestComponentOutputs(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2020-12-18 21:45:52 +00:00
|
|
|
// A component's outputs should never be returned by `RegisterResource`, even if (especially if) there are
|
|
|
|
// outputs from a prior deployment and the component's inputs have not changed.
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("component", "resA", false)
|
2020-12-18 21:45:52 +00:00
|
|
|
assert.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
assert.Equal(t, resource.PropertyMap{}, resp.Outputs)
|
2020-12-18 21:45:52 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
err = monitor.RegisterResourceOutputs(resp.URN, resource.PropertyMap{
|
2020-12-18 21:45:52 +00:00
|
|
|
"foo": resource.NewStringProperty("bar"),
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF)
|
2020-12-18 21:45:52 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2020-12-18 21:45:52 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 1),
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
2021-07-12 22:51:11 +00:00
|
|
|
|
|
|
|
// Test calling a method.
|
|
|
|
func TestSingleComponentMethodDefaultProviderLifecycle(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2021-07-12 22:51:11 +00:00
|
|
|
var urn resource.URN
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
construct := func(monitor *deploytest.ResourceMonitor,
|
|
|
|
typ, name string, parent resource.URN, inputs resource.PropertyMap,
|
2023-07-25 08:03:46 +00:00
|
|
|
info plugin.ConstructInfo, options plugin.ConstructOptions,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.ConstructResult, error) {
|
2021-07-12 22:51:11 +00:00
|
|
|
var err error
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{
|
2022-06-29 12:18:14 +00:00
|
|
|
Parent: parent,
|
2024-01-26 18:29:22 +00:00
|
|
|
Aliases: aliasesFromAliases(options.Aliases),
|
2022-06-29 12:18:14 +00:00
|
|
|
Protect: options.Protect,
|
2021-07-12 22:51:11 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
urn = resp.URN
|
2021-07-12 22:51:11 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typB", "resA", true, deploytest.ResourceOptions{
|
2021-07-12 22:51:11 +00:00
|
|
|
Parent: urn,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
outs := resource.PropertyMap{"foo": resource.NewStringProperty("bar")}
|
|
|
|
err = monitor.RegisterResourceOutputs(urn, outs)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.ConstructResult{
|
|
|
|
URN: urn,
|
|
|
|
Outputs: outs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
call := func(monitor *deploytest.ResourceMonitor, tok tokens.ModuleMember, args resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
2021-07-12 22:51:11 +00:00
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"name": resource.NewStringProperty("Alice"),
|
|
|
|
}, args)
|
|
|
|
name := args["name"].StringValue()
|
|
|
|
|
|
|
|
result, _, err := monitor.Invoke("pulumi:pulumi:getResource", resource.PropertyMap{
|
|
|
|
"urn": resource.NewStringProperty(string(urn)),
|
|
|
|
}, "", "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
state := result["state"]
|
|
|
|
foo := state.ObjectValue()["foo"].StringValue()
|
|
|
|
|
|
|
|
message := fmt.Sprintf("%s, %s!", name, foo)
|
|
|
|
return plugin.CallResult{
|
|
|
|
Return: resource.PropertyMap{
|
|
|
|
"message": resource.NewStringProperty(message),
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &deploytest.Provider{
|
|
|
|
ConstructF: construct,
|
|
|
|
CallF: call,
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2021-07-12 22:51:11 +00:00
|
|
|
Remote: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.NewStringProperty("bar"),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
2021-07-12 22:51:11 +00:00
|
|
|
|
|
|
|
outs, _, _, err := monitor.Call("pkgA:m:typA/methodA", resource.PropertyMap{
|
|
|
|
"name": resource.NewStringProperty("Alice"),
|
2024-02-21 09:15:38 +00:00
|
|
|
}, nil, "", "")
|
2021-07-12 22:51:11 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"message": resource.NewStringProperty("Alice, bar!"),
|
|
|
|
}, outs)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2021-07-12 22:51:11 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because different ordering makes the colouring different.
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2021-07-12 22:51:11 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 4),
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test creating a resource from a method.
|
|
|
|
func TestSingleComponentMethodResourceDefaultProviderLifecycle(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2021-07-12 22:51:11 +00:00
|
|
|
var urn resource.URN
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
construct := func(monitor *deploytest.ResourceMonitor,
|
|
|
|
typ, name string, parent resource.URN, inputs resource.PropertyMap,
|
2023-07-25 08:03:46 +00:00
|
|
|
info plugin.ConstructInfo, options plugin.ConstructOptions,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.ConstructResult, error) {
|
2021-07-12 22:51:11 +00:00
|
|
|
var err error
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{
|
2022-06-29 12:18:14 +00:00
|
|
|
Parent: parent,
|
2024-01-26 18:29:22 +00:00
|
|
|
Aliases: aliasesFromAliases(options.Aliases),
|
2022-06-29 12:18:14 +00:00
|
|
|
Protect: options.Protect,
|
2021-07-12 22:51:11 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
urn = resp.URN
|
2021-07-12 22:51:11 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typB", "resA", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
2021-07-12 22:51:11 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
outs := resource.PropertyMap{"foo": resource.NewStringProperty("bar")}
|
2024-04-19 11:08:56 +00:00
|
|
|
err = monitor.RegisterResourceOutputs(resp.URN, outs)
|
2021-07-12 22:51:11 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2021-07-12 22:51:11 +00:00
|
|
|
Outputs: outs,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
call := func(monitor *deploytest.ResourceMonitor, tok tokens.ModuleMember, args resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typC", "resA", true, deploytest.ResourceOptions{
|
2021-07-12 22:51:11 +00:00
|
|
|
Parent: urn,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.CallResult{}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return &deploytest.Provider{
|
|
|
|
ConstructF: construct,
|
|
|
|
CallF: call,
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2021-07-12 22:51:11 +00:00
|
|
|
Remote: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.NewStringProperty("bar"),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
2021-07-12 22:51:11 +00:00
|
|
|
|
2024-02-21 09:15:38 +00:00
|
|
|
_, _, _, err = monitor.Call("pkgA:m:typA/methodA", resource.PropertyMap{}, nil, "", "")
|
2021-07-12 22:51:11 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2021-07-12 22:51:11 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because different ordering makes the colouring different.
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2021-07-12 22:51:11 +00:00
|
|
|
Steps: MakeBasicLifecycleSteps(t, 4),
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
2021-09-29 23:05:45 +00:00
|
|
|
|
|
|
|
// This tests a scenario involving two remote components with interdependencies that are only represented in the
|
|
|
|
// user program.
|
|
|
|
func TestComponentDeleteDependencies(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
2021-09-29 23:05:45 +00:00
|
|
|
|
|
|
|
var (
|
|
|
|
firstURN resource.URN
|
|
|
|
nestedURN resource.URN
|
|
|
|
sgURN resource.URN
|
|
|
|
secondURN resource.URN
|
|
|
|
ruleURN resource.URN
|
|
|
|
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
deploytest.NewProviderLoader("pkgB", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
ConstructF: func(monitor *deploytest.ResourceMonitor, typ, name string, parent resource.URN,
|
2023-07-25 08:03:46 +00:00
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.ConstructResult, error) {
|
2021-09-29 23:05:45 +00:00
|
|
|
switch typ {
|
|
|
|
case "pkgB:m:first":
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgB:m:first", name, false)
|
2021-09-29 23:05:45 +00:00
|
|
|
require.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
firstURN = resp.URN
|
2021-09-29 23:05:45 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err = monitor.RegisterResource("nested", "nested", false,
|
2021-09-29 23:05:45 +00:00
|
|
|
deploytest.ResourceOptions{
|
|
|
|
Parent: firstURN,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
nestedURN = resp.URN
|
2021-09-29 23:05:45 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err = monitor.RegisterResource("pkgA:m:sg", "sg", true, deploytest.ResourceOptions{
|
2021-09-29 23:05:45 +00:00
|
|
|
Parent: nestedURN,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
sgURN = resp.URN
|
2021-09-29 23:05:45 +00:00
|
|
|
|
|
|
|
err = monitor.RegisterResourceOutputs(nestedURN, resource.PropertyMap{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = monitor.RegisterResourceOutputs(firstURN, resource.PropertyMap{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.ConstructResult{URN: firstURN}, nil
|
|
|
|
case "pkgB:m:second":
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgB:m:second", name, false,
|
2021-09-29 23:05:45 +00:00
|
|
|
deploytest.ResourceOptions{
|
|
|
|
Dependencies: options.Dependencies,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
secondURN = resp.URN
|
2021-09-29 23:05:45 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err = monitor.RegisterResource("pkgA:m:rule", "rule", true,
|
2021-09-29 23:05:45 +00:00
|
|
|
deploytest.ResourceOptions{
|
|
|
|
Parent: secondURN,
|
|
|
|
Dependencies: options.PropertyDependencies["sgID"],
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
ruleURN = resp.URN
|
2021-09-29 23:05:45 +00:00
|
|
|
|
|
|
|
err = monitor.RegisterResourceOutputs(secondURN, resource.PropertyMap{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.ConstructResult{URN: secondURN}, nil
|
|
|
|
default:
|
|
|
|
return plugin.ConstructResult{}, fmt.Errorf("unexpected type %v", typ)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgB:m:first", "first", false, deploytest.ResourceOptions{
|
2021-09-29 23:05:45 +00:00
|
|
|
Remote: true,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgB:m:second", "second", false, deploytest.ResourceOptions{
|
2021-09-29 23:05:45 +00:00
|
|
|
Remote: true,
|
|
|
|
PropertyDeps: map[resource.PropertyKey][]resource.URN{
|
|
|
|
"sgID": {sgURN},
|
|
|
|
},
|
|
|
|
Dependencies: []resource.URN{firstURN},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p := &TestPlan{Options: TestUpdateOptions{T: t, HostF: hostF}}
|
2021-09-29 23:05:45 +00:00
|
|
|
|
|
|
|
p.Steps = []TestStep{
|
|
|
|
{
|
|
|
|
Op: Update,
|
|
|
|
SkipPreview: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Op: Destroy,
|
|
|
|
SkipPreview: true,
|
|
|
|
Validate: func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2021-09-29 23:05:45 +00:00
|
|
|
|
|
|
|
firstIndex, nestedIndex, sgIndex, secondIndex, ruleIndex := -1, -1, -1, -1, -1
|
|
|
|
|
|
|
|
for i, entry := range entries {
|
|
|
|
switch urn := entry.Step.URN(); urn {
|
|
|
|
case firstURN:
|
|
|
|
firstIndex = i
|
|
|
|
case nestedURN:
|
|
|
|
nestedIndex = i
|
|
|
|
case sgURN:
|
|
|
|
sgIndex = i
|
|
|
|
case secondURN:
|
|
|
|
secondIndex = i
|
|
|
|
case ruleURN:
|
|
|
|
ruleIndex = i
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.Less(t, ruleIndex, sgIndex)
|
|
|
|
assert.Less(t, ruleIndex, secondIndex)
|
|
|
|
assert.Less(t, secondIndex, firstIndex)
|
|
|
|
assert.Less(t, secondIndex, sgIndex)
|
|
|
|
assert.Less(t, sgIndex, nestedIndex)
|
|
|
|
assert.Less(t, nestedIndex, firstIndex)
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2021-09-29 23:05:45 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
p.Run(t, nil)
|
|
|
|
}
|
2022-01-20 11:18:54 +00:00
|
|
|
|
2022-01-21 23:54:51 +00:00
|
|
|
func TestProtect(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
2022-01-21 23:54:51 +00:00
|
|
|
|
|
|
|
idCounter := 0
|
|
|
|
deleteCounter := 0
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
DiffF: func(
|
|
|
|
urn resource.URN,
|
|
|
|
id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
ignoreChanges []string,
|
|
|
|
) (plugin.DiffResult, error) {
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["foo"].DeepEquals(newInputs["foo"]) {
|
2022-01-21 23:54:51 +00:00
|
|
|
// If foo changes do a replace, we use this to check we don't delete on replace
|
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"foo"},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
return plugin.DiffResult{}, nil
|
|
|
|
},
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-01-21 23:54:51 +00:00
|
|
|
resourceID := resource.ID(fmt.Sprintf("created-id-%d", idCounter))
|
|
|
|
idCounter = idCounter + 1
|
|
|
|
return resourceID, news, resource.StatusOK, nil
|
|
|
|
},
|
2023-10-13 14:12:26 +00:00
|
|
|
DeleteF: func(urn resource.URN, id resource.ID, oldInputs, oldOutputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
timeout float64,
|
|
|
|
) (resource.Status, error) {
|
2022-01-21 23:54:51 +00:00
|
|
|
deleteCounter = deleteCounter + 1
|
|
|
|
return resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
|
|
|
|
2022-01-29 08:57:36 +00:00
|
|
|
shouldProtect := true
|
2022-01-21 23:54:51 +00:00
|
|
|
createResource := true
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2022-01-21 23:54:51 +00:00
|
|
|
if createResource {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-01-21 23:54:51 +00:00
|
|
|
Inputs: ins,
|
2022-01-29 08:57:36 +00:00
|
|
|
Protect: shouldProtect,
|
2022-01-21 23:54:51 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-01-21 23:54:51 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-01-21 23:54:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run an update to create the resource
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-01-21 23:54:51 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
assert.Equal(t, "created-id-0", snap.Resources[1].ID.String())
|
|
|
|
assert.Equal(t, 0, deleteCounter)
|
|
|
|
|
|
|
|
expectedUrn := snap.Resources[1].URN
|
|
|
|
expectedMessage := ""
|
|
|
|
|
|
|
|
// Both updates below should give a diagnostic event
|
|
|
|
validate := func(project workspace.Project,
|
|
|
|
target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2022-01-21 23:54:51 +00:00
|
|
|
for _, event := range events {
|
|
|
|
if event.Type == DiagEvent {
|
|
|
|
payload := event.Payload().(DiagEventPayload)
|
|
|
|
assert.Equal(t, expectedUrn, payload.URN)
|
|
|
|
assert.Equal(t, expectedMessage, payload.Message)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2022-01-21 23:54:51 +00:00
|
|
|
}
|
|
|
|
|
Don't bail at preview when a protected resource needs replacement (#15969)
<!---
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
Don't bail at preview when a protected resource needs replacement, just
error. This makes sure that users can see the actual diff that causes
the replacement.
Fixes #5027
Before:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2
└─ azure-native:resources:ResourceGroup rg 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
Resources:
1 unchanged
```
After:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2 1 error; 2 warnings
+- └─ azure-native:resources:ResourceGroup rg replace [diff: ~location]; 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
pulumi:pulumi:Stack (azure-native-ts-dev2):
error: preview failed
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
+-azure-native:resources:ResourceGroup: (replace) 🔒
[id=/subscriptions/0282681f-7a9e-424b-80b2-96babd57a8a1/resourceGroups/rg5f8e30e4]
[urn=urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg]
[provider=urn:pulumi:dev2::azure-native-ts::pulumi:providers:azure-native::default_2_30_0::3c957b2a-4852-439c-b211-22a115bbe89a]
~ location: "westeurope" => "westus2"
error: preview failed
Resources:
+-1 to replace
1 unchanged
```
## 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. -->
2024-04-18 16:45:52 +00:00
|
|
|
// Run a dry-run (preview) which will cause a replace, we should get an error.
|
|
|
|
// However, the preview doesn't bail, so we expect one "created" resource as a result of this operation.
|
2022-01-21 23:54:51 +00:00
|
|
|
expectedMessage = "<{%reset%}>unable to replace resource \"urn:pulumi:test::test::pkgA:m:typA::resA\"\n" +
|
|
|
|
"as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from " +
|
|
|
|
"the resource in your Pulumi program and run `pulumi up`<{%reset%}>\n"
|
|
|
|
ins = resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
_, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, true, p.BackendClient, validate, "1")
|
Don't bail at preview when a protected resource needs replacement (#15969)
<!---
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
Don't bail at preview when a protected resource needs replacement, just
error. This makes sure that users can see the actual diff that causes
the replacement.
Fixes #5027
Before:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2
└─ azure-native:resources:ResourceGroup rg 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
Resources:
1 unchanged
```
After:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2 1 error; 2 warnings
+- └─ azure-native:resources:ResourceGroup rg replace [diff: ~location]; 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
pulumi:pulumi:Stack (azure-native-ts-dev2):
error: preview failed
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
+-azure-native:resources:ResourceGroup: (replace) 🔒
[id=/subscriptions/0282681f-7a9e-424b-80b2-96babd57a8a1/resourceGroups/rg5f8e30e4]
[urn=urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg]
[provider=urn:pulumi:dev2::azure-native-ts::pulumi:providers:azure-native::default_2_30_0::3c957b2a-4852-439c-b211-22a115bbe89a]
~ location: "westeurope" => "westus2"
error: preview failed
Resources:
+-1 to replace
1 unchanged
```
## 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. -->
2024-04-18 16:45:52 +00:00
|
|
|
assert.ErrorContains(t, err, "step generator errored")
|
|
|
|
|
|
|
|
// Run an update which will cause a replace, we should get an error.
|
|
|
|
// Contrary to the preview, the error is a bail, so no resources are created.
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, validate, "2")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2022-01-21 23:54:51 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
assert.Equal(t, "created-id-0", snap.Resources[1].ID.String())
|
|
|
|
assert.Equal(t, 0, deleteCounter)
|
|
|
|
|
|
|
|
// Run a new update which will cause a delete, we still shouldn't see a provider delete
|
2023-01-10 18:32:12 +00:00
|
|
|
expectedMessage = "<{%reset%}>resource \"urn:pulumi:test::test::pkgA:m:typA::resA\" cannot be deleted\n" +
|
|
|
|
"because it is protected. To unprotect the resource, either remove the `protect` flag " +
|
|
|
|
"from the resource in your Pulumi program and run `pulumi up`, or use the command:\n" +
|
2022-01-21 23:54:51 +00:00
|
|
|
"`pulumi state unprotect 'urn:pulumi:test::test::pkgA:m:typA::resA'`<{%reset%}>\n"
|
|
|
|
createResource = false
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, validate, "3")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2022-01-21 23:54:51 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
assert.Equal(t, "created-id-0", snap.Resources[1].ID.String())
|
2022-01-29 08:57:36 +00:00
|
|
|
assert.Equal(t, true, snap.Resources[1].Protect)
|
2022-01-21 23:54:51 +00:00
|
|
|
assert.Equal(t, 0, deleteCounter)
|
2022-01-29 08:57:36 +00:00
|
|
|
|
|
|
|
// Run a new update to remove the protect and replace in the same update, this should delete the old one
|
|
|
|
// and create the new one
|
|
|
|
createResource = true
|
|
|
|
shouldProtect = false
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "4")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-01-29 08:57:36 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
Don't bail at preview when a protected resource needs replacement (#15969)
<!---
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
Don't bail at preview when a protected resource needs replacement, just
error. This makes sure that users can see the actual diff that causes
the replacement.
Fixes #5027
Before:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2
└─ azure-native:resources:ResourceGroup rg 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
Resources:
1 unchanged
```
After:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2 1 error; 2 warnings
+- └─ azure-native:resources:ResourceGroup rg replace [diff: ~location]; 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
pulumi:pulumi:Stack (azure-native-ts-dev2):
error: preview failed
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
+-azure-native:resources:ResourceGroup: (replace) 🔒
[id=/subscriptions/0282681f-7a9e-424b-80b2-96babd57a8a1/resourceGroups/rg5f8e30e4]
[urn=urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg]
[provider=urn:pulumi:dev2::azure-native-ts::pulumi:providers:azure-native::default_2_30_0::3c957b2a-4852-439c-b211-22a115bbe89a]
~ location: "westeurope" => "westus2"
error: preview failed
Resources:
+-1 to replace
1 unchanged
```
## 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. -->
2024-04-18 16:45:52 +00:00
|
|
|
assert.Equal(t, "created-id-2", snap.Resources[1].ID.String())
|
2022-01-29 08:57:36 +00:00
|
|
|
assert.Equal(t, false, snap.Resources[1].Protect)
|
|
|
|
assert.Equal(t, 1, deleteCounter)
|
|
|
|
|
|
|
|
// Run a new update to add the protect flag, nothing else should change
|
|
|
|
shouldProtect = true
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "5")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-01-29 08:57:36 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
Don't bail at preview when a protected resource needs replacement (#15969)
<!---
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
Don't bail at preview when a protected resource needs replacement, just
error. This makes sure that users can see the actual diff that causes
the replacement.
Fixes #5027
Before:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2
└─ azure-native:resources:ResourceGroup rg 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
Resources:
1 unchanged
```
After:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2 1 error; 2 warnings
+- └─ azure-native:resources:ResourceGroup rg replace [diff: ~location]; 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
pulumi:pulumi:Stack (azure-native-ts-dev2):
error: preview failed
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
+-azure-native:resources:ResourceGroup: (replace) 🔒
[id=/subscriptions/0282681f-7a9e-424b-80b2-96babd57a8a1/resourceGroups/rg5f8e30e4]
[urn=urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg]
[provider=urn:pulumi:dev2::azure-native-ts::pulumi:providers:azure-native::default_2_30_0::3c957b2a-4852-439c-b211-22a115bbe89a]
~ location: "westeurope" => "westus2"
error: preview failed
Resources:
+-1 to replace
1 unchanged
```
## 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. -->
2024-04-18 16:45:52 +00:00
|
|
|
assert.Equal(t, "created-id-2", snap.Resources[1].ID.String())
|
2022-01-29 08:57:36 +00:00
|
|
|
assert.Equal(t, true, snap.Resources[1].Protect)
|
|
|
|
assert.Equal(t, 1, deleteCounter)
|
|
|
|
|
|
|
|
// Edit the snapshot to remove the protect flag and try and replace
|
|
|
|
snap.Resources[1].Protect = false
|
|
|
|
ins = resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "daz",
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, validate, "6")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-01-29 08:57:36 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
Don't bail at preview when a protected resource needs replacement (#15969)
<!---
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
Don't bail at preview when a protected resource needs replacement, just
error. This makes sure that users can see the actual diff that causes
the replacement.
Fixes #5027
Before:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2
└─ azure-native:resources:ResourceGroup rg 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
Resources:
1 unchanged
```
After:
```
$ pulumi preview
Type Name Plan Info
pulumi:pulumi:Stack azure-native-ts-dev2 1 error; 2 warnings
+- └─ azure-native:resources:ResourceGroup rg replace [diff: ~location]; 1 error
Diagnostics:
azure-native:resources:ResourceGroup (rg):
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
pulumi:pulumi:Stack (azure-native-ts-dev2):
error: preview failed
$ pulumi preview --diff
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev2::azure-native-ts::pulumi:pulumi:Stack::azure-native-ts-dev2]
error: unable to replace resource "urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg"
as it is currently marked for protection. To unprotect the resource, remove the `protect` flag from the resource in your Pulumi program and run `pulumi up`
+-azure-native:resources:ResourceGroup: (replace) 🔒
[id=/subscriptions/0282681f-7a9e-424b-80b2-96babd57a8a1/resourceGroups/rg5f8e30e4]
[urn=urn:pulumi:dev2::azure-native-ts::azure-native:resources:ResourceGroup::rg]
[provider=urn:pulumi:dev2::azure-native-ts::pulumi:providers:azure-native::default_2_30_0::3c957b2a-4852-439c-b211-22a115bbe89a]
~ location: "westeurope" => "westus2"
error: preview failed
Resources:
+-1 to replace
1 unchanged
```
## 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. -->
2024-04-18 16:45:52 +00:00
|
|
|
assert.Equal(t, "created-id-3", snap.Resources[1].ID.String())
|
2022-01-29 08:57:36 +00:00
|
|
|
assert.Equal(t, 2, deleteCounter)
|
2022-01-21 23:54:51 +00:00
|
|
|
}
|
2022-01-31 10:31:51 +00:00
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
func TestRetainOnDelete(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
idCounter := 0
|
|
|
|
|
2022-01-31 10:31:51 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2022-10-11 15:30:58 +00:00
|
|
|
DiffF: func(
|
|
|
|
urn resource.URN,
|
|
|
|
id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
ignoreChanges []string,
|
|
|
|
) (plugin.DiffResult, error) {
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["foo"].DeepEquals(newInputs["foo"]) {
|
2022-10-11 15:30:58 +00:00
|
|
|
// If foo changes do a replace, we use this to check we don't delete on replace
|
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"foo"},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
return plugin.DiffResult{}, nil
|
|
|
|
},
|
2022-01-31 10:31:51 +00:00
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-10-11 15:30:58 +00:00
|
|
|
resourceID := resource.ID(fmt.Sprintf("created-id-%d", idCounter))
|
|
|
|
idCounter = idCounter + 1
|
|
|
|
return resourceID, news, resource.StatusOK, nil
|
2022-01-31 10:31:51 +00:00
|
|
|
},
|
2023-10-13 14:12:26 +00:00
|
|
|
DeleteF: func(urn resource.URN, id resource.ID, oldInputs, oldOutputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
timeout float64,
|
|
|
|
) (resource.Status, error) {
|
2022-10-11 15:30:58 +00:00
|
|
|
assert.Fail(t, "Delete was called")
|
|
|
|
return resource.StatusOK, nil
|
2022-01-31 10:31:51 +00:00
|
|
|
},
|
|
|
|
}, nil
|
2022-10-11 15:30:58 +00:00
|
|
|
}, deploytest.WithoutGrpc),
|
2022-01-31 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
|
|
|
|
|
|
|
createResource := true
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2022-10-11 15:30:58 +00:00
|
|
|
if createResource {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-10-11 15:30:58 +00:00
|
|
|
Inputs: ins,
|
|
|
|
RetainOnDelete: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2022-01-31 10:31:51 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-01-31 10:31:51 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// TODO: we're only serializing step.Old, not step.Old.State for the display test,
|
|
|
|
// but that is required for the retain on delete flag
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2022-01-31 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
// Run an update to create the resource
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-10-11 15:30:58 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
assert.Equal(t, "created-id-0", snap.Resources[1].ID.String())
|
2022-01-31 10:31:51 +00:00
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
// Run a new update which will cause a replace, we shouldn't see a provider delete but should get a new id
|
2022-01-31 10:31:51 +00:00
|
|
|
ins = resource.NewPropertyMapFromMap(map[string]interface{}{
|
2022-10-11 15:30:58 +00:00
|
|
|
"foo": "baz",
|
2022-01-31 10:31:51 +00:00
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-10-11 15:30:58 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
assert.Equal(t, "created-id-1", snap.Resources[1].ID.String())
|
2022-01-31 10:31:51 +00:00
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
// Run a new update which will cause a delete, we still shouldn't see a provider delete
|
|
|
|
createResource = false
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "2")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-10-11 15:30:58 +00:00
|
|
|
assert.NotNil(t, snap)
|
2022-10-20 06:15:43 +00:00
|
|
|
assert.Len(t, snap.Resources, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeletedWith(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
idCounter := 0
|
|
|
|
|
|
|
|
topURN := resource.URN("")
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
DiffF: func(
|
|
|
|
urn resource.URN,
|
|
|
|
id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
ignoreChanges []string,
|
|
|
|
) (plugin.DiffResult, error) {
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["foo"].DeepEquals(newInputs["foo"]) {
|
2022-10-20 06:15:43 +00:00
|
|
|
// If foo changes do a replace, we use this to check we don't delete on replace
|
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"foo"},
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
return plugin.DiffResult{}, nil
|
|
|
|
},
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-10-20 06:15:43 +00:00
|
|
|
resourceID := resource.ID(fmt.Sprintf("created-id-%d", idCounter))
|
|
|
|
idCounter = idCounter + 1
|
|
|
|
return resourceID, news, resource.StatusOK, nil
|
|
|
|
},
|
2023-10-13 14:12:26 +00:00
|
|
|
DeleteF: func(urn resource.URN, id resource.ID, oldInputs, oldOutputs resource.PropertyMap,
|
2023-03-03 16:36:39 +00:00
|
|
|
timeout float64,
|
|
|
|
) (resource.Status, error) {
|
2022-10-20 06:15:43 +00:00
|
|
|
if urn != topURN {
|
|
|
|
// Only topURN (aURN) should be actually deleted
|
|
|
|
assert.Fail(t, "Delete was called")
|
|
|
|
}
|
|
|
|
return resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
|
|
|
|
|
|
|
createResource := true
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2022-10-20 06:15:43 +00:00
|
|
|
if createResource {
|
2024-04-19 11:08:56 +00:00
|
|
|
respA, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-10-20 06:15:43 +00:00
|
|
|
Inputs: ins,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2024-04-19 11:08:56 +00:00
|
|
|
topURN = respA.URN
|
2022-10-20 06:15:43 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
respB, err := monitor.RegisterResource("pkgA:m:typA", "resB", true, deploytest.ResourceOptions{
|
2022-10-20 06:15:43 +00:00
|
|
|
Inputs: ins,
|
2024-04-19 11:08:56 +00:00
|
|
|
DeletedWith: respA.URN,
|
2022-10-20 06:15:43 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typA", "resC", true, deploytest.ResourceOptions{
|
2022-10-20 06:15:43 +00:00
|
|
|
Inputs: ins,
|
2024-04-19 11:08:56 +00:00
|
|
|
DeletedWith: respB.URN,
|
2022-10-20 06:15:43 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-10-20 06:15:43 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-10-20 06:15:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run an update to create the resource
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-10-20 06:15:43 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 4)
|
|
|
|
assert.Equal(t, "created-id-0", snap.Resources[1].ID.String())
|
|
|
|
assert.Equal(t, "created-id-1", snap.Resources[2].ID.String())
|
|
|
|
assert.Equal(t, "created-id-2", snap.Resources[3].ID.String())
|
|
|
|
|
2022-11-04 13:02:32 +00:00
|
|
|
// Run a new update which will cause a replace, we should only see a provider delete for aURN but should
|
|
|
|
// get a new id for everything
|
2022-10-20 06:15:43 +00:00
|
|
|
ins = resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-10-20 06:15:43 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 4)
|
|
|
|
assert.Equal(t, "created-id-3", snap.Resources[1].ID.String())
|
|
|
|
assert.Equal(t, "created-id-4", snap.Resources[2].ID.String())
|
|
|
|
assert.Equal(t, "created-id-5", snap.Resources[3].ID.String())
|
|
|
|
|
|
|
|
// Run a new update which will cause a delete, we still shouldn't see a provider delete for anything but aURN
|
|
|
|
createResource = false
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "2")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-10-20 06:15:43 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 0)
|
|
|
|
}
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
func TestInvalidGetIDReportsUserError(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-01-31 10:31:51 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
2022-10-11 15:30:58 +00:00
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
2022-01-31 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
_, _, err := monitor.ReadResource("pkgA:m:typA", "resA", "", "", resource.PropertyMap{}, "", "", "")
|
2022-10-11 15:30:58 +00:00
|
|
|
assert.Error(t, err)
|
2022-01-31 10:31:51 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-01-31 10:31:51 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-01-31 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
2022-04-05 11:43:04 +00:00
|
|
|
validate := ExpectDiagMessage(t, regexp.QuoteMeta(
|
2022-10-11 15:30:58 +00:00
|
|
|
"<{%reset%}>Expected an ID for urn:pulumi:test::test::pkgA:m:typA::resA<{%reset%}>"))
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, validate)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-01-31 10:31:51 +00:00
|
|
|
assert.NotNil(t, snap)
|
2022-10-11 15:30:58 +00:00
|
|
|
assert.Len(t, snap.Resources, 1)
|
2022-01-31 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
func TestEventSecrets(t *testing.T) {
|
2022-03-04 08:17:41 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2022-01-31 10:31:51 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
2022-10-11 15:30:58 +00:00
|
|
|
DiffF: func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2023-05-29 15:41:36 +00:00
|
|
|
diff := oldOutputs.Diff(newInputs)
|
2022-10-11 15:30:58 +00:00
|
|
|
if diff == nil {
|
|
|
|
return plugin.DiffResult{Changes: plugin.DiffNone}, nil
|
|
|
|
}
|
2023-10-18 10:33:04 +00:00
|
|
|
detailedDiff := plugin.NewDetailedDiffFromObjectDiff(diff, false)
|
2022-10-11 15:30:58 +00:00
|
|
|
changedKeys := diff.ChangedKeys()
|
|
|
|
|
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ChangedKeys: changedKeys,
|
|
|
|
DetailedDiff: detailedDiff,
|
|
|
|
}, nil
|
2022-01-31 10:31:51 +00:00
|
|
|
},
|
2022-10-11 15:30:58 +00:00
|
|
|
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-10-11 15:30:58 +00:00
|
|
|
return resource.ID("id123"), inputs, resource.StatusOK, nil
|
2022-01-31 10:31:51 +00:00
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
var inputs resource.PropertyMap
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-10-11 15:30:58 +00:00
|
|
|
Inputs: inputs,
|
2022-01-31 10:31:51 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-01-31 10:31:51 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because secrets are serialized with the blinding crypter and can't be restored
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2022-10-11 15:30:58 +00:00
|
|
|
Steps: []TestStep{{
|
|
|
|
Op: Update,
|
|
|
|
SkipPreview: true,
|
|
|
|
}},
|
2022-01-31 10:31:51 +00:00
|
|
|
}
|
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
inputs = resource.PropertyMap{
|
|
|
|
"webhooks": resource.MakeSecret(resource.NewArrayProperty([]resource.PropertyValue{
|
|
|
|
resource.NewObjectProperty(resource.PropertyMap{
|
|
|
|
"clientConfig": resource.NewObjectProperty(resource.PropertyMap{
|
|
|
|
"service": resource.NewStringProperty("foo"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
})),
|
2022-01-31 10:31:51 +00:00
|
|
|
}
|
2022-10-11 15:30:58 +00:00
|
|
|
snap := p.Run(t, nil)
|
2022-01-31 10:31:51 +00:00
|
|
|
|
2022-10-11 15:30:58 +00:00
|
|
|
inputs = resource.PropertyMap{
|
|
|
|
"webhooks": resource.MakeSecret(resource.NewArrayProperty([]resource.PropertyValue{
|
|
|
|
resource.NewObjectProperty(resource.PropertyMap{
|
|
|
|
"clientConfig": resource.NewObjectProperty(resource.PropertyMap{
|
|
|
|
"service": resource.NewStringProperty("bar"),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
})),
|
|
|
|
}
|
|
|
|
p.Steps[0].Validate = func(project workspace.Project, target deploy.Target, entries JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
evts []Event, err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
2022-04-06 18:01:06 +00:00
|
|
|
for _, e := range evts {
|
|
|
|
var step StepEventMetadata
|
turn on the golangci-lint exhaustive linter (#15028)
Turn on the golangci-lint exhaustive linter. This is the first step
towards catching more missing cases during development rather than
in tests, or in production.
This might be best reviewed commit-by-commit, as the first commit turns
on the linter with the `default-signifies-exhaustive: true` option set,
which requires a lot less changes in the current codebase.
I think it's probably worth doing the second commit as well, as that
will get us the real benefits, even though we end up with a little bit
more churn. However it means all the `switch` statements are covered,
which isn't the case after the first commit, since we do have a lot of
`default` statements that just call `assert.Fail`.
Fixes #14601
## 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. -->
2024-01-17 16:50:41 +00:00
|
|
|
//nolint:exhaustive // We only care about a subset of events here
|
2022-04-06 18:01:06 +00:00
|
|
|
switch e.Type {
|
|
|
|
case ResourcePreEvent:
|
|
|
|
step = e.Payload().(ResourcePreEventPayload).Metadata
|
|
|
|
case ResourceOutputsEvent:
|
|
|
|
step = e.Payload().(ResourceOutputsEventPayload).Metadata
|
|
|
|
default:
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if step.URN.Name() != "resA" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
assert.True(t, step.Old.Inputs["webhooks"].IsSecret())
|
|
|
|
assert.True(t, step.Old.Outputs["webhooks"].IsSecret())
|
|
|
|
assert.True(t, step.New.Inputs["webhooks"].IsSecret())
|
|
|
|
}
|
2023-10-11 14:44:09 +00:00
|
|
|
return err
|
2022-04-06 18:01:06 +00:00
|
|
|
}
|
|
|
|
p.Run(t, snap)
|
|
|
|
}
|
2022-05-04 17:36:30 +00:00
|
|
|
|
2022-06-06 16:34:04 +00:00
|
|
|
func TestAdditionalSecretOutputs(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2022-06-22 12:52:42 +00:00
|
|
|
t.Skip("AdditionalSecretOutputs warning is currently disabled")
|
|
|
|
|
2022-06-06 16:34:04 +00:00
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-06-06 16:34:04 +00:00
|
|
|
return resource.ID("id123"), inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
var inputs resource.PropertyMap
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-06-06 16:34:04 +00:00
|
|
|
Inputs: inputs,
|
|
|
|
AdditionalSecretOutputs: []resource.PropertyKey{"a", "b"},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-06-06 16:34:04 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-06-06 16:34:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
inputs = resource.PropertyMap{
|
|
|
|
"a": resource.NewStringProperty("testA"),
|
|
|
|
// b is missing
|
|
|
|
"c": resource.MakeSecret(resource.NewStringProperty("testC")),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run an update to create the resource and check we warn about b
|
|
|
|
validate := func(
|
|
|
|
project workspace.Project, target deploy.Target,
|
|
|
|
entries JournalEntries, events []Event,
|
2024-05-06 17:34:24 +00:00
|
|
|
err error,
|
2023-10-11 14:44:09 +00:00
|
|
|
) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2022-06-06 16:34:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for i := range events {
|
|
|
|
if events[i].Type == "diag" {
|
|
|
|
payload := events[i].Payload().(engine.DiagEventPayload)
|
|
|
|
if payload.Severity == "warning" &&
|
|
|
|
payload.URN == "urn:pulumi:test::test::pkgA:m:typA::resA" &&
|
|
|
|
payload.Message == "<{%reset%}>Could not find property 'b' listed in additional secret outputs.<{%reset%}>\n" {
|
|
|
|
// Found the message we expected
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-12 12:19:42 +00:00
|
|
|
return errors.New("Expected a diagnostic message, got none")
|
2022-06-06 16:34:04 +00:00
|
|
|
}
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, validate)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-06-06 16:34:04 +00:00
|
|
|
|
|
|
|
// Should have the provider and resA
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
resA := snap.Resources[1]
|
|
|
|
assert.Equal(t, []resource.PropertyKey{"a", "b"}, resA.AdditionalSecretOutputs)
|
|
|
|
assert.True(t, resA.Outputs["a"].IsSecret())
|
|
|
|
assert.True(t, resA.Outputs["c"].IsSecret())
|
|
|
|
}
|
2022-06-13 21:03:34 +00:00
|
|
|
|
|
|
|
func TestDefaultParents(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-11-07 13:15:36 +00:00
|
|
|
t.Skipf("Default parents disabled due to https://github.com/pulumi/pulumi/issues/10950")
|
2022-06-13 21:03:34 +00:00
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-06-13 21:03:34 +00:00
|
|
|
return "created-id", news, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource(
|
2022-06-13 21:03:34 +00:00
|
|
|
resource.RootStackType,
|
|
|
|
info.Project+"-"+info.Stack,
|
|
|
|
false,
|
|
|
|
deploytest.ResourceOptions{})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource(
|
2022-06-13 21:03:34 +00:00
|
|
|
"pkgA:m:typA",
|
|
|
|
"resA",
|
|
|
|
true,
|
|
|
|
deploytest.ResourceOptions{})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-06-13 21:03:34 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-06-13 21:03:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run an update to create the resource
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-06-13 21:03:34 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 3)
|
|
|
|
|
|
|
|
// Assert that resource 0 is the stack
|
|
|
|
assert.Equal(t, resource.RootStackType, snap.Resources[0].Type)
|
|
|
|
// Assert that the other 2 resources have the stack as a parent
|
|
|
|
assert.Equal(t, snap.Resources[0].URN, snap.Resources[1].Parent)
|
|
|
|
assert.Equal(t, snap.Resources[0].URN, snap.Resources[2].Parent)
|
|
|
|
}
|
2022-10-14 11:09:10 +00:00
|
|
|
|
|
|
|
func TestPendingDeleteOrder(t *testing.T) {
|
|
|
|
// Test for https://github.com/pulumi/pulumi/issues/2948 Ensure that if we have resources A and B, and we
|
|
|
|
// go to replace A but then fail to replace B that we correctly handle everything in the same order when
|
|
|
|
// we retry the update.
|
|
|
|
//
|
|
|
|
// That is normally for this operation we would do the following:
|
|
|
|
// 1. Create new A
|
|
|
|
// 2. Create new B
|
|
|
|
// 3. Delete old B
|
|
|
|
// 4. Delete old A
|
|
|
|
// So if step 2 fails to create the new B we want to see:
|
|
|
|
// 1. Create new A
|
|
|
|
// 2. Create new B (fail)
|
|
|
|
// 1. Create new B
|
|
|
|
// 2. Delete old B
|
|
|
|
// 3. Delete old A
|
|
|
|
// Currently (and what #2948 tracks) is that the engine does the following:
|
|
|
|
// 1. Create new A
|
|
|
|
// 2. Create new B (fail)
|
|
|
|
// 3. Delete old A
|
|
|
|
// 1. Create new B
|
|
|
|
// 2. Delete old B
|
|
|
|
// That delete A fails because the delete B needs to happen first.
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
cloudState := map[resource.ID]resource.PropertyMap{}
|
|
|
|
|
|
|
|
failCreationOfTypB := false
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-10-14 11:09:10 +00:00
|
|
|
if strings.Contains(string(urn), "typB") && failCreationOfTypB {
|
2023-12-12 12:19:42 +00:00
|
|
|
return "", nil, resource.StatusOK, errors.New("Could not create typB")
|
2022-10-14 11:09:10 +00:00
|
|
|
}
|
|
|
|
|
2023-12-12 12:19:42 +00:00
|
|
|
id := resource.ID(strconv.Itoa(len(cloudState)))
|
2022-10-14 11:09:10 +00:00
|
|
|
if !preview {
|
|
|
|
cloudState[id] = news
|
|
|
|
}
|
|
|
|
return id, news, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
DeleteF: func(urn resource.URN,
|
2023-10-13 14:12:26 +00:00
|
|
|
id resource.ID, oldInputs, oldOutputs resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.Status, error) {
|
2022-10-14 11:09:10 +00:00
|
|
|
// Fail if anything in cloud state still points to us
|
2023-01-06 10:01:06 +00:00
|
|
|
for other, res := range cloudState {
|
2022-10-14 11:09:10 +00:00
|
|
|
for _, v := range res {
|
|
|
|
if v.IsString() && v.StringValue() == string(id) {
|
2023-01-06 10:01:06 +00:00
|
|
|
return resource.StatusOK, fmt.Errorf("Can not delete %s used by %s", id, other)
|
2022-10-14 11:09:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delete(cloudState, id)
|
|
|
|
return resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
DiffF: func(urn resource.URN,
|
2023-05-29 15:41:36 +00:00
|
|
|
id resource.ID, oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2022-10-14 11:09:10 +00:00
|
|
|
if strings.Contains(string(urn), "typA") {
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["foo"].DeepEquals(newInputs["foo"]) {
|
2022-10-14 11:09:10 +00:00
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"foo"},
|
|
|
|
DetailedDiff: map[string]plugin.PropertyDiff{
|
|
|
|
"foo": {
|
|
|
|
Kind: plugin.DiffUpdateReplace,
|
|
|
|
InputDiff: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DeleteBeforeReplace: false,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if strings.Contains(string(urn), "typB") {
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["parent"].DeepEquals(newInputs["parent"]) {
|
2022-10-14 11:09:10 +00:00
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"parent"},
|
|
|
|
DetailedDiff: map[string]plugin.PropertyDiff{
|
|
|
|
"parent": {
|
|
|
|
Kind: plugin.DiffUpdateReplace,
|
|
|
|
InputDiff: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DeleteBeforeReplace: false,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return plugin.DiffResult{}, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
2022-10-14 11:09:10 +00:00
|
|
|
assert.Fail(t, "Didn't expect update to be called")
|
|
|
|
return nil, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-10-14 11:09:10 +00:00
|
|
|
Inputs: ins,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typB", "resB", true, deploytest.ResourceOptions{
|
2022-10-14 11:09:10 +00:00
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
2024-04-19 11:08:56 +00:00
|
|
|
"parent": resp.ID,
|
2022-10-14 11:09:10 +00:00
|
|
|
}),
|
2024-04-19 11:08:56 +00:00
|
|
|
Dependencies: []resource.URN{resp.URN},
|
2022-10-14 11:09:10 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-10-14 11:09:10 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-10-14 11:09:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run an update to create the resources
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2024-01-03 17:32:13 +00:00
|
|
|
require.NoError(t, err)
|
2022-10-14 11:09:10 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 3)
|
|
|
|
|
|
|
|
// Trigger a replacement of A but fail to create B
|
|
|
|
failCreationOfTypB = true
|
|
|
|
ins = resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
})
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2022-10-14 11:09:10 +00:00
|
|
|
// Assert that this fails, we should have two copies of A now, one new one and one old one pending delete
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2022-10-14 11:09:10 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 4)
|
|
|
|
assert.Equal(t, snap.Resources[1].Type, tokens.Type("pkgA:m:typA"))
|
|
|
|
assert.False(t, snap.Resources[1].Delete)
|
|
|
|
assert.Equal(t, snap.Resources[2].Type, tokens.Type("pkgA:m:typA"))
|
|
|
|
assert.True(t, snap.Resources[2].Delete)
|
|
|
|
|
|
|
|
// Now allow B to create and try again
|
|
|
|
failCreationOfTypB = false
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "2")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-10-14 11:09:10 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 3)
|
|
|
|
}
|
2022-10-31 18:33:42 +00:00
|
|
|
|
2022-11-28 12:13:19 +00:00
|
|
|
func TestPendingDeleteReplacement(t *testing.T) {
|
|
|
|
// Test for https://github.com/pulumi/pulumi/issues/11391, check that if we
|
|
|
|
// try to replace a resource via delete before replace, but fail to delete
|
|
|
|
// it, then rerun that we don't error.
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
cloudID := 0
|
|
|
|
cloudState := map[resource.ID]resource.PropertyMap{}
|
|
|
|
|
|
|
|
failDeletionOfTypB := true
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
2022-11-28 12:13:19 +00:00
|
|
|
id := resource.ID("")
|
|
|
|
if !preview {
|
2023-12-12 12:19:42 +00:00
|
|
|
id = resource.ID(strconv.Itoa(cloudID))
|
2022-11-28 12:13:19 +00:00
|
|
|
cloudID = cloudID + 1
|
|
|
|
cloudState[id] = news
|
|
|
|
}
|
|
|
|
return id, news, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
DeleteF: func(urn resource.URN,
|
2023-10-13 14:12:26 +00:00
|
|
|
id resource.ID, oldInputs, oldOutputs resource.PropertyMap, timeout float64,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.Status, error) {
|
2022-11-28 12:13:19 +00:00
|
|
|
// Fail if anything in cloud state still points to us
|
|
|
|
for _, res := range cloudState {
|
|
|
|
for _, v := range res {
|
|
|
|
if v.IsString() && v.StringValue() == string(id) {
|
|
|
|
return resource.StatusOK, fmt.Errorf("Can not delete %s", id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.Contains(string(urn), "typB") && failDeletionOfTypB {
|
2023-12-12 12:19:42 +00:00
|
|
|
return resource.StatusOK, errors.New("Could not delete typB")
|
2022-11-28 12:13:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
delete(cloudState, id)
|
|
|
|
return resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
DiffF: func(urn resource.URN,
|
2023-05-29 15:41:36 +00:00
|
|
|
id resource.ID, oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
2022-11-28 12:13:19 +00:00
|
|
|
if strings.Contains(string(urn), "typA") {
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["foo"].DeepEquals(newInputs["foo"]) {
|
2022-11-28 12:13:19 +00:00
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"foo"},
|
|
|
|
DetailedDiff: map[string]plugin.PropertyDiff{
|
|
|
|
"foo": {
|
|
|
|
Kind: plugin.DiffUpdateReplace,
|
|
|
|
InputDiff: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DeleteBeforeReplace: true,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if strings.Contains(string(urn), "typB") {
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["parent"].DeepEquals(newInputs["parent"]) {
|
2022-11-28 12:13:19 +00:00
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"parent"},
|
|
|
|
DetailedDiff: map[string]plugin.PropertyDiff{
|
|
|
|
"parent": {
|
|
|
|
Kind: plugin.DiffUpdateReplace,
|
|
|
|
InputDiff: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DeleteBeforeReplace: false,
|
|
|
|
}, nil
|
|
|
|
}
|
2023-05-29 15:41:36 +00:00
|
|
|
if !oldOutputs["frob"].DeepEquals(newInputs["frob"]) {
|
2022-11-28 12:13:19 +00:00
|
|
|
return plugin.DiffResult{
|
|
|
|
Changes: plugin.DiffSome,
|
|
|
|
ReplaceKeys: []resource.PropertyKey{"frob"},
|
|
|
|
DetailedDiff: map[string]plugin.PropertyDiff{
|
|
|
|
"frob": {
|
|
|
|
Kind: plugin.DiffUpdateReplace,
|
|
|
|
InputDiff: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
DeleteBeforeReplace: false,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return plugin.DiffResult{}, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
2022-11-28 12:13:19 +00:00
|
|
|
assert.Fail(t, "Didn't expect update to be called")
|
|
|
|
return nil, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
insA := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
|
|
|
inB := "active"
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
respA, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2022-11-28 12:13:19 +00:00
|
|
|
Inputs: insA,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typB", "resB", true, deploytest.ResourceOptions{
|
2022-11-28 12:13:19 +00:00
|
|
|
Inputs: resource.NewPropertyMapFromMap(map[string]interface{}{
|
2024-04-19 11:08:56 +00:00
|
|
|
"parent": respA.ID,
|
2022-11-28 12:13:19 +00:00
|
|
|
"frob": inB,
|
|
|
|
}),
|
|
|
|
PropertyDeps: map[resource.PropertyKey][]resource.URN{
|
2024-04-19 11:08:56 +00:00
|
|
|
"parent": {respA.URN},
|
2022-11-28 12:13:19 +00:00
|
|
|
},
|
2024-04-19 11:08:56 +00:00
|
|
|
Dependencies: []resource.URN{respA.URN},
|
2022-11-28 12:13:19 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2022-11-28 12:13:19 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2022-11-28 12:13:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run an update to create the resources
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-11-28 12:13:19 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 3)
|
|
|
|
|
|
|
|
// Trigger a replacement of B but fail to delete it
|
|
|
|
inB = "inactive"
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2022-11-28 12:13:19 +00:00
|
|
|
// Assert that this fails, we should have two B's one marked to delete
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.Error(t, err)
|
2022-11-28 12:13:19 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 4)
|
|
|
|
assert.Equal(t, snap.Resources[1].Type, tokens.Type("pkgA:m:typA"))
|
|
|
|
assert.False(t, snap.Resources[1].Delete)
|
|
|
|
assert.Equal(t, snap.Resources[2].Type, tokens.Type("pkgA:m:typB"))
|
|
|
|
assert.False(t, snap.Resources[2].Delete)
|
|
|
|
assert.Equal(t, snap.Resources[3].Type, tokens.Type("pkgA:m:typB"))
|
|
|
|
assert.True(t, snap.Resources[3].Delete)
|
|
|
|
|
|
|
|
// Now trigger a replacment of A, which will also trigger B to replace
|
|
|
|
insA = resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
})
|
|
|
|
failDeletionOfTypB = false
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil)
|
2022-11-28 12:13:19 +00:00
|
|
|
// Assert this is ok, we should have just one A and B
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2022-11-28 12:13:19 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 3)
|
|
|
|
assert.Equal(t, snap.Resources[1].Type, tokens.Type("pkgA:m:typA"))
|
|
|
|
assert.False(t, snap.Resources[1].Delete)
|
|
|
|
assert.Equal(t, snap.Resources[2].Type, tokens.Type("pkgA:m:typB"))
|
|
|
|
assert.False(t, snap.Resources[2].Delete)
|
|
|
|
}
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
|
|
|
|
func TestTimestampTracking(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
p := &TestPlan{}
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "created-id", news, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
DiffF: func(urn resource.URN, id resource.ID,
|
2023-05-29 15:41:36 +00:00
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
) (plugin.DiffResult, error) {
|
|
|
|
return plugin.DiffResult{Changes: plugin.DiffSome}, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
UpdateF: func(_ resource.URN, _ resource.ID, _, _, _ resource.PropertyMap, _ float64,
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
_ []string, _ bool,
|
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
|
|
|
outputs := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
|
|
|
return outputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource(
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
resource.RootStackType,
|
|
|
|
info.Project+"-"+info.Stack,
|
|
|
|
false,
|
|
|
|
deploytest.ResourceOptions{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource(
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
"pkgA:m:typA",
|
|
|
|
"resA",
|
|
|
|
true,
|
|
|
|
deploytest.ResourceOptions{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
p.Options.HostF = deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
p.Options.T = t
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
// Run an update to create the resource -- created and updated should be set and equal.
|
|
|
|
p.Steps = []TestStep{{Op: Update, SkipPreview: true}}
|
|
|
|
snap := p.Run(t, nil)
|
|
|
|
require.NotEmpty(t, snap.Resources)
|
|
|
|
|
|
|
|
creationTimes := make(map[resource.URN]time.Time, len(snap.Resources))
|
|
|
|
for _, resource := range snap.Resources {
|
|
|
|
assert.NotNil(t, resource.Created, "missing created time: %v", resource.URN)
|
|
|
|
assert.NotNil(t, resource.Modified, "missing modified time: %v", resource.URN)
|
|
|
|
tz, _ := resource.Created.Zone()
|
|
|
|
assert.Equal(t, "UTC", tz, "time zone is not UTC: %v", resource.URN)
|
|
|
|
assert.Equal(t, resource.Created, resource.Modified,
|
|
|
|
"created time != modified time: %v", resource.URN)
|
|
|
|
|
|
|
|
creationTimes[resource.URN] = *resource.Created
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run a refresh -- created and updated should be unchanged.
|
|
|
|
p.Steps = []TestStep{{Op: Refresh, SkipPreview: true}}
|
|
|
|
snap = p.Run(t, snap)
|
|
|
|
require.NotEmpty(t, snap.Resources)
|
|
|
|
for _, resource := range snap.Resources {
|
|
|
|
assert.NotNil(t, resource.Created, "missing created time: %v", resource.URN)
|
|
|
|
assert.NotNil(t, resource.Modified, "missing modified time: %v", resource.URN)
|
|
|
|
assert.Equal(t, *resource.Created, creationTimes[resource.URN],
|
|
|
|
"created time changed: %v", resource.URN)
|
|
|
|
assert.Equal(t, resource.Created, resource.Modified,
|
|
|
|
"modified time changed: %v", resource.URN)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run another update -- updated should be greater than created for resA,
|
|
|
|
// everything else should be untouched.
|
|
|
|
p.Steps = []TestStep{{Op: Update, SkipPreview: true}}
|
|
|
|
snap = p.Run(t, snap)
|
|
|
|
require.NotEmpty(t, snap.Resources)
|
|
|
|
for _, resource := range snap.Resources {
|
|
|
|
assert.NotNil(t, resource.Created, resource.URN, "missing created time: %v", resource.URN)
|
|
|
|
assert.NotNil(t, resource.Modified, resource.URN, "missing modified time: %v", resource.URN)
|
|
|
|
assert.Equal(t, creationTimes[resource.URN], *resource.Created,
|
|
|
|
"created time changed: %v", resource.URN)
|
|
|
|
|
2024-03-14 15:28:32 +00:00
|
|
|
//exhaustive:ignore
|
This commit adds the `Created` and `Modified` timestamps to pulumi state that are optional.
`Created`: Created tracks when the remote resource was first added to state by pulumi. Checkpoints prior to early 2023 do not include this. (Create, Import)
`Modified`: Modified tracks when the resource state was last altered. Checkpoints prior to early 2023 do not include this. (Create, Import, Read, Refresh, Update)
When serialized they will follow RFC3339 with nanoseconds captured by a test case.
https://pkg.go.dev/time#RFC3339
Note: Older versions of pulumi may strip these fields when modifying the state.
For future expansion, when we inevitably need to track other timestamps, we'll add a new "operationTimestamps" field (or something similarly named that clarified these are timestamps of the actual Pulumi operations).
operationTimestamps: {
created: ...,
updated: ...,
imported: ...,
}
Fixes https://github.com/pulumi/pulumi/issues/12022
2023-02-06 20:39:11 +00:00
|
|
|
switch resource.Type {
|
|
|
|
case "pkgA:m:typA":
|
|
|
|
tz, _ := resource.Modified.Zone()
|
|
|
|
assert.Equal(t, "UTC", tz, "time zone is not UTC: %v", resource.URN)
|
|
|
|
assert.NotEqual(t, creationTimes[resource.URN], *resource.Modified,
|
|
|
|
"modified time did not update: %v", resource.URN)
|
|
|
|
assert.Greater(t, *resource.Modified, *resource.Created,
|
|
|
|
"modified time is too old: %v", resource.URN)
|
|
|
|
case "pulumi:providers:pkgA", "pulumi:pulumi:Stack":
|
|
|
|
tz, _ := resource.Modified.Zone()
|
|
|
|
assert.Equal(t, "UTC", tz, "time zone is not UTC: %v", resource.URN)
|
|
|
|
assert.NotNil(t, *resource.Created, "missing created time: %v", resource.URN)
|
|
|
|
assert.NotNil(t, *resource.Modified, "missing modified time: %v", resource.URN)
|
|
|
|
default:
|
|
|
|
require.FailNow(t, "unrecognized resource type", resource.Type)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-30 08:50:36 +00:00
|
|
|
|
2023-05-29 15:41:36 +00:00
|
|
|
func TestOldCheckedInputsAreSent(t *testing.T) {
|
|
|
|
// Test for https://github.com/pulumi/pulumi/issues/5973, check that the old inputs from Check are passed
|
2023-10-13 14:12:26 +00:00
|
|
|
// to Diff, Update, and Delete.
|
2023-05-29 15:41:36 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
firstUpdate := true
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CheckF: func(urn resource.URN,
|
|
|
|
olds, news resource.PropertyMap, randomSeed []byte,
|
|
|
|
) (resource.PropertyMap, []plugin.CheckFailure, error) {
|
|
|
|
// Check that the old inputs are passed to CheckF
|
|
|
|
if firstUpdate {
|
|
|
|
assert.Nil(t, olds)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
}), news)
|
|
|
|
} else {
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"default": "default",
|
|
|
|
}), olds)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
}), news)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a default property
|
|
|
|
results := resource.PropertyMap{}
|
|
|
|
for k, v := range news {
|
|
|
|
results[k] = v
|
|
|
|
}
|
|
|
|
results["default"] = resource.NewStringProperty("default")
|
|
|
|
|
|
|
|
return results, nil, nil
|
|
|
|
},
|
|
|
|
DiffF: func(urn resource.URN,
|
|
|
|
id resource.ID, oldInputs, oldOutputs, newInputs resource.PropertyMap, ignoreChanges []string,
|
|
|
|
) (plugin.DiffResult, error) {
|
|
|
|
// Check that the old inputs and outputs are passed to DiffF
|
|
|
|
if firstUpdate {
|
|
|
|
assert.Nil(t, oldInputs)
|
|
|
|
assert.Nil(t, oldOutputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
}), newInputs)
|
|
|
|
} else {
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"default": "default",
|
|
|
|
}), oldInputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"default": "default",
|
|
|
|
"computed": "computed",
|
|
|
|
}), oldOutputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
"default": "default",
|
|
|
|
}), newInputs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Let the engine do the diff, we just want to assert the conditions above
|
|
|
|
return plugin.DiffResult{}, nil
|
|
|
|
},
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
id := resource.ID("")
|
|
|
|
results := resource.PropertyMap{}
|
|
|
|
for k, v := range news {
|
|
|
|
results[k] = v
|
|
|
|
}
|
|
|
|
// Add a computed property
|
|
|
|
results["computed"] = resource.MakeComputed(resource.NewStringProperty(""))
|
|
|
|
|
|
|
|
if !preview {
|
|
|
|
id = resource.ID("1")
|
|
|
|
results["computed"] = resource.NewStringProperty("computed")
|
|
|
|
}
|
|
|
|
return id, results, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
UpdateF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs, newInputs resource.PropertyMap,
|
|
|
|
timeout float64, ignoreChanges []string, preview bool,
|
|
|
|
) (resource.PropertyMap, resource.Status, error) {
|
|
|
|
// Check that the old inputs and outputs are passed to UpdateF
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"default": "default",
|
|
|
|
}), oldInputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"default": "default",
|
|
|
|
"computed": "computed",
|
|
|
|
}), oldOutputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
"default": "default",
|
|
|
|
}), newInputs)
|
|
|
|
|
|
|
|
results := resource.PropertyMap{}
|
|
|
|
for k, v := range newInputs {
|
|
|
|
results[k] = v
|
|
|
|
}
|
|
|
|
// Add a computed property
|
|
|
|
results["computed"] = resource.MakeComputed(resource.NewStringProperty(""))
|
|
|
|
|
|
|
|
if !preview {
|
|
|
|
results["computed"] = resource.NewStringProperty("computed")
|
|
|
|
}
|
|
|
|
|
|
|
|
return results, resource.StatusOK, nil
|
|
|
|
},
|
2023-10-13 14:12:26 +00:00
|
|
|
DeleteF: func(urn resource.URN, id resource.ID,
|
|
|
|
oldInputs, oldOutputs resource.PropertyMap,
|
|
|
|
timeout float64,
|
|
|
|
) (resource.Status, error) {
|
|
|
|
// Check that the old inputs and outputs are passed to UpdateF
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
"default": "default",
|
|
|
|
}), oldInputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
"default": "default",
|
|
|
|
"computed": "computed",
|
|
|
|
}), oldOutputs)
|
|
|
|
|
|
|
|
return resource.StatusOK, nil
|
|
|
|
},
|
2023-05-29 15:41:36 +00:00
|
|
|
}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
insA := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2023-05-29 15:41:36 +00:00
|
|
|
Inputs: insA,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2023-05-29 15:41:36 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2023-05-29 15:41:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run an update to create the resources
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2023-05-29 15:41:36 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
resA := snap.Resources[1]
|
|
|
|
assert.Equal(t, tokens.Type("pkgA:m:typA"), resA.Type)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"default": "default",
|
|
|
|
}), resA.Inputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
"default": "default",
|
|
|
|
"computed": "computed",
|
|
|
|
}), resA.Outputs)
|
|
|
|
|
|
|
|
// Now run another update with new inputs
|
|
|
|
insA = resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
})
|
|
|
|
firstUpdate = false
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2023-05-29 15:41:36 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
resA = snap.Resources[1]
|
|
|
|
assert.Equal(t, tokens.Type("pkgA:m:typA"), resA.Type)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
"default": "default",
|
|
|
|
}), resA.Inputs)
|
|
|
|
assert.Equal(t, resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "baz",
|
|
|
|
"default": "default",
|
|
|
|
"computed": "computed",
|
|
|
|
}), resA.Outputs)
|
2023-10-13 14:12:26 +00:00
|
|
|
|
|
|
|
// Now run a destroy to delete the resource and check the stored inputs and outputs are sent
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Destroy).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "2")
|
2023-10-13 14:12:26 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 0)
|
2023-05-29 15:41:36 +00:00
|
|
|
}
|
2023-07-07 09:14:20 +00:00
|
|
|
|
|
|
|
func TestResourceNames(t *testing.T) {
|
|
|
|
// Regression test for https://github.com/pulumi/pulumi/issues/10117
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
cases := []string{
|
|
|
|
"foo",
|
|
|
|
":colons",
|
|
|
|
"-dashes",
|
|
|
|
"file/path.txt",
|
|
|
|
"bar|table",
|
|
|
|
"spaces in names",
|
|
|
|
"email@address",
|
|
|
|
"<output object>",
|
|
|
|
"[brackets]",
|
|
|
|
"{braces}",
|
|
|
|
"(parens)",
|
|
|
|
"C:\\windows\\paths",
|
|
|
|
"& @ $ % ^ * #",
|
|
|
|
"'quotes'",
|
|
|
|
"\"double quotes\"",
|
2023-11-20 08:59:00 +00:00
|
|
|
"double::colons", // https://github.com/pulumi/pulumi/issues/13968
|
2023-07-07 09:14:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range cases {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "1", resource.PropertyMap{}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2023-11-20 08:59:00 +00:00
|
|
|
// Check the name works as a provider
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pulumi:providers:pkgA", tt, true)
|
2023-07-07 09:14:20 +00:00
|
|
|
assert.NoError(t, err)
|
2023-11-20 08:59:00 +00:00
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
provRef, err := providers.NewReference(resp.URN, resp.ID)
|
2023-11-20 08:59:00 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// And a custom resource
|
2024-04-19 11:08:56 +00:00
|
|
|
respCustom, err := monitor.RegisterResource("pkgA:m:typA", tt, true, deploytest.ResourceOptions{
|
2023-11-20 08:59:00 +00:00
|
|
|
Provider: provRef.String(),
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// And a component resource
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typB", tt, false, deploytest.ResourceOptions{
|
2023-11-20 08:59:00 +00:00
|
|
|
// And as a URN parameter
|
2024-04-19 11:08:56 +00:00
|
|
|
Parent: respCustom.URN,
|
2023-11-20 08:59:00 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2023-07-07 09:14:20 +00:00
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2023-07-07 09:14:20 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2023-07-07 09:14:20 +00:00
|
|
|
}
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(p.GetProject(), p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-07-07 09:14:20 +00:00
|
|
|
|
2023-10-13 09:46:07 +00:00
|
|
|
require.NoError(t, err)
|
2023-11-20 08:59:00 +00:00
|
|
|
require.Len(t, snap.Resources, 3)
|
|
|
|
assert.Equal(t, resource.URN("urn:pulumi:test::test::pulumi:providers:pkgA::"+tt), snap.Resources[0].URN)
|
2023-07-07 09:14:20 +00:00
|
|
|
assert.Equal(t, resource.URN("urn:pulumi:test::test::pkgA:m:typA::"+tt), snap.Resources[1].URN)
|
2023-11-20 08:59:00 +00:00
|
|
|
assert.Equal(t, resource.URN("urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typB::"+tt), snap.Resources[2].URN)
|
2023-07-07 09:14:20 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
|
|
|
|
func TestSourcePositions(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "created-id", inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ReadF: func(urn resource.URN, id resource.ID,
|
|
|
|
inputs, state resource.PropertyMap,
|
|
|
|
) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
const regPos = "/test/source/positions#1,2"
|
|
|
|
const readPos = "/test/source/positions#3,4"
|
|
|
|
inputs := resource.PropertyMap{}
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
Inputs: inputs,
|
|
|
|
SourcePosition: "file://" + regPos,
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, _, err = monitor.ReadResource("pkgA:m:typA", "resB", "id", "", inputs, "", "", "file://"+readPos)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
}
|
|
|
|
regURN := p.NewURN("pkgA:m:typA", "resA", "")
|
|
|
|
readURN := p.NewURN("pkgA:m:typA", "resB", "")
|
|
|
|
|
|
|
|
// Run the initial update.
|
|
|
|
project := p.GetProject()
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
[engine] Add support for source positions
These changes add support for passing source position information in
gRPC metadata and recording the source position that corresponds to a
resource registration in the statefile.
Enabling source position information in the resource model can provide
substantial benefits, including but not limited to:
- Better errors from the Pulumi CLI
- Go-to-defintion for resources in state
- Editor integration for errors, etc. from `pulumi preview`
Source positions are (file, line) or (file, line, column) tuples
represented as URIs. The line and column are stored in the fragment
portion of the URI as "line(,column)?". The scheme of the URI and the
form of its path component depends on the context in which it is
generated or used:
- During an active update, the URI's scheme is `file` and paths are
absolute filesystem paths. This allows consumers to easily access
arbitrary files that are available on the host.
- In a statefile, the URI's scheme is `project` and paths are relative
to the project root. This allows consumers to resolve source positions
relative to the project file in different contexts irrespective of the
location of the project itself (e.g. given a project-relative path and
the URL of the project's root on GitHub, one can build a GitHub URL for
the source position).
During an update, source position information may be attached to gRPC
calls as "source-position" metadata. This allows arbitrary calls to be
associated with source positions without changes to their protobuf
payloads. Modifying the protobuf payloads is also a viable approach, but
is somewhat more invasive than attaching metadata, and requires changes
to every call signature.
Source positions should reflect the position in user code that initiated
a resource model operation (e.g. the source position passed with
`RegisterResource` for `pet` in the example above should be the source
position in `index.ts`, _not_ the source position in the Pulumi SDK). In
general, the Pulumi SDK should be able to infer the source position of
the resource registration, as the relationship between a resource
registration and its corresponding user code should be static per SDK.
Source positions in state files will be stored as a new `registeredAt`
property on each resource. This property is optional.
2023-06-29 18:41:19 +00:00
|
|
|
|
|
|
|
assert.Len(t, snap.Resources, 3)
|
|
|
|
|
|
|
|
reg := snap.Resources[1]
|
|
|
|
assert.Equal(t, regURN, reg.URN)
|
|
|
|
assert.Equal(t, "project://"+regPos, reg.SourcePosition)
|
|
|
|
|
|
|
|
read := snap.Resources[2]
|
|
|
|
assert.Equal(t, readURN, read.URN)
|
|
|
|
assert.Equal(t, "project://"+readPos, read.SourcePosition)
|
|
|
|
}
|
2023-07-18 15:10:23 +00:00
|
|
|
|
|
|
|
func TestBadResourceOptionURNs(t *testing.T) {
|
|
|
|
// Test for https://github.com/pulumi/pulumi/issues/13490, check that if a user (or SDK) sends a malformed
|
|
|
|
// URN we return an error.
|
|
|
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
name string
|
|
|
|
opts deploytest.ResourceOptions
|
|
|
|
assertFn func(err error)
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "malformed alias urn",
|
|
|
|
opts: deploytest.ResourceOptions{
|
2024-01-26 18:29:22 +00:00
|
|
|
Aliases: []*pulumirpc.Alias{
|
|
|
|
makeUrnAlias("very-bad urn"),
|
|
|
|
},
|
2023-07-18 15:10:23 +00:00
|
|
|
},
|
|
|
|
assertFn: func(err error) {
|
2023-12-15 17:45:32 +00:00
|
|
|
assert.ErrorContains(t, err, "invalid alias URN: invalid URN \"very-bad urn\"")
|
2023-07-18 15:10:23 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "malformed alias parent urn",
|
|
|
|
opts: deploytest.ResourceOptions{
|
2024-01-26 18:29:22 +00:00
|
|
|
Aliases: []*pulumirpc.Alias{
|
|
|
|
makeSpecAliasWithParent("", "", "", "", "very-bad urn"),
|
|
|
|
},
|
2023-07-18 15:10:23 +00:00
|
|
|
},
|
|
|
|
assertFn: func(err error) {
|
2023-12-15 17:45:32 +00:00
|
|
|
assert.ErrorContains(t, err, "invalid parent alias URN: invalid URN \"very-bad urn\"")
|
2023-07-18 15:10:23 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "malformed parent urn",
|
|
|
|
opts: deploytest.ResourceOptions{
|
|
|
|
Parent: "very-bad urn",
|
|
|
|
},
|
|
|
|
assertFn: func(err error) {
|
2023-12-15 17:45:32 +00:00
|
|
|
assert.ErrorContains(t, err, "invalid parent URN: invalid URN \"very-bad urn\"")
|
2023-07-18 15:10:23 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "malformed deleted with urn",
|
|
|
|
opts: deploytest.ResourceOptions{
|
|
|
|
DeletedWith: "very-bad urn",
|
|
|
|
},
|
|
|
|
assertFn: func(err error) {
|
2023-12-15 17:45:32 +00:00
|
|
|
assert.ErrorContains(t, err, "invalid DeletedWith URN: invalid URN \"very-bad urn\"")
|
2023-07-18 15:10:23 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "malformed dependency",
|
|
|
|
opts: deploytest.ResourceOptions{
|
|
|
|
Dependencies: []resource.URN{"very-bad urn"},
|
|
|
|
},
|
|
|
|
assertFn: func(err error) {
|
2023-12-15 17:45:32 +00:00
|
|
|
assert.ErrorContains(t, err, "invalid dependency URN: invalid URN \"very-bad urn\"")
|
2023-07-18 15:10:23 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tt := range cases {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(info plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "res", true, tt.opts)
|
2023-07-18 15:10:23 +00:00
|
|
|
tt.assertFn(err)
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2023-07-18 15:10:23 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2023-07-18 15:10:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
2023-10-11 14:44:09 +00:00
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2023-07-18 15:10:23 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-09-11 15:54:07 +00:00
|
|
|
|
|
|
|
func TestProviderChecksums(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}, deploytest.WithoutGrpc),
|
|
|
|
}
|
|
|
|
|
|
|
|
ins := resource.NewPropertyMapFromMap(map[string]interface{}{
|
|
|
|
"foo": "bar",
|
|
|
|
})
|
|
|
|
|
|
|
|
createResource := true
|
2023-09-28 21:50:18 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2023-09-11 15:54:07 +00:00
|
|
|
if createResource {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2023-09-11 15:54:07 +00:00
|
|
|
Inputs: ins,
|
|
|
|
PluginChecksums: map[string][]byte{
|
|
|
|
"windows-x64": {0, 1, 2, 3, 4},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2023-09-28 21:50:18 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2023-09-11 15:54:07 +00:00
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2023-09-11 15:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
|
|
|
|
// Run an update
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2023-09-11 15:54:07 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 2)
|
|
|
|
// Check the checksum was saved in the provider resource
|
|
|
|
assert.Equal(t, tokens.Type("pulumi:providers:pkgA"), snap.Resources[0].Type)
|
|
|
|
assert.Equal(t, "0001020304", snap.Resources[0].Inputs["pluginChecksums"].ObjectValue()["windows-x64"].StringValue())
|
|
|
|
|
|
|
|
// Delete the resource and ensure the checksums are passed to EnsurePlugins
|
|
|
|
createResource = false
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(project, p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2023-10-13 09:46:07 +00:00
|
|
|
assert.NoError(t, err)
|
2023-09-11 15:54:07 +00:00
|
|
|
assert.NotNil(t, snap)
|
|
|
|
assert.Len(t, snap.Resources, 0)
|
|
|
|
}
|
2023-10-18 10:33:04 +00:00
|
|
|
|
|
|
|
// Regression test for https://github.com/pulumi/pulumi/issues/14040, ensure the step generators automatic
|
|
|
|
// diff is tagged as an input diff.
|
|
|
|
func TestAutomaticDiff(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
inputs := resource.PropertyMap{
|
|
|
|
"foo": resource.NewNumberProperty(1),
|
|
|
|
}
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", true, deploytest.ResourceOptions{
|
2023-10-18 10:33:04 +00:00
|
|
|
Inputs: inputs,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2023-10-18 10:33:04 +00:00
|
|
|
}
|
|
|
|
resURN := p.NewURN("pkgA:m:typA", "resA", "")
|
|
|
|
|
|
|
|
// Run the initial update.
|
|
|
|
project := p.GetProject()
|
|
|
|
snap, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Change the inputs and run again
|
|
|
|
inputs = resource.PropertyMap{
|
|
|
|
"foo": resource.NewNumberProperty(2),
|
|
|
|
}
|
|
|
|
_, err = TestOp(Update).Run(project, p.GetTarget(t, snap), p.Options, true, p.BackendClient,
|
|
|
|
func(_ workspace.Project, _ deploy.Target, _ JournalEntries,
|
2024-05-06 17:34:24 +00:00
|
|
|
events []Event, err error,
|
2023-10-18 10:33:04 +00:00
|
|
|
) error {
|
|
|
|
found := false
|
|
|
|
for _, e := range events {
|
|
|
|
if e.Type == ResourcePreEvent {
|
|
|
|
p := e.Payload().(ResourcePreEventPayload).Metadata
|
|
|
|
if p.URN == resURN {
|
|
|
|
// Should find an update op with the diff set to an input diff
|
|
|
|
assert.Equal(t, deploy.OpUpdate, p.Op)
|
|
|
|
assert.Equal(t, []resource.PropertyKey{"foo"}, p.Diffs)
|
|
|
|
assert.Equal(t, map[string]plugin.PropertyDiff{
|
|
|
|
"foo": {
|
|
|
|
Kind: plugin.DiffUpdate,
|
|
|
|
InputDiff: true,
|
|
|
|
},
|
|
|
|
}, p.DetailedDiff)
|
|
|
|
found = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.True(t, found)
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
2024-02-06 16:46:31 +00:00
|
|
|
|
|
|
|
// Test that the engine only sends OutputValues for Construct and Call
|
|
|
|
func TestConstructCallSecretsUnknowns(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "created-id", inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ReadF: func(urn resource.URN, id resource.ID,
|
|
|
|
inputs, state resource.PropertyMap,
|
|
|
|
) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ConstructF: func(monitor *deploytest.ResourceMonitor, typ, name string, parent resource.URN,
|
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
|
|
|
) (plugin.ConstructResult, error) {
|
|
|
|
// Assert that "foo" is secret and "bar" is unknown
|
|
|
|
foo := inputs["foo"]
|
|
|
|
assert.True(t, foo.IsOutput())
|
|
|
|
assert.True(t, foo.OutputValue().Known)
|
|
|
|
assert.True(t, foo.OutputValue().Secret)
|
|
|
|
|
|
|
|
bar := inputs["bar"]
|
|
|
|
assert.True(t, bar.IsOutput())
|
|
|
|
assert.False(t, bar.OutputValue().Known)
|
|
|
|
assert.False(t, bar.OutputValue().Secret)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{})
|
2024-02-06 16:46:31 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2024-02-06 16:46:31 +00:00
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
CallF: func(monitor *deploytest.ResourceMonitor,
|
|
|
|
tok tokens.ModuleMember, args resource.PropertyMap,
|
|
|
|
info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
|
|
|
// Assert that "foo" is secret and "bar" is unknown
|
|
|
|
foo := args["foo"]
|
|
|
|
assert.True(t, foo.IsOutput())
|
|
|
|
assert.True(t, foo.OutputValue().Known)
|
|
|
|
assert.True(t, foo.OutputValue().Secret)
|
|
|
|
|
|
|
|
bar := args["bar"]
|
|
|
|
assert.True(t, bar.IsOutput())
|
|
|
|
assert.False(t, bar.OutputValue().Known)
|
|
|
|
assert.False(t, bar.OutputValue().Secret)
|
|
|
|
|
|
|
|
return plugin.CallResult{}, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
|
|
|
inputs := resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
}
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2024-02-06 16:46:31 +00:00
|
|
|
Remote: true,
|
|
|
|
Inputs: inputs,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-02-21 09:15:38 +00:00
|
|
|
_, _, _, err = monitor.Call("pkgA:m:typA", inputs, nil, "", "")
|
2024-02-06 16:46:31 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2024-02-06 16:46:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
2024-02-08 13:01:47 +00:00
|
|
|
|
|
|
|
// Test that the engine propagates dependencies from Construct and Call
|
|
|
|
func TestConstructCallReturnDependencies(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
test := func(t *testing.T, opt deploytest.PluginOption) {
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "created-id", inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ReadF: func(urn resource.URN, id resource.ID,
|
|
|
|
inputs, state resource.PropertyMap,
|
|
|
|
) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ConstructF: func(monitor *deploytest.ResourceMonitor, typ, name string, parent resource.URN,
|
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
|
|
|
) (plugin.ConstructResult, error) {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{})
|
2024-02-08 16:06:40 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
respA, err := monitor.RegisterResource("pkgA:m:typA", name+"-a", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
2024-02-08 16:06:40 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Return a secret and unknown output depending on some internal resource
|
2024-04-19 11:08:56 +00:00
|
|
|
deps := []resource.URN{respA.URN}
|
2024-02-08 16:06:40 +00:00
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2024-02-08 16:06:40 +00:00
|
|
|
Outputs: resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
},
|
|
|
|
OutputDependencies: map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": deps,
|
|
|
|
"bar": deps,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
CallF: func(monitor *deploytest.ResourceMonitor,
|
|
|
|
tok tokens.ModuleMember, args resource.PropertyMap,
|
|
|
|
info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
2024-03-15 09:05:18 +00:00
|
|
|
// Arg was sent as an output but the dependency map should still be filled in for providers to look at
|
2024-02-21 09:15:38 +00:00
|
|
|
assert.Equal(t,
|
|
|
|
[]resource.URN{"urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a"},
|
|
|
|
options.ArgDependencies["arg"])
|
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
// Assume a single output arg that this call depends on
|
|
|
|
arg := args["arg"]
|
|
|
|
deps := arg.OutputValue().Dependencies
|
|
|
|
|
|
|
|
return plugin.CallResult{
|
|
|
|
Return: resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
},
|
|
|
|
ReturnDependencies: map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": deps,
|
|
|
|
"bar": deps,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, opt),
|
|
|
|
}
|
2024-02-08 13:01:47 +00:00
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2024-02-08 16:06:40 +00:00
|
|
|
Remote: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
2024-02-08 13:01:47 +00:00
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
// The urn of the internal resource the component created
|
|
|
|
urn := resource.URN("urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a")
|
|
|
|
|
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from RegisterResource.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
2024-02-08 16:06:40 +00:00
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Dependencies)
|
2024-02-08 16:06:40 +00:00
|
|
|
|
|
|
|
result, deps, _, err := monitor.Call("pkgA:m:typA", resource.PropertyMap{
|
|
|
|
// Send this as an output value using the dependencies returned.
|
|
|
|
"arg": resource.NewOutputProperty(resource.Output{
|
2024-04-19 11:08:56 +00:00
|
|
|
Element: resp.Outputs["foo"].SecretValue().Element,
|
2024-02-08 16:06:40 +00:00
|
|
|
Known: true,
|
|
|
|
Secret: true,
|
|
|
|
Dependencies: []resource.URN{urn},
|
|
|
|
}),
|
2024-02-21 09:15:38 +00:00
|
|
|
}, nil, "", "")
|
2024-02-08 16:06:40 +00:00
|
|
|
assert.NoError(t, err)
|
2024-02-08 13:01:47 +00:00
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from Call.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
}, result)
|
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
|
|
|
}, deps)
|
2024-02-08 13:01:47 +00:00
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
return nil
|
2024-02-08 13:01:47 +00:00
|
|
|
})
|
2024-02-08 16:06:40 +00:00
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
2024-02-08 13:01:47 +00:00
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2024-02-08 16:06:40 +00:00
|
|
|
}
|
2024-02-08 13:01:47 +00:00
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
project := p.GetProject()
|
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, true, p.BackendClient, nil)
|
2024-02-08 13:01:47 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
2024-02-08 16:06:40 +00:00
|
|
|
t.Run("WithGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithGrpc)
|
|
|
|
})
|
|
|
|
t.Run("WithoutGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithoutGrpc)
|
|
|
|
})
|
2024-02-08 13:01:47 +00:00
|
|
|
}
|
2024-02-14 08:15:24 +00:00
|
|
|
|
|
|
|
// Test that the engine can receive OutputValues for Construct and Call
|
|
|
|
func TestConstructCallReturnOutputs(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
test := func(t *testing.T, opt deploytest.PluginOption) {
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "created-id", inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ReadF: func(urn resource.URN, id resource.ID,
|
|
|
|
inputs, state resource.PropertyMap,
|
|
|
|
) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ConstructF: func(monitor *deploytest.ResourceMonitor, typ, name string, parent resource.URN,
|
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
|
|
|
) (plugin.ConstructResult, error) {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{})
|
2024-02-14 08:15:24 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
respA, err := monitor.RegisterResource("pkgA:m:typA", name+"-a", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
2024-02-14 08:15:24 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Return a secret and unknown output depending on some internal resource
|
2024-04-19 11:08:56 +00:00
|
|
|
deps := []resource.URN{respA.URN}
|
2024-02-14 08:15:24 +00:00
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2024-02-14 08:15:24 +00:00
|
|
|
Outputs: resource.PropertyMap{
|
|
|
|
"foo": resource.NewOutputProperty(resource.Output{
|
|
|
|
Element: resource.NewStringProperty("foo"),
|
|
|
|
Known: true,
|
|
|
|
Secret: true,
|
|
|
|
Dependencies: deps,
|
|
|
|
}),
|
|
|
|
"bar": resource.NewOutputProperty(resource.Output{
|
|
|
|
Dependencies: deps,
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
OutputDependencies: nil, // Left blank on purpose because AcceptsOutputs is true
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
CallF: func(monitor *deploytest.ResourceMonitor,
|
|
|
|
tok tokens.ModuleMember, args resource.PropertyMap,
|
|
|
|
info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
2024-03-15 09:05:18 +00:00
|
|
|
// Arg was sent as an output but the dependency map should still be filled in for providers to look at
|
2024-02-21 09:15:38 +00:00
|
|
|
assert.Equal(t,
|
|
|
|
[]resource.URN{"urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a"},
|
|
|
|
options.ArgDependencies["arg"])
|
|
|
|
|
2024-02-14 08:15:24 +00:00
|
|
|
// Assume a single output arg that this call depends on
|
|
|
|
arg := args["arg"]
|
|
|
|
deps := arg.OutputValue().Dependencies
|
|
|
|
|
|
|
|
return plugin.CallResult{
|
|
|
|
Return: resource.PropertyMap{
|
|
|
|
"foo": resource.NewOutputProperty(resource.Output{
|
|
|
|
Element: resource.NewStringProperty("foo"),
|
|
|
|
Known: true,
|
|
|
|
Secret: true,
|
|
|
|
Dependencies: deps,
|
|
|
|
}),
|
|
|
|
"bar": resource.NewOutputProperty(resource.Output{
|
|
|
|
Dependencies: deps,
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
ReturnDependencies: nil, // Left blank on purpose because AcceptsOutputs is true
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, opt),
|
|
|
|
}
|
|
|
|
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2024-02-14 08:15:24 +00:00
|
|
|
Remote: true,
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// The urn of the internal resource the component created
|
|
|
|
urn := resource.URN("urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a")
|
|
|
|
|
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from RegisterResource.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
2024-02-14 08:15:24 +00:00
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Dependencies)
|
2024-02-14 08:15:24 +00:00
|
|
|
|
|
|
|
result, deps, _, err := monitor.Call("pkgA:m:typA", resource.PropertyMap{
|
|
|
|
// Send this as an output value using the dependencies returned.
|
|
|
|
"arg": resource.NewOutputProperty(resource.Output{
|
2024-04-19 11:08:56 +00:00
|
|
|
Element: resp.Outputs["foo"].SecretValue().Element,
|
2024-02-14 08:15:24 +00:00
|
|
|
Known: true,
|
|
|
|
Secret: true,
|
|
|
|
Dependencies: []resource.URN{urn},
|
|
|
|
}),
|
2024-02-21 09:15:38 +00:00
|
|
|
}, nil, "", "")
|
2024-02-14 08:15:24 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from Call.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
}, result)
|
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
|
|
|
}, deps)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2024-02-14 08:15:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, true, p.BackendClient, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
t.Run("WithGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithGrpc)
|
|
|
|
})
|
|
|
|
t.Run("WithoutGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithoutGrpc)
|
|
|
|
})
|
|
|
|
}
|
2024-03-15 09:05:18 +00:00
|
|
|
|
|
|
|
// Test that the engine fills in dependencies to Construct and Call given just OutputValues
|
|
|
|
func TestConstructCallSendDependencies(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
test := func(t *testing.T, opt deploytest.PluginOption) {
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "created-id", inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ReadF: func(urn resource.URN, id resource.ID,
|
|
|
|
inputs, state resource.PropertyMap,
|
|
|
|
) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ConstructF: func(monitor *deploytest.ResourceMonitor, typ, name string, parent resource.URN,
|
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
|
|
|
) (plugin.ConstructResult, error) {
|
|
|
|
// Arg was sent as an output but the dependency map should still be filled in for providers to look at
|
|
|
|
assert.Equal(t,
|
|
|
|
[]resource.URN{"urn:pulumi:test::test::pkgA:m:typC::resC"},
|
|
|
|
options.PropertyDependencies["arg"])
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{})
|
2024-03-15 09:05:18 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
respA, err := monitor.RegisterResource("pkgA:m:typA", name+"-a", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
2024-03-15 09:05:18 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Return a secret and unknown output depending on some internal resource
|
2024-04-19 11:08:56 +00:00
|
|
|
deps := []resource.URN{respA.URN}
|
2024-03-15 09:05:18 +00:00
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2024-03-15 09:05:18 +00:00
|
|
|
Outputs: resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
},
|
|
|
|
OutputDependencies: map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": deps,
|
|
|
|
"bar": deps,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
CallF: func(monitor *deploytest.ResourceMonitor,
|
|
|
|
tok tokens.ModuleMember, args resource.PropertyMap,
|
|
|
|
info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
|
|
|
// Arg was sent as an output but the dependency map should still be filled in for providers to look at
|
|
|
|
assert.Equal(t,
|
|
|
|
[]resource.URN{"urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a"},
|
|
|
|
options.ArgDependencies["arg"])
|
|
|
|
|
|
|
|
// Assume a single output arg that this call depends on
|
|
|
|
arg := args["arg"]
|
|
|
|
deps := arg.OutputValue().Dependencies
|
|
|
|
|
|
|
|
return plugin.CallResult{
|
|
|
|
Return: resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
},
|
|
|
|
ReturnDependencies: map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": deps,
|
|
|
|
"bar": deps,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, opt),
|
|
|
|
}
|
|
|
|
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
respC, err := monitor.RegisterResource("pkgA:m:typC", "resC", false, deploytest.ResourceOptions{
|
2024-03-15 09:05:18 +00:00
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"arg": resource.NewNumberProperty(1),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2024-03-15 09:05:18 +00:00
|
|
|
Remote: true,
|
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"arg": resource.NewOutputProperty(resource.Output{
|
2024-04-19 11:08:56 +00:00
|
|
|
Element: respC.Outputs["arg"],
|
2024-03-15 09:05:18 +00:00
|
|
|
Known: true,
|
2024-04-19 11:08:56 +00:00
|
|
|
Dependencies: []resource.URN{respC.URN},
|
2024-03-15 09:05:18 +00:00
|
|
|
}),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// The urn of the internal resource the component created
|
|
|
|
urn := resource.URN("urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a")
|
|
|
|
|
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from RegisterResource.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
2024-03-15 09:05:18 +00:00
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Dependencies)
|
2024-03-15 09:05:18 +00:00
|
|
|
|
|
|
|
result, deps, _, err := monitor.Call("pkgA:m:typA", resource.PropertyMap{
|
|
|
|
// Send this as an output value using the dependencies returned.
|
|
|
|
"arg": resource.NewOutputProperty(resource.Output{
|
2024-04-19 11:08:56 +00:00
|
|
|
Element: resp.Outputs["foo"].SecretValue().Element,
|
2024-03-15 09:05:18 +00:00
|
|
|
Known: true,
|
|
|
|
Secret: true,
|
|
|
|
Dependencies: []resource.URN{urn},
|
|
|
|
}),
|
|
|
|
}, nil, "", "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from Call.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
}, result)
|
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
|
|
|
}, deps)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2024-03-15 09:05:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, true, p.BackendClient, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("WithGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithGrpc)
|
|
|
|
})
|
|
|
|
t.Run("WithoutGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithoutGrpc)
|
|
|
|
})
|
|
|
|
}
|
2024-03-15 13:01:45 +00:00
|
|
|
|
|
|
|
// Test that the engine deduplicated dependencies to Construct and Call given OutputValues and dependency maps.
|
|
|
|
func TestConstructCallDependencyDedeuplication(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
test := func(t *testing.T, opt deploytest.PluginOption) {
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, inputs resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "created-id", inputs, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ReadF: func(urn resource.URN, id resource.ID,
|
|
|
|
inputs, state resource.PropertyMap,
|
|
|
|
) (plugin.ReadResult, resource.Status, error) {
|
|
|
|
return plugin.ReadResult{Inputs: inputs, Outputs: state}, resource.StatusOK, nil
|
|
|
|
},
|
|
|
|
ConstructF: func(monitor *deploytest.ResourceMonitor, typ, name string, parent resource.URN,
|
|
|
|
inputs resource.PropertyMap, info plugin.ConstructInfo, options plugin.ConstructOptions,
|
|
|
|
) (plugin.ConstructResult, error) {
|
|
|
|
// Arg was sent as an output but the dependency map should still be filled in for providers to look at
|
|
|
|
assert.Equal(t,
|
|
|
|
[]resource.URN{"urn:pulumi:test::test::pkgA:m:typC::resC"},
|
|
|
|
options.PropertyDependencies["arg"])
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(tokens.Type(typ), name, false, deploytest.ResourceOptions{})
|
2024-03-15 13:01:45 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
respA, err := monitor.RegisterResource("pkgA:m:typA", name+"-a", true, deploytest.ResourceOptions{
|
|
|
|
Parent: resp.URN,
|
2024-03-15 13:01:45 +00:00
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Return a secret and unknown output depending on some internal resource
|
2024-04-19 11:08:56 +00:00
|
|
|
deps := []resource.URN{respA.URN}
|
2024-03-15 13:01:45 +00:00
|
|
|
return plugin.ConstructResult{
|
2024-04-19 11:08:56 +00:00
|
|
|
URN: resp.URN,
|
2024-03-15 13:01:45 +00:00
|
|
|
Outputs: resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
},
|
|
|
|
OutputDependencies: map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": deps,
|
|
|
|
"bar": deps,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
CallF: func(monitor *deploytest.ResourceMonitor,
|
|
|
|
tok tokens.ModuleMember, args resource.PropertyMap,
|
|
|
|
info plugin.CallInfo, options plugin.CallOptions,
|
|
|
|
) (plugin.CallResult, error) {
|
|
|
|
// Arg was sent as an output but the dependency map should still be filled in for providers to look at
|
|
|
|
assert.Equal(t,
|
|
|
|
[]resource.URN{"urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a"},
|
|
|
|
options.ArgDependencies["arg"])
|
|
|
|
|
|
|
|
// Assume a single output arg that this call depends on
|
|
|
|
arg := args["arg"]
|
|
|
|
deps := arg.OutputValue().Dependencies
|
|
|
|
|
|
|
|
return plugin.CallResult{
|
|
|
|
Return: resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
},
|
|
|
|
ReturnDependencies: map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": deps,
|
|
|
|
"bar": deps,
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}, opt),
|
|
|
|
}
|
|
|
|
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
respC, err := monitor.RegisterResource("pkgA:m:typC", "resC", false, deploytest.ResourceOptions{
|
2024-03-15 13:01:45 +00:00
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"arg": resource.NewNumberProperty(1),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource("pkgA:m:typA", "resA", false, deploytest.ResourceOptions{
|
2024-03-15 13:01:45 +00:00
|
|
|
Remote: true,
|
|
|
|
Inputs: resource.PropertyMap{
|
|
|
|
"arg": resource.NewOutputProperty(resource.Output{
|
2024-04-19 11:08:56 +00:00
|
|
|
Element: respC.Outputs["arg"],
|
2024-03-15 13:01:45 +00:00
|
|
|
Known: true,
|
2024-04-19 11:08:56 +00:00
|
|
|
Dependencies: []resource.URN{respC.URN},
|
2024-03-15 13:01:45 +00:00
|
|
|
}),
|
|
|
|
},
|
|
|
|
PropertyDeps: map[resource.PropertyKey][]resource.URN{
|
2024-04-19 11:08:56 +00:00
|
|
|
"arg": {respC.URN},
|
2024-03-15 13:01:45 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// The urn of the internal resource the component created
|
|
|
|
urn := resource.URN("urn:pulumi:test::test::pkgA:m:typA$pkgA:m:typA::resA-a")
|
|
|
|
|
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from RegisterResource.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Outputs)
|
2024-03-15 13:01:45 +00:00
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
2024-04-19 11:08:56 +00:00
|
|
|
}, resp.Dependencies)
|
2024-03-15 13:01:45 +00:00
|
|
|
|
|
|
|
result, deps, _, err := monitor.Call("pkgA:m:typA", resource.PropertyMap{
|
|
|
|
// Send this as an output value using the dependencies returned.
|
|
|
|
"arg": resource.NewOutputProperty(resource.Output{
|
2024-04-19 11:08:56 +00:00
|
|
|
Element: resp.Outputs["foo"].SecretValue().Element,
|
2024-03-15 13:01:45 +00:00
|
|
|
Known: true,
|
|
|
|
Secret: true,
|
|
|
|
Dependencies: []resource.URN{urn},
|
|
|
|
}),
|
|
|
|
}, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"arg": {urn},
|
|
|
|
}, "", "")
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
// Assert that the outputs are received as just plain values because SDKs don't yet support output
|
|
|
|
// values returned from Call.
|
|
|
|
assert.Equal(t, resource.PropertyMap{
|
|
|
|
"foo": resource.MakeSecret(resource.NewStringProperty("foo")),
|
|
|
|
"bar": resource.MakeComputed(resource.NewStringProperty("")),
|
|
|
|
}, result)
|
|
|
|
assert.Equal(t, map[resource.PropertyKey][]resource.URN{
|
|
|
|
"foo": {urn},
|
|
|
|
"bar": {urn},
|
|
|
|
}, deps)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
|
|
|
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2024-03-15 13:01:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
project := p.GetProject()
|
|
|
|
_, err := TestOp(Update).Run(project, p.GetTarget(t, nil), p.Options, true, p.BackendClient, nil)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("WithGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithGrpc)
|
|
|
|
})
|
|
|
|
t.Run("WithoutGrpc", func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
test(t, deploytest.WithoutGrpc)
|
|
|
|
})
|
|
|
|
}
|
2024-03-22 09:22:40 +00:00
|
|
|
|
2024-03-25 22:37:46 +00:00
|
|
|
// TestStackOutputsProgramError tests that previous stack outputs aren't deleted when an update fails because
|
|
|
|
// of a program error.
|
|
|
|
func TestStackOutputsProgramError(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
var step int
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(resource.RootStackType, "test", false)
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
val := resource.NewProperty(fmt.Sprintf("step %v", step))
|
|
|
|
|
|
|
|
var outputs resource.PropertyMap
|
|
|
|
|
|
|
|
switch step {
|
|
|
|
case 0, 3:
|
|
|
|
outputs = resource.PropertyMap{
|
|
|
|
"first": val,
|
|
|
|
"second": val,
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
// If an error is raised between calling `pulumi.export("first", ...)` and `pulumi.export("second", ...)`
|
|
|
|
// in SDKs like Python and Go, the first export is still registered via RegisterResourceOutputs.
|
|
|
|
// This test simulates that by not including "second" when the program will error.
|
|
|
|
outputs = resource.PropertyMap{
|
|
|
|
"first": val,
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
// The Node.js SDK is a bit different, when an error is thrown between module exports, none of the exports
|
|
|
|
// are included. An empty set of outputs is registered via RegisterResourceOutputs.
|
|
|
|
outputs = resource.PropertyMap{}
|
|
|
|
}
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
err = monitor.RegisterResourceOutputs(resp.URN, outputs)
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
if step == 1 || step == 2 {
|
|
|
|
return errors.New("program error")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF},
|
2024-03-25 22:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
validateSnapshot := func(snap *deploy.Snapshot, expectedResourceCount int, expectedOutputs resource.PropertyMap) {
|
|
|
|
assert.Len(t, snap.Resources, expectedResourceCount)
|
|
|
|
assert.Equal(t, resource.RootStackType, snap.Resources[0].Type)
|
|
|
|
assert.Equal(t, expectedOutputs, snap.Resources[0].Outputs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the initial update which sets some stack outputs.
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
validateSnapshot(snap, 1, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 0"),
|
|
|
|
"second": resource.NewProperty("step 0"),
|
|
|
|
})
|
|
|
|
|
|
|
|
// Run another update where the program fails before registering all of the stack outputs, simulating the behavior
|
|
|
|
// of returning an error after only the first output is set.
|
|
|
|
// Ensure the original stack outputs are preserved.
|
|
|
|
step = 1
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.ErrorContains(t, err, "program error")
|
|
|
|
validateSnapshot(snap, 1, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 1"),
|
|
|
|
"second": resource.NewProperty("step 0"), // Prior output is preserved
|
|
|
|
})
|
|
|
|
|
|
|
|
// Run another update that fails to update both stack updates.
|
|
|
|
// Ensure the prior stack outputs are preserved.
|
|
|
|
step = 2
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "2")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.ErrorContains(t, err, "program error")
|
|
|
|
validateSnapshot(snap, 1, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 1"), // Prior output is preserved
|
|
|
|
"second": resource.NewProperty("step 0"), // Prior output is preserved
|
|
|
|
})
|
|
|
|
|
|
|
|
// Run again, this time without erroring, to ensure the stack outputs are updated.
|
|
|
|
step = 3
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "3")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
validateSnapshot(snap, 1, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 3"),
|
|
|
|
"second": resource.NewProperty("step 3"),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestStackOutputsResourceError tests that previous stack outputs aren't deleted when an update fails
|
|
|
|
// due to a resource operation error.
|
|
|
|
func TestStackOutputsResourceError(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
var step int
|
|
|
|
|
|
|
|
loaders := []*deploytest.ProviderLoader{
|
|
|
|
deploytest.NewProviderLoader("pkgA", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
|
|
|
|
return &deploytest.Provider{
|
|
|
|
CreateF: func(urn resource.URN, news resource.PropertyMap, timeout float64,
|
|
|
|
preview bool,
|
|
|
|
) (resource.ID, resource.PropertyMap, resource.Status, error) {
|
|
|
|
return "", nil, resource.StatusUnknown, errors.New("oh no")
|
|
|
|
},
|
|
|
|
}, nil
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
|
|
|
|
programF := deploytest.NewLanguageRuntimeF(func(_ plugin.RunInfo, monitor *deploytest.ResourceMonitor) error {
|
2024-04-19 11:08:56 +00:00
|
|
|
resp, err := monitor.RegisterResource(resource.RootStackType, "test", false)
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
|
|
val := resource.NewProperty(fmt.Sprintf("step %v", step))
|
|
|
|
|
|
|
|
switch step {
|
|
|
|
case 0, 3:
|
2024-04-19 11:08:56 +00:00
|
|
|
outsErr := monitor.RegisterResourceOutputs(resp.URN, resource.PropertyMap{
|
2024-03-25 22:37:46 +00:00
|
|
|
"first": val,
|
|
|
|
"second": val,
|
|
|
|
})
|
|
|
|
assert.NoError(t, outsErr)
|
|
|
|
|
|
|
|
case 1:
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.ErrorContains(t, err, "oh no")
|
|
|
|
// RegisterResourceOutputs not called here, simulating what happens in SDKs when an output of resA
|
|
|
|
// is exported as a stack output.
|
|
|
|
|
|
|
|
case 2:
|
2024-04-19 11:08:56 +00:00
|
|
|
outsErr := monitor.RegisterResourceOutputs(resp.URN, resource.PropertyMap{
|
2024-03-25 22:37:46 +00:00
|
|
|
"first": val,
|
|
|
|
"second": val,
|
|
|
|
})
|
|
|
|
assert.NoError(t, outsErr)
|
|
|
|
|
2024-04-19 11:08:56 +00:00
|
|
|
_, err = monitor.RegisterResource("pkgA:m:typA", "resA", true)
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.ErrorContains(t, err, "oh no")
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
|
|
|
hostF := deploytest.NewPluginHostF(nil, nil, programF, loaders...)
|
|
|
|
p := &TestPlan{
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
// Skip display tests because secrets are serialized with the blinding crypter and can't be restored
|
|
|
|
Options: TestUpdateOptions{T: t, HostF: hostF, SkipDisplayTests: true},
|
2024-03-25 22:37:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
validateSnapshot := func(snap *deploy.Snapshot, expectedResourceCount int, expectedOutputs resource.PropertyMap) {
|
|
|
|
assert.Len(t, snap.Resources, expectedResourceCount)
|
|
|
|
assert.Equal(t, resource.RootStackType, snap.Resources[0].Type)
|
|
|
|
assert.Equal(t, expectedOutputs, snap.Resources[0].Outputs)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run the initial update which sets some stack outputs.
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err := TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, nil), p.Options, false, p.BackendClient, nil, "0")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
validateSnapshot(snap, 1, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 0"),
|
|
|
|
"second": resource.NewProperty("step 0"),
|
|
|
|
})
|
|
|
|
|
|
|
|
// Run another that simulates creating a resource that will error during creation and exporting an output of that
|
|
|
|
// resource as a stack output, in which case no RegisterResourceOutputs call is made.
|
|
|
|
step = 1
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "1")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.ErrorContains(t, err, "oh no")
|
|
|
|
validateSnapshot(snap, 2, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 0"), // Original output is preserved
|
|
|
|
"second": resource.NewProperty("step 0"), // Original output is preserved
|
|
|
|
})
|
|
|
|
|
|
|
|
// Run another update that still registers a resource that will fail during creation, but do that after the
|
|
|
|
// stack outputs are registered, which is in-line with the behavior of real-world programs.
|
|
|
|
step = 2
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "2")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.ErrorContains(t, err, "oh no")
|
|
|
|
validateSnapshot(snap, 2, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 2"),
|
|
|
|
"second": resource.NewProperty("step 2"),
|
|
|
|
})
|
|
|
|
|
|
|
|
// Run again, this time without erroring, to ensure the stack outputs are updated.
|
|
|
|
step = 3
|
Add display to the engine tests (#16050)
We want to add more test coverage to the display code. The best way to
do that is to add it to the engine tests, that already cover most of the
pulumi functionality.
It's probably not really possible to review all of the output, but at
least it gives us a baseline, which we can work with.
There's a couple of tests that are flaky for reasons I don't quite
understand yet. I marked them as to skip and we can look at them later.
I'd rather get in the baseline tests sooner, rather than spending a
bunch of time looking at that. The output differences also seem very
minor, so not super concerning.
The biggest remaining issue is that this doesn't interact well with the
Chdir we're doing in the engine. We could either pass the CWD through,
or just try to get rid of that Chdir. So this should only be merged
after https://github.com/pulumi/pulumi/pull/15607.
I've tried to split this into a few commits, separating out adding the
testdata, so it's hopefully a little easier to review, even though the
PR is still quite large.
One other thing to note is that we're comparing that the output has all
the same lines, and not that it is exactly the same. Because of how the
engine is implemented, there's a bunch of race conditions otherwise,
that would make us have to skip a bunch of tests, just because e.g.
resource A is sometimes deleted before resource B and sometimes it's the
other way around.
The biggest downside of that is that running with `PULUMI_ACCEPT` will
produce a diff even when there are no changes. Hopefully we won't have
to run that way too often though, so it might not be a huge issue?
---------
Co-authored-by: Fraser Waters <fraser@pulumi.com>
2024-05-13 07:18:25 +00:00
|
|
|
snap, err = TestOp(Update).RunStep(p.GetProject(), p.GetTarget(t, snap), p.Options, false, p.BackendClient, nil, "3")
|
2024-03-25 22:37:46 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
validateSnapshot(snap, 1, resource.PropertyMap{
|
|
|
|
"first": resource.NewProperty("step 3"),
|
|
|
|
"second": resource.NewProperty("step 3"),
|
|
|
|
})
|
|
|
|
}
|