dotnet, nodejs and python automation APIs did not specify exec-kind for
refresh or destroy operations. This is now added following the same
logic from the go automation API.
When using the filestate backend (local files and cloud buckets) there is no protection to prevent two processes from managing the same stack simultaneously.
This PR creates a locks directory in the management directory that stores lock files for a stack. Each backend implementation gets its own UUID that is joined with the stack name. The feature is currently available behind the `PULUMI_SELF_MANAGED_STATE_LOCKING=1` environment variable flag.
This change avoids `RuntimeError: There is no current event loop in thread '<thread_name>'` errors when passing a resource as an input multiple times when using mocks.
The problem is that when using mocks, we deserialize the gRPC inputs before passing them to the user's mock methods. Deserializing inputs doesn't typically require an event loop, however, during deserialization of resource references, we end up creating some instances of `Future`, which does require an event loop to be present for the current thread. If this is done multiple times for a resource, it's possible that `deserialize_properties` will be called on an asyncio thread that doesn't yet have an event loop, resulting in the error being raised.
The error does not occur when only passing the resource reference once because typically the thread (e.g. `asyncio_0`) used in that case will have already had an event loop created for it due to the use of the internal `_syncawait` when _serializing_ the source resource's properties, which ensures an event loop is set for the thread.
The fix is to ensure an event loop is created for the thread in the mocks implementation before calling `deserialize_properties`.
It is possible for the same version of the same provider SDK to be loaded multiple times in Node.js. In this case, we might legitimately get mutliple registrations of the same resource. It should not matter which we use, so we can just skip re-registering. De-serialized resources will always be instances of classes from the first registered package.
Example layout this addresses. Registrations of resources in `package3` at the same verrsion.
`node_modules`
`@pulumi/pulumi`
`package1`
`node_modules`
`package3`
`package2`
`node_modules`
`package3`
Fixes#6258.
* Init Workspace interface for C# Automation API
* fleshing out workspace interface and beginning of local workspace implementation
* initial run pulumi cmd implementation
* resolve issue with pulumi cmd cleanup wrapper task after testing
* flesh out local workspace implementation, flesh out stack implementation, cleanup run pulumi cmd implementation and make it an instance so it is mockable/testable, separate serialization in prep for custom converters
* project settings json serialization implemented
* Initial commit of language server
* Add deployment from language server
* Cleanup
* finish json serialization
* project runtime yaml serialization completed. just need stack config value yaml serialization
* Remove typed argument
* Limit concurrency
* Rename file for consistency
* final commit of a semi-working project settings & stack settings serialization so that it is in the commit history
* modify workspace API so that settings accessors aren't fully exposed since we are defering a complete serialization implementation until a later date
* yaml converters wrap any outgoing exceptions so resolve that
* getting the beginning of inline program GRPC communication set up
* stack lifecycle operations implemented, and switched to newtonsoft for JSON serialization
* change back to system.text.json with a custom object converter
* local workspace tests written, working on getting them passing
* fix the encoding on the GO files used for testing
* all tests passing except inline program, pulumi engine not available with inline
* inline program engine is now running as expecting, but inline program is not recognizing local stack config
* All tests passing, but no concurrency capability because of the singleton DeploymentInstance.
* cleanup unnecessary usings
* minor cleanup / changes after a quick review. Make sure ConfigureAwait is used where needed. Remove newtonsoft dependency from testing. Update workspace API to use existing PluginKind enum. Modify LanguageRuntimeService so that its semaphore operates process-wide.
* support for parallel execution of inline program, test included
* Update LocalWorkspaceTests.cs
remove some redundancy from the inline program parallel execution text
* flesh out some comments and make asynclocal instance readonly
* Strip out instance locking since it is no longer necessary with AsyncLocal wrapping the Deployment.Instance. Modify CreateRunner method such that we are ensuring there isn't a chance of delayed synchronous execution polluting the value of Deployment.Instance across calls to Deployment.RunAsync
* resolve conflicts with changes made to Deployment.TestAsync entrypoints
* update changelog
* write a test that fails if the CreateRunnerAndRunAsync method on Deployment is not marked async and fix test project data file ref
* make resource package state share the lifetime of the deployment so that their isn't cross deployment issues with resource packages, add support and tests for external resource packages (resource packages that aren't referenced by the executing assembly)
* enable parallel test collection execution in test suite, add some additional tests for deployment instance protection and ensuring that our first class stack exceptions are thrown when expected
* minor inline project name arg change, and re-add xunit json to build output (whoops)
* strip out concurrency changes since they are now in #6139, split automation into separate assembly, split automation tests into separate assembly
* add copyright to the top of each new file
* resolve some PR remarks
* inline program exception is now properly propagated to the caller on UpAsync and PreviewAsync
* modify PulumiFn to allow TStack and other delegate overloads without needing multiple first class delegates.
* whoops missing a copyright
* resolve getting TStack into IRunner so that outputs are registered correctly and so that there isn't 2 instances of Pulumi.Stack instantiated.
* resolve issue with propagation of TStack exceptions and add a test
* add support for a TStack PulumiFn resolved via IServiceProvider
* update automation API description
* fix comment and remove unnecessary TODOs
* disable packaging of automation api assembly
* re-name automation api documentation file appropriately
* add --limit support to dotnet automation api for stack history per #6257
* re-name XStack as WorkspaceStack
* replace --limit usage with --page-size and --page in dotnet automation api per #6292
Co-authored-by: evanboyle <evan@pulumi.com>
Co-authored-by: Josh Studt <josh.studt@figmarketing.com>
Co-authored-by: Dan Friedman <dan@thefriedmans.org>
Co-authored-by: David Ferretti <David.Ferretti@figmarketing.com>
Co-authored-by: Mikhail Shilkov <github@mikhail.io>
We previously looked for `python3` and fallback to `python` on all systems. However, our Windows CI images include a `python3.exe` symlink to `python.exe` which does not work with `venv`. So on Windows, just look for `python` first, falling back to `python3`. (The default python.org Windows installation only includes `python.exe`).
Adds a `--limit` flag to `pulumi stack history. This allows limiting to the last few entries rather than fetching the entirety of a stack's update history (which can be quite slow for stacks with lots of updates). Example: `pulumi stack history --limit 1` fetches the last history entry only.
`stack.up` and related operations in the Automation API have been updated to consume this change, drastically reducing overhead.
`Output.from_input` deeply unwraps nested output values in dicts and lists, but doesn't currently do that for the more recently added "input types" (i.e. args classes). This leads to errors when using args classes with output values with `Provider` resources, which uses `Output.from_input` on each input property and then serializes the value to JSON in an `apply`. This changes fixes `Output.from_input` to recurse into values within args classes to properly unwrap any nested outputs.
Promise leak debugging was accidentally toStringing an Output, leading to a red herring for several users trying to understand what was causing promise leaks.
Related to #6153 and #5853.
.NET's implementation of RegisterResourceOutputs was always serializing resources as resource references, regardless of the monitor's reported support. This change fixes .NET to check if the monitor supports resource references, which is consistent with all the other languages, and with serialization code elsewhere in the .NET SDK.
* Fix resource-ref-as-ID marshaling. (#6125)
This reapplies 2f0dba23ab.
* Fix malformed resource value bug
PR #6125 introduced a bug by marshaling resource
ids as PropertyValues, but not handling that case on
the unmarshaling side. The previous code assumed
that the id was a simple string value. This bug prevents
any stack update operations (preview, update, destroy,
refresh). Since this change was already
released, we must now handle both cases in the
unmarshaling code.
* Add resource ref unit tests for the Go SDK. (#6142)
This reapplies 3d505912b8.
Co-authored-by: Pat Gavlin <pat@pulumi.com>
- Add tests that deserialize known custom and component resources
- Add tests that deserialize missing custom and component resources
These changes also add support for deserializing resources with missing
modules/packages. Such resources are deserialized as generic component,
custom, or provider resources as appropriate.
Contributes to #5943.
- Add tests that deserialize known custom and component resources
- Add tests that deserialize missing custom and component resources
These changes also add support for deserializing resources with missing
modules/packages. Such resources are deserialized as generic component,
custom, or provider resources as appropriate.
Contributes to #5943.
When marshaling a resource reference as its ID (i.e. when
opts.KeepResources is false, as it will be in the case of downlevel SDKs
and resource providers), we must take care to marshal/unmarshal an empty
ID as the unknown property value.
This includes the following changes to the resource ref APIs:
- Bifurcate resource reference creation into two methods: one for
creating references to custom resources and one for creating
references to component resources.
- Store the ID in a resource reference as a PropertyValue s.t. it can be
computed.
- Add a helper method for retrieving the ID as a string + an indicator of
whether or not the reference has an ID.
Fixes#5939.
Related: #5653
This will take an existing output and then unwrap the secret, and
return a new output
```
import * as pulumi from "@pulumi/pulumi";
const x = pulumi.secret("test")
export const xVal = x;
const y = pulumi.unsecret(x);
export const yVal = y;
```
```
▶ pulumi stack output
Current stack outputs (3):
OUTPUT VALUE
xVal [secret]
yVal test
```
Also adds the ability to check if an output is as secret:
```
import * as pulumi from "@pulumi/pulumi";
const x = pulumi.secret("test")
const isSecret = x.isSecret;
export const isSecretDeets = isSecret;
```
- Add tests that serialize custom and component resources for targets
that support resource references
- Add tests that serialize custom and component resources for downlevel
targets
- Add tests that deserialize known custom and component resources
- Add tests that deserialize missing custom and component resources
These changes also fix a few bugs that were encountered during testing:
- Component resource construction was not supported
- Resources with missing packages could not be deserialized
In the latter case, a missing resource is deserialized as a generic
DependencyResource.
These changes also update the signature of IMocks.NewResourceAsync to
allow the returned ID to be null. This is technically a C# breaking change
with respect to nullability.
Contributes to #5943.
Co-authored-by: Mikhail Shilkov <github@mikhail.io>
In order to support resource construction in the Go SDK, the
engine context needs to be available in the RPC unmarshaling
code. This change adds a context parameter to the Construct and
ConstructProvider functions, and plumbs the engine context through
to the relevant calls to these functions.
When a resource reference is deserialized, it may not have a version in which case `version` will be an empty string. This change fixes `TryGetResourceType` to work correctly when an empty version is passed.
* [sdk/go] Support maps in Invoke outputs and Read inputs
These are already supported by the implementation, but were prevented by overzealous input validation in Invoke and ReadResource.
Follow-up to #4522 and #4521.
* Add CHANGELOG
* PR feedback
Adds an opt-in `allowSecrets` flag to `serializeFunction` to allow it to capture secrets. If passed, `serializeFunction` will now report back whether it captured any secrets. This information can be used by callers to wrap the resulting text in a Secret value.
Fixes#2718.
These changes are a combination of three commits, each of which
contributes to the testing and/or fixing of a problem with marshaling
unknowns in `plugin.provider.Update` when `preview` is true.
## deploytest: add support for gRPC adapters.
These changes add support for communicating with providers using the
gRPC adapters to the deploytest pacakage. This makes it easier to test
the gRPC adapters across typical lifecycle patterns.
Supporting these changes are two additions to the `resource/plugin`
package:
1. A type that bridges between the `plugin.Provider` interface and the
`pulumirpc.ResourceProviderServer`
2. A function to create a `plugin.Provider` given a
`pulumirpc.ResourceProviderClient`
The deploytest package uses these to wrap an in-process
`plugin.Provider` in a gRPC interface and connect to it without using
the default plugin host, respectively.
## pulumi_test: test provider preview over gRPC.
Add a test that runs the provider preview lifecycle, but using a
provider that communicates over gRPC.
## gRPC bridge: fix unknowns in `Update` previews
Set the `KeepUnknowns` and `RejectUnknowns` bits in the `MarshalOptions`
used when unmarshaling update results to preserve unknowns during a
preview and reject them otherwise.
These changes also set the `RejectUnknowns` bit in the `MarshalOptions`
used by `Create` if `preview` is false, and fix a bug in the array
unmarshaler that could cause out-of-bounds accesses.
Fixes https://github.com/pulumi/pulumi/issues/6004.
* Do not read TGZs into memory.
This runs a serious risk of exhausting the memory on lower-end machines
(e.g. certain CI VMs), especially given the potential size of some
plugins.
* CHANGELOG
* fixes
- Improve the existing coverage to use real resources and mocks
- Add tests for deserialization as well as serialization
- Add tests that serialize custom resources during preview
Contributes to #5943.
- Reset the runtime prior to each test
- Use the SDK's `test` decorator instead of `async_test`
- Rename a couple classes to avoid warnings from pytest
These tests cover the same scenarios that are coverted in the engine's
unit tests, but exercise the Node SDK's marshalling paths.
These changes include a few enhancements to the Node SDK's test APIs
that make it easier to more precisely control its behavior, and extend
the `Mocks` interface to allow the registration of component resources
to work properly.
Contributes to #5943.
- Add component ref coverage to the existing test
- Add coverage for a downlevel SDK communicating with an engine that
supports resource refs
- Add coverage for a downlevel engine communicating with an SDK that
supports resource refs
As part of improving coverage, these changes add a knob to explicitly
disable resource refs in the engine without the use of the environment
variable. The environment variable is now only read by the CLI, and has
been restored to its prior polarity (i.e. `PULUMI_ENABLE_RESOURCE_REFERENCES`).
* Enable resource reference feature by default
Unless the PULUMI_DISABLE_RESOURCE_REFERENCES flag
is explicitly set to a truthy value, the resource reference feature is now
enabled by default.
* Set AcceptResources in the language SDKs
This can be disabled by setting the `PULUMI_DISABLE_RESOURCE_REFERENCES` environment variable to a truthy value.
Co-authored-by: Justin Van Patten <jvp@justinvp.com>
`log.error` will call the engine's `log` gRPC endpoint (if the engine is available; otherwise it will write to `console.error`) with `LogSeverity.ERROR`, which tell the engine to stop processing further resource operations.
Without this, any uncaught errors (such as input validation errors done inside `apply`) would be written to stderr, but wouldn't actually result in an update error.
This re-applies the fix in 5857 to make credentials.json writes concurrency safe.
The original fix used `path.Dir` instead of `filepath.Dir` - which led to not placing the temp file in the same folder (and drive) as the renamed file target. This led to errors on Windows environments where the working directory was on a different drive than the `~/.pulumi` directory. The change to use `filepath.Dir` instead ensures that even on Windows, the true directory containing the credentials file is used for the temp file as well.
Fixes#3877.
* Properly resize arrays when adding
The current logic attempts to update the array but, because
append may need to allocate a new array with adequate space,
the code can currently leave dest referring to the old,
under-sized array. The solution is to use the set(dest)
logic that already exists and is used for the IsNull case.
Added a test case that would fail before this fix and now passes.
This fixespulumi/pulumi#5871.
* Add CHANGELOG entry
Implement GetRequiredPlugins for Python, which determines the plugins
required by the program.
Also, if the `virtualenv` runtime option is set, and the specified
virtual directory is missing or empty, automatically create it and
install dependencies into it.
Running `pulumi` operations in parallel could occasionally result in truncating the `~/.pulumi/credentials.json` file and reading that truncated file from another process before the content could be written.
Instead, use `os.Rename` to atomically replace the file contents.
Concurrent `pulumi` operations could still compete for who gets to write the file first, and could lead to surprising results in some extreme cases. But we should not see the corrupted file contents any longer.
Fixes#3877.
There are two significant changes in this commit: one to the way
resource packages/modules are stored and retrieved, and one to resource
ref deserialization in the face of missing resource packages/modules.
Resource packages and modules no longer require an exact version match
during deserialization. Instead, the newest compatible version of the
package or module is selected. If no version was specified, the newest
version of the package or module will be chosen. As a special case, a
package or module that has no version will always be treated as the best
version for that package or module.
If a resource package or module is not found when attempting to
deserialize a resource reference, the SDK no longer emits an error, and
instead deserializes the reference as its URN or ID (if present). This
accommodates providers that have not yet been updated to include the
appropriate factory registrations.
- Differentiate between resource references that have no ID (i.e. because
the referenced resource is not a CustomResource) and resource references
that have IDs that are not known. This is necessary for proper
backwards-compatible serialization of resource references.
- Fix the key that stores a resource reference's package version in the
.NET, NodeJS, and Python SDKs.
- Ensure that the resource monitor's marshalling/unmarshalling of inputs
and outputs to/from calls to `Construct` retain resource references as
appropriate.
- Fix serialization behavior for resources -> resource references in the
Go SDK: if a resource's ID is unknown, it should still be serialized
as a resource reference, albeit a reference with an unknown ID.
The PULUMI_BACKEND_URL env var allows specifying the backend to use instead of deferring to the project or the ~/.pulumi/credentials.json file to decide on the "current" backend. This allows for using Pulumi without a dependence on this piece of global filesystem state, so that each `pulumi` invocation can control the exact backend it want's to operate on, without having to do stateful `pulumi login`/`pulumi logout` operations.
This is especially useful for automation scenarios like Automation API generally (and effectively solves https://github.com/pulumi/pulumi/issues/5591), or https://github.com/pulumi/pulumi-kubernetes-operator/issues/83 specifically.
This also makes things like efe7a599e6/dist/actions/entrypoint.sh (L10) less necessary, and possible to accomplish for any containerized `pulumi` execution without the need for this logic to be embedded in bash scripts wrapping the CLI.
Two improvements:
1. Don't display "[resource plugin <foo>] installing" if the plugin is already installed.
2. Close the plugin download progress bar before displaying any subsequent output, and only show output of `npm install` when there is an error.
Just what it says on the tin.
The SDK code generator will be updated to use the new `urn`
resource option inside of each module's implementation of
`ResourceModule.construct`.
Part of #2430.
Co-authored-by: Justin Van Patten <jvp@justinvp.com>
When installing a plugin, previous versions of Pulumi extracted the
plugin tarball to a temp directory and then renamed the temp directory
to the final plugin directory. This was done to prevent concurrent
installs: if a process fails to rename the temp dir because the final
dir already exists, it means another process already installed the
plugin. Unfortunately, on Windows the rename operation often fails due
to aggressive virus scanners opening files in the temp dir.
In order to provide reliable plugin installs on Windows, we now extract
the tarball directly into the final directory, and use file locks to
prevent concurrent installs from toppling over one another.
During install, a lock file is created in the plugin cache directory
with the same name as the plugin's final directory but suffixed with
`.lock`. The process that obtains the lock is responsible for extracting
the tarball. Before it does that, it cleans up any previous temp
directories of failed installs of previous versions of Pulumi. Then it
creates an empty `.partial` file next to the `.lock` file. The
`.partial` file indicates an installation is in-progress. The `.partial`
file is deleted when installation is complete, indicating the plugin was
successfully installed. If a failure occurs during installation, the
`.partial` file will remain indicating the plugin wasn't fully
installed. The next time the plugin is installed, the old installation
directory will be removed and replaced with a fresh install.
This is the same approach Go uses for installing modules in its
module cache.
Just what it says on the tin. This is implemented by changing the
`GetPackageConfig` method of `ConfigSource` to return a `PropertyMap`
and ensuring that any secret config is represented by a `Secret`.
This is necessary due to the way we've factored the libraries imported
by users into modules. The primary alternative is to ensure that each
child module imports the root module for a package and registers itself
with that package where necessary to prevent circular dependencies. This
simplifies the core SDKs slightly at the cost of greater complications
in the generated SDKs; the approach taken by these changes seems like a
more maintainable option.
Contributes to #2430.
Co-authored-by: Justin Van Patten <jvp@justinvp.com>
Resources are serialized as their URN, ID, and package version. Each
Pulumi package is expected to register itself with the SDK. The package
will be invoked to construct appropriate instances of rehydrated
resources. Packages are distinguished by their name and their version.
This is the foundation of cross-process resources.
Related to #2430.
Co-authored-by: Mikhail Shilkov <github@mikhail.io>
Co-authored-by: Luke Hoban <luke@pulumi.com>
Co-authored-by: Levi Blackstone <levi@pulumi.com>
These changes add support for provider-side previews of create and
update operations, which allows resource providers to supply output
property values for resources that are being created or updated during a
preview.
If a plugin supports provider-side preview, its create/update methods
will be invoked during previews with the `preview` property set to true.
It is the responsibility of the provider to fill in any output
properties that are known before returning. It is a best practice for
providers to only fill in property values that are guaranteed to be
identical if the preview were instead an update (i.e. only those output
properties whose values can be conclusively determined without
actually performing the create/update operation should be populated).
Providers that support previews must accept unknown values in their
create and update methods.
If a plugin does not support provider-side preview, the inputs to a
create or update operation will be propagated to the outputs as they are
today.
Fixes#4992.
The logic for validating prompted values in 'new' wasn't quite right,
leading to the possibility of creating Pulumi.yaml files with blank
project names.
This manifests in various ways and I've hit it a number of times
over the past few months because of the way we handle project/stack
name conflicts in 'new' -- which itself is a bit annoying too:
https://github.com/pulumi/pulumi/blob/master/pkg/cmd/pulumi/new.go#L206-L207
Because we substitue a default value of "", and because the prompting
logic assumed default values are always valid, we would skip validation
and therefore accept a blank Pulumi.yaml file.
This generates an invalid project which causes errors elsewhere, such as
error: failed to load Pulumi project located at ".../Pulumi.yaml":
project is missing a 'name' attribute
I hit this all the time with our getting started guide because I've
gone through it so many times and have leftover stacks from prior
run-throughs. I wouldn't be surprised if a lot of people hit this.
The solution here validates all values, including the default.
Note also that we failed to validate the value used by 'new --yes'
which meant you could bypass all validation by passing --yes, leading
to similar outcomes.
I've added a couple new tests for these cases. There is a risk we
depend on illegal default values somewhere which will now be rejected,
but that would seem strange, and assuming the tests pass, I would
assume that's not true. Let me know if that's wrong.
Fixespulumi/pulumi#3255.
A recent change to output deserialization resulted in secrets being returned unwrapped. This change addresses the regression, ensuring any unwrapped secret values are rewrapped before being returned.
We recently made a change to the Python codegen to emit `int` type annotations, instead of `float`, for properties that are typed as `schema.IntType`.
But the number values that come back from protobuf structs are always floats (like JSON), so we need to cast the values intended to be integers to `int`.
* Revise host mode.
The current implementation of host mode uses a `pulumi host` command and
an ad-hoc communication protocol between the engine and client to
connect a language host after the host has begun listening. The most
significant disadvantages of this approach are the communication
protocol (which currently requires the use of stdout), the host-specific
command, and the difficulty of accommodating the typical program-bound
lifetime for an update.
These changes reimplement host mode by adding engine support for
connecting to an existing language runtime service rather than launching
a plugin. This capability is provided via an engine-specific language
runtime, `client`, which accepts the address of the existing languge
runtime service as a runtime option. The CLI exposes this runtime via
the `--client` flag to the `up` and `preview` commands, which similarly
accepts the address of an existing language runtime service as an
argument. These changes also adjust the automation API to consume the
new host mode implementation.
When installing a plugin, if it contains a `PulumiPlugin.yaml` file with a `runtime` value of `nodejs` or `python`, install dependencies for the plugin.
For Node.js, `npm install` is run (or `yarn install` if `PULUMI_PREFER_YARN` is set).
For Python, a virtual environment is created and deps installed into it.