Because of our Proxy types, every output will return something when
you call `.isSecret` on it. However, if you call it on an output from
a version of `@pulumi/pulumi` which did not support secrets, the thing
you will get back is not undefined but rather an `Output` which wraps
undefined.
Because of this, care must be taken when reading this property and so
a small helper is introduced and used in places we care about.
All existing implementations would fail if secret values were passed
to the dyanmic provider. When the provider says it does not support
secrets, the engine will do basic secrets tracking (any outputs with
the same names as secret inputs become secrets themselves).
Since we don't support nesting secrets (as they are modeled as
Outputs), as we deserialize, we push the secretness up to top level,
where we will correctly use it to mark the output as secret.
This fixes an issue where if you created a StackReference resource,
with a mix of secret and non secret properties, you would see the
"wire form" of the secrets as values on the `outputs` map of the
StackReference resource.
In our system, we model secrets as outputs with an additional bit of
metadata that says they are secret. For Read and Register resource
calls, our RPC interface says if the client side of the interface can
handle secrets being returned (i.e. the language SDK knows how to
sniff for the special signiture and resolve the output with the
special bit set).
For Invoke, we have no such model. Instead, we return a `Promise<T>`
where T's shape has just regular property fields. There's no place
for us to tack the secretness onto, since there are no Outputs.
So, for now, don't even return secret values back across the invoke
channel. We can still take them as arguments (which is good) but we
can't even return secrets as part of invoke calls. This is not ideal,
but given the way we model these sources, there's no way around
this. Fortunately, the result of these invoke calls are not stored in
the checkpoint and since the type is not Output<T> it will be clear
that the underlying value is just present in plaintext. A user that
wants to pass the result of an invoke into a resource can turn an
existing property into a secret via `pulumi.secret`.
For a given {Read,Register}Resource call, there may be a set of
outputs that should be treated as secrets, even if the provider itself
does not think they are always sensitive. For example, when
constructing a `@pulumi/random::RandomString` it's possible that you
will be using the string as a shared secret between two
resources (e.g. the resigstration of a webhook and its handler) and so
you want the value stored in the checkpoint in a secure manner.
This change augments the RPCs such that we can communicate this from
the language host into the engine.
When serializing values, if the other end of the resource monitor
interface does not support secrets (e.g. it is an older CLI), don't
pass secrets to it.
`Output<T>` now tracks if an output represents secret data or
not. When secret, it is marshalled as a secret value and we signal to
the resource monitor that it is safe to return secret values to us.
The `pulumi` module exports a new functiion, `secret<T>` which works
in the same was a `output<T>` except that it marks the underlying
output as a secret.
This secret bit flows as you would expect across `all`'s and
`apply`'s.
Note that in process memory, the raw value is still present, when you
run an `apply` for a secret output, you are able to see the raw
value. In addition, if you capture a secret output with a lambda, the
raw value will be present in the captured source text.
- When configuring a provider, the engine can now communicate to the
provider if it supports marhsalling secrets as rich values, if so,
the provider should return any secret values as typed secret
objects.
- When configuring a provider, the provider can now communicate if it
supports accepting secrets as rich values. When true, the engine
should marshall secrets as strongly typed values when passing them
to the provider
- The resource monitor is agumented such that a client can ask if it
understands a given feature. We will use this to test support for
secrets, so the language SDKs can understand how they should
marshall secrets when calling resource monitor RPCs
- Register and Read resource gain additional flags to let the resource
monitor know if the client can understand secret values being passed
back as a the result of a call.
We changed the `pulumi update` command to be `pulumi up` a while back
(`update` is an alias of `up`). This change just makes it so we refer to
the actual command, `pulumi up`, instead of the older `pulumi update`.
In previous commits, we have changed the language plugin protocol to
allow the host to communicate that the plugin is meant to boot in "query
mode." In nodejs, this involves not doing things like registering the
default stack resource. This commit will implement this functionality.
`pulumi query` requires that language plugins know about "query mode" so
that they don't do things like try to register the default stack
resource.
To communicate that a language host should boot into query mode, we
augment the language plugin protocol to include this information.
* NodeJS: allow callers to override provider version
* Python: allow callers to override provider version
* NodeJS: add version for invoke
* Python: add version to invoke
* NodeJS: add tests for ReadResource
* Post-merge cleanup
* update doc comments
Fixes#2277.
Adds a new ignoreChanges resource option that allows specifying a list of property names whose values will be ignored during updates. The property values will be used for Create, but will be ignored for purposes of updates, and as a result also cannot trigger replacements.
This is a feature of the Pulumi engine, not of the resource providers, so no new logic is needed in providers to support this feature. Instead, the engine simply replaces the values of input properties in the goal state with old inputs for properties marked as ignoreChanges.
Currently, only top level properties may be specified in ignoreChanges. In the future, this could be extended to support paths to nested properties (including into array elements) with a JSONPath/JMESPath syntax.
* Enable unit testing for Pulumi programs
This change enables rudimentary unit testing of your Pulumi programs, by introducing a `PULUMI_TEST_MODE` envvar that, when set, allows programs to run without a CLI. That includes
* Just being able to import your Pulumi modules, and test ordinary functions -- which otherwise would have often accidentally triggered the "Not Running in a CLI" error message
* Being able to verify a subset of resource properties and shapes, with the caveat that outputs are not included, due to the fact that this is a perpetual "dry run" without any engine operations occurring
In principle, this also means you can attach a debugger and step through your code.
* Finish the unit testing features
This change
1) Incorporates CR feedback, namely requiring that test mode be
explicitly enabled for any of this to work.
2) Implements Python support for the same capabilities.
3) Includes tests for both JavaScript and Python SDKs.
* Add a note on unit testing to the CHANGELOG
* Use Node 8 friendly assert API
* Embellish the CHANGELOG entry a bit
In pursuit of pulumi/pulumi#2389, this commit adds the necessary changes
to the resource monitor protocol so that language hosts can communicate
exactly what version of a provider should be used when servicing an
Invoke, ReadResource, or RegisterResource. The expectation here is that,
if a language host provides a version, the engine MUST use EXACTLY that
version of a provider plugin in order to service the request.
This makes the Python SDK's Config constructor name argument
optional, similar to what we do in the Node.js SDK. If not supplied,
the current project name is used as the default.
When using a dynamic provider, the following messages are printed,
because we did not update the dynamic provider when we added these new
RPCs:
```
Method handler checkConfig for /pulumirpc.ResourceProvider/CheckConfig expected but not provided
Method handler diffConfig for /pulumirpc.ResourceProvider/DiffConfig expected but not provided
```
Given that we don't do anything for the `configure` RPC today, we can
also just no-op these RPCs as well.
These changes take advantage of the newly-added support for returning
inputs from Read to update a resource's inputs as part of a refresh.
As a consequence, the Pulumi engine will now properly detect drift
between the actual state of a resource and the desired state described
by the program and generate appropriate update or replace steps.
As part of these changes, a resource's old inputs are now passed to the
provider when performing a refresh. The provider can take advantage of
this to maintain the accuracy of any additional data or metadata in the
resource's inputs that may need to be updated during the refresh.
This is required for the complete implementation of
https://github.com/pulumi/pulumi-terraform/pull/349. Without access to
the old inputs for a resource, TF-based providers would lose all
information about default population during a refresh.
This update includes several changes to core `@pulumi/pulumi` constructs that will not play nicely
in side-by-side applications that pull in prior versions of this package. As such, we are rev'ing
the minor version of the package from 0.16 to 0.17. Recent version of `pulumi` will now detect,
and warn, if different versions of `@pulumi/pulumi` are loaded into the same application. If you
encounter this warning, it is recommended you move to versions of the `@pulumi/...` packages that
are compatible. i.e. keep everything on 0.16.x until you are ready to move everything to 0.17.x.
### Improvements
- `Output<T>` now 'lifts' property members from the value it wraps, simplifying common coding patterns. Note: this wrapping only happens for POJO values, not `Output<Resource>`s.
- Depending on a **Component** Resource will now depend on all other Resources parented by that
Resource. This will help out the programming model for Component Resources as your consumers can
just depend on a Component and have that automatically depend on all the child Resources created
by that Component. Note: this does not apply to a **Custom** resource. Depending on a
CustomResource will still only wait on that single resource being created, not any other Resources
that consider that CustomResource to be a parent.
These changes add two new methods to the provider interface and extend
the results of three others.
The new methods are `CheckConfig` and `DiffConfig`, which fill out the
set of methods required for a complete implementation of the
first-class provider design. Though these methods are optional for
backwards compatibility, they should be implemented by all future
providers for the best possible user experience.
The adjusted result types are `DiffResponse`, `ReadResponse`, and
`ErrorResourceInitFailed`. The first has been updated to include a list
of the properties that changed (if any). The latter two now include
an estimated set of inputs for the resource as well as the resource's
state. Together, these three changes enable the engine to determine the
set of inputs that should be specified by a user in order to match those
that describe the resource's current state.
This contributes to #2453, #1662, #1635, and #1718.
* Revert "Make toString and toJSON internal (#2489)"
This reverts commit 7579b84f73.
* Revert "Update error message to point at docs. (#2488)"
This reverts commit 9156c26a2e.
* Revert "Throw on Output.toString and toJSON (#2486)"
This reverts commit c33b4505c0.
* Fix an issue with empty ID for CustomResource
The Python runtime was checking the ID field it receives from the engine
against None, assuming that the engine would not set the ID field if one
was not present. However, it does set the ID field; it is set to the
empty string when an ID is not known.
This commit fixes an issue that can cause certain IDs to be erroneously
considered to be known during previews, which can cause problems during
the Check phase of resources that directly reference IDs of other
resources.
* Add CHANGELOG
We do all our work in a virtualenv and across repositories we now
consume dependencies via pypi (also installed in a virtualenv) so best
case install into the user site packages wastes time and maybe prints
some warnings and worse case it clobbers something they've installed
for real.
These changes add a new flag to the various `ResourceOptions` types that
indicates that a resource should be deleted before it is replaced, even
if the provider does not require this behavior. The usual
delete-before-replace cascade semantics apply.
Fixes#1620.
* Clean up documentation for Python SDK
The Python SDK currently does a couple of bad things that make it
difficult to generate documentation:
1. It "wildcard-imports" submodules without each module specifying an
__all__ member
2. Documentation strings don't have a consistent format
3. Documentation strings are in Markdown and not reStructuredText
To remedy this, this commit addresses 1 by explicitly specifying which
members are being exported from submodules, so that we can see in one
place exactly what the public surface area of the pulumi package is. For
2 and 3, this commit fixes a large number of documentation strings to
contain metadata tags that Sphinx is capable of reading. This allows us
to generate high-quality documentation directly from the source without
having to manually parse docstrings.
* Please pylint
* Work around commonjs protoc bug
When compiling with the commonjs target, the protoc compiler still emits
references to Closure Compiler-isms that whack global state onto the
global object. This is particularly bad for us since we expect to be
able to make backwards-compatible changes to our Protobuf definitions
without breaking things, and this bug makes it impossible to do so.
To remedy the bug, this commit hacks the output of protoc (again) with
sed in order to avoid ever touching the global object. Everything still
works fine because the commonjs target (correctly) exports the protobuf
message types via the module system - it's just not writing to global
anymore.
* Fix status.proto
* Don't hack status.proto
- Add support for per-property dependencies to the Go SDK
- Add tests for first-class secret rejection in the checkpoint and RPC
layers and language SDKs
This implements the new algorithm for deciding which resources must be
deleted due to a delete-before-replace operation.
We need to compute the set of resources that may be replaced by a
change to the resource under consideration. We do this by taking the
complete set of transitive dependents on the resource under
consideration and removing any resources that would not be replaced by
changes to their dependencies. We determine whether or not a resource
may be replaced by substituting unknowns for input properties that may
change due to deletion of the resources their value depends on and
calling the resource provider's Diff method.
This is perhaps clearer when described by example. Consider the
following dependency graph:
A
__|__
B C
| _|_
D E F
In this graph, all of B, C, D, E, and F transitively depend on A. It may
be the case, however, that changes to the specific properties of any of
those resources R that would occur if a resource on the path to A were
deleted and recreated may not cause R to be replaced. For example, the
edge from B to A may be a simple dependsOn edge such that a change to
B does not actually influence any of B's input properties. In that case,
neither B nor D would need to be deleted before A could be deleted.
In order to make the above algorithm a reality, the resource monitor
interface has been updated to include a map that associates an input
property key with the list of resources that input property depends on.
Older clients of the resource monitor will leave this map empty, in
which case all input properties will be treated as depending on all
dependencies of the resource. This is probably overly conservative, but
it is less conservative than what we currently implement, and is
certainly correct.
On startup, when we were populating the Settings object, we failed to
coerce the dry_run parameter from a string to a boolean, which resulted
in is_dry_run always believing that it was a preview. This PR fixes this
oversight by explicitly coercing to a boolean prior to sending the value
to Settings.
When is resource is waiting for its dependencies to resolve, it first
informs the RPC_MANAGER that it intends to do an RPC - this is to
prevent premature termination of the program while RPCs are still in
flight or queued to execute.
However, this is a problem whenever a resource fails to create for
whatever reason. The most common ways for this to happen are for invokes
to fail, resource creation itself to fail, or throwing in an apply.
Today, this causes a deadlock, since all consumers of the failed
resources block forever while never decrementing the RPC count.
This commit addresses the issue by deliberately (abnormally) resolving
all futures that are created in the process of preparing a resource.
This solves the problem by immediately terminating all resources that
are waiting for the failed resource's outputs to resolve - they resolve
immediately, and exceptionally.
The end result is now that, instead of deadlocking, a doomed program now
terminates as expected with a single exception message.
When previewing a real first-class provider, it is often the case that
the provider's ID is unknown during a preview. This commit fixes a bug
where we did not translate an unknown ID into the rpc layer's sentinel
UNKNOWN value where we should have, which caused the engine to fail to
resolve the provider reference.
For some reason, writing to stderr using sys.stderr.write doesn't work,
but printing to stderr using the print function does. I don't know why
this is, but I do know that this makes the printed messages show up as
messages on the Pulumi CLI.
Invoke in Node.js allows users to optionally pass a parent or a provider
to the invoke, which dictates either explicitly or implicitly which
provider to use when performing an invoke. If a provider is specified
explicitly, that provider is used to perform the invoke. If a parent is
specified, that parent's provider is used to perform the invoke.
It is possible for the sub-process responsible for running a NodeJS
Pulumi program to exit with a success code before the user's program has
run if the process of loading the runtime generates an unhandled promise
rejection. These changes fix this by registering the unhandled exception
and rejection handlers that are responsible for ensuring a non-zero exit
code in these cases before any other action is taken.
Note that this issue is really only possible because the Node language
host (like the Python language host) is composed of two processes: one
that serves the language host gRPC service and one that loads and runs
the user's program. The former launches the latter in response to a call
to its `Run` gRPC endpoint. The lifetime of the user's program is
considered to be bounded by the lifetime of the `Run` invocation. The
NodeJS process maintains its own connection to the engine over which
resource registrations are communicated. It is tempting to add a message
to the resource monitor RPC interface that signals that no further
registrations are performed, but this is complicated due to the
three-party topology and the possibility that such an RPC may never be
sent (e.g. due to a crash or a downlevel version of the Pulumi Node
runtime).
Fixes#2316.
* Implement first-class providers for Python
First-class providers are an explicit projection of providers themselves
into Pulumi programs. For the most post, providers are just regular
resources, but the addition of providers to the fray (and the ability of
resources to be constructed by providers in the same program) requires
some changes to the Python resource model.
A summary of the changes:
1. Added ProviderResource, a custom resource that is the base class of
all providers.
2. ResourceOptions now has 'provider' and 'providers' fields.
'provider', when passed to a custom resource, allows users to override
the provider that is used to construct a resource to an instance of a
ProviderResource. 'providers', when passed to a component resource,
allows users to override providers used to construct children of the
component resource.
3. 'protect', 'providers', and 'provider' are all now inherited from
a resource's parent if they aren't specified in the child.
This commit adds the requisite code for the above changes and, in
addition, adds a number of new tests that exercise them and related code
paths.
* Rebase against master
This is something of a quick hack to work around the limitations that
are at the root of #2310. In short, `StackReference` resources do not
change during a update because their inputs have not changed and we do
not refresh resources as part of the update by default. We want
`StackReference` to remain a resource for myriad reasons (not the least
of which is to avoid a breaking change), but it does seem correct for it
to refresh its state during each update. Because there is no actual CRUD
operation associated with a `StackReferece`, we can obtain this behavior
by changing the implementation of its ctor in the various SDKs s.t. its
options bag always contains an appropriate `id`, thus indicating a
`Read`.
Fixes#2310.
* Add 'Output.all' combinator for Python
Output.all is a useful combinator that we already have in Node that
allows the composition of a list of outputs into an output of a list.
This is very useful when authoring components and its lack of presence
in Python was an oversight.
This commit adds 'Output.all' and 'Output.from_input', adding tests and
documentation for each.
* start unwrap
* Add functionality and test for nested inputs
Previously, we assumed that the dynamic provider was located in
`./node_modules/@pulumi/pulumi/../` which is correct in the majority
of cases. However, tools like lerna or yarn workspaces (or custom
workflows) allow the node_modules folder to be located elsewhere on
disk, and node will still find it because of its algorithm for module
resolution.
So, do what we do in the language host itself, first launch node and
ask it to tell us where it resolves a require statement to on disk and
then launch node against that script.
Fixes#2261
If a custom resource has explicitly specified a provider, add that
provider to the resource's provider map under the resource's package.
This allows children of the custom resource to inherit the resource's
provider.
Fixes#2262.
The langhost shares its standard out and standard error with the
language executor that it is used (python/nodejs), so we must be sure to
flush our stdout and stderr before reporting a Run failure to the
engine.
'python' is not usually symlinked to 'python3' on most distros unless
you are already running in a virtual environment. Launching 'python3'
explicitly ensures that we will either launch the program successfully
or immediately fail, instead of launching the program with Python 2 and
failing with syntax errors at runtime.
This commit also emits an error message asking users to install Python
3.6 or later if we failed to find the 'python3' executable.
This changes the input type for dependsOn from simply
`Resource[] | Resource` to `Input<Input<Resource>[]> | Input<Resource>`.
This permits `Output<Resource>`s, etc in addition to
`Promise<Resource>`s. The logic for dynamically unpicking the right
types and recursing through the data structures isn't straightforward,
but I've written a test for all of the interesting permutations.
This fixespulumi/pulumi#991.
These changes add a new resource to the Pulumi SDK,
`pulumi.StackReference`, that represents a reference to another stack.
This resource has an output property, `outputs`, that contains the
complete set of outputs for the referenced stack. The Pulumi account
performing the deployment that creates a `StackReference` must have
access to the referenced stack or the call will fail.
This resource is implemented by a builtin provider managed by the engine.
This provider will be used for any custom resources and invokes inside
the `pulumi:pulumi` module. Currently this provider supports only the
`pulumi:pulumi:StackReference` resource.
Fixes#109.
* Fix, formalize and add tests for property rewrites
The Python SDK provides two hooks for resources to override how their
properties are communicated to and from the engine. The code that
performs this transformation is subtle and, before this commit, subtly
incorrect.
This commit adds a test that verifies that the SDK correctly transforms
properties recursively according to the two transformation hooks, while
also fixing a smattering of test issues encountered when adding the new
test.
* CR feedback
We run the same suite of changes that we did on gometalinter. This
ended up catching a few new issues, some of which were addressed and
some of which were baselined.
- Remove the forked copy of the toolset
- Stop installing `pipenv` in sdk/python/Makefile
After this, we'll require that you already have `pipenv` present
before building.
* Implement RegisterResourceOutputs for Python 3
RegisterResourceOutputs allows Python 3 programs to export stack outputs
and export outputs off of component resources (which, under the hood,
are the same thing).
Adds a new integration test for stack outputs for Python programs, as
well as add a langhost test for register resource outputs.
Fixespulumi/pulumi#2163
* CR: Rename stack_output -> export
Fix integration tests that hardcoded paths to stack_outputs
* Fix one more reference to stack_outputs
future_input tests that it's possible to use coroutines as inputs to
Pulumi resources. resource_thens tests that it's possible to use outputs
to chain resource inputs and outputs together and that the SDK reports
correct dependencies to the engine.
This PR also fixes two bugs exposed by the new tests: first, coroutines
needed to be scheduled before awaiting (otherwise we'd deadlock) and
Nones in maps needed to be ignored when serializing and deserializing.
1. Add support for first-class providers
2. Make `pulumi.ResourceState` conform to the `pulumi.Resource` interface
3. Wait for inputs to resolve inside RPC goroutines rather than doing so
before starting the goroutines
Note that (2) involves a breaking change to `pulumi.ResourceState` that
will require adjusting `tfgen`'s code generation.
Fixes https://github.com/pulumi/pulumi-terraform/issues/256
Contributes to #1713
* Make v8 primitives async as there is no way to avoid async in node11.
* Simplify API.
* Move processing of well-known globals into the v8 layer.
We'll need this so that we can map from RemoteObjectIds back to these well known values.
* Remove unnecesssary check.
* Cleanup comments and extract helper.
* Introduce helper bridge method for the simple case of making an entry for a string.
* Make functions async. They'll need to be async once we move to the Inspector api.
* Make functions async. They'll need to be async once we move to the Inspector api.
* Make functions async. They'll need to be async once we move to the Inspector api.
* Move property access behind helpers so they can move to the Inspector API in the future.
* Only call function when we know we have a Function. Remove redundant null check.
* Properly serialize certain special JavaScript number values that JSON serialization cannot handle.
* Only marshall across the 'source' and 'flags' for a RegExp when serializing.
* Add a simple test to validate a regex without flags.
* Extract functionality into helper method.
* Add test with complex output scenarios.
* Output serialization needs to avoid recursively trying to serialize a serialized value.
* Introduce indirection for introspecting properties of an object.
* Use our own introspection API for examining an Array.
* Hide direct property access through API indirection.
* Produce values like the v8 Inspector does.
* Compute the module map asynchronously. Will need that when mapping mirrors instead.
* Cleanup a little code in closure creation.
* Get serialization working on Node11 (except function locations).
* Run tests in the same order on <v11 and >=v11
* Make tests run on multiple versions of node.
* Rename file to make PR simpler to review.
* Cleanup.
* Be more careful with global state.
* Remove commented line.
* Only allow getting a session when on Node11 or above.
* Promisify methods.
* Several gardening tasks for Python
1. Update pipenv to 2018.7.1, which is the most recent release that
isn't broken on Python 2
2. Update our pylint dependency to 1.9, the most recently released
version
3. Re-enable pylint for the Pulumi package
* Back out of pipenv upgrade
It's apparently broken in our CI. Also upgrade pylint to 2.1, which is
apparently the "actual" most recently release according to PyPI.
* Fix a bad merge
* Provide a Py hook for providers to rename props
This commit adds input and output hooks that can be overridden by
providers if they would like to change the names of dictionary fields
when projecting resources into Python.
* Add syntax sugar for dict outputs
Properly recurse when rewriting input dictionaries
* Implement RPC for Python 3
* Try not setting PYTHONPATH
* Remove PYTHONPATH line
* Implement Invoke for Python 3
* Implement register resource
* progress
* Rewrite the whole thing
* Fix a few bugs
* All tests pass
* Fix an abnormal shutdown bug
* CR feedback
* Provide a hook for resources to rename properties
As dictionaries and other classes come from the engine, the
translate_property hook can be used to intercept them and rename
properties if desired.
* Fix variable names and comments
* Disable Python integration tests for now
Rather than placing these combinators directly on the Output class,
which feels odd because they are special purpose to iterables, and deal
with not only Outputs but also Inputs, we will place them on a
separate and dedicated iterable module for these utility helpers.
This change adds some new constructors for output properties:
1) We alias `Output.create` to `output`, more like Promise's various
construction methods. This reads better and is more discoverable.
2) A new `Output.createMap` function will accept an array of inputs,
along with a selector function for key/value pairs, and produces
an output map with said keys and values inside of it.
3) A new `Output.createGroupByMap` functon will similarly accept an
array of inputs and a key/value selector, however it creates an
output map with said keys, but where values are arrays of values,
and all duplicate keys will lead to appending to said arrays.
Tests to come in a subsequent checkin.
This commit introduces a 'next' package which we can use as a staging
ground for incrementally adopting new Python 3 code. The next package is
initially populated with the non-runtime portions of the Python SDK,
which is enough to pass all tests when running on Python 3. Future
commits will reach further into the runtime.
* Fail closure serialization in Node 11
Node 11 changed many of the intrinsics that we depend upon for closure
serialization, so until we fix the underlying issues this commit lazily
fails if a closure is serialized when running on Node 11.
* CR feedback
Some providers (namely Kubernetes) require unbounded parallelism in
order to function correctly. This commit enables the engine to operate
in a mode with unbounded parallelism and switches to that mode by
default.
Suppose you have `pulumi.output(o).apply(foo)`, with `o` being type `O`
and `foo` taking type `O` as an argument. If `O` is a type with methods,
this will fail to type check.
The reason is that `UnwrappedObject<T>` (as well as the other
`Unwrapped*` types) will recursively wrap the types of field values
whose type was `Function`. Since `UnwrappedObject<Function>` is not the
same as `Function`, we fail to type check. Note that this does not
result in an actual "boxed" object -- this is purely at the type level.
This commit resolves this by considering `Function` a primitive type,
which will cause us to not wrap the types of field values, instead
leaving them as `Function`.
With this commit, the functions in 'pulumi.log' can be used to send
diagnostic messages to the Pulumi CLI. The Pulumi SDK bootstrap script
now also uses this feature to send diagnostic information on unhandled
exceptions to the Pulumi CLI.
Instead of looping forever, due to some recent improvements in engine
error handling it's sufficient for a language host to exit cleanly with
a zero exit code when the resource monitor is shutting down.
If you forget to implement check on a dynamic provider, all your
inputs mysteriously disappear. It's doubly odd because many providers
don't need to perform any checking on transformation of their inputs.
This change simply propagates the new inputs as-is by default when
a user-supplied check method isn't provided. This would have saved
me 20 minutes just now ... :-)
This introduces a Dockerfile for the Pulumi CLI. This makes it
easier to develop and test the engine in a self-contained environment,
in addition to being suitable for running the actual CLI itself.
For instance,
$ docker run pulumi/pulumi -e "PULUMI_ACCESS_TOKEN=x" up
will run the Pulumi program mounted under the /app volume. This will
be used in some upcoming CI/CD scenarios.
This uses multi-stage builds, and Debian Stretch as the base, for
relatively fast and lean build times and resulting images. We are
intentional about restoring dep packages independent of the actual
source code so that we don't end up needlessly re-depping, which can
consume quite a bit of time. After fixing
https://github.com/pulumi/pulumi/issues/1986, we should explore an
Alpine base image option.
I made the decision to keep this image scoped to just the Go builds.
Therefore, none of the actual SDK packages themselves are built, just
the engine, CLI, and language plugins for Node.js, Python, and Go.
It's possible to create a mega-container that has all of these full
environments so that we can rebuild them too, but for now I figured
it was better to rely on package management for them.
Another alternative would have been to install released binaries,
rather than building them. To keep the useful flow for development,
however, I decided to go the build route for now. If we build at the
same hashes, the resulting binaries "should" be ~identical anyhow.
I've created a pulumi/pulumi Docker Hub repo that we can publish this
into. For now, there is no CI publishing of the image.
This fixespulumi/pulumi#1991.
* Revert RunError behavior. Introduce new ResourceError for errors associated with a resource.
* Fix docs.
* Use resource error.
* Use ResourceError in more places.
* Use ResourceError in a few more places.
* Throw a resource error.
* Make required.
* Revert this.
* Lint.
* Only report errors once.
* Better comment.
* Search for Go project executables in more places than just $PATH
This searches the following in preferred order:
1. Local directory
2. $GOPATH/bin
3. In $PATH
* Check if program is not a directory before executing
* Protobuf changes
* Move management of root resource state to engine
This commit fixes a persistent side-by-side issue in the NodeJS SDK by
moving the management of root resource state to the engine. Doing so
adds two new endpoints to the Engine gRPC service: 1) GetRootResource
and 2) SetRootResource, which get and set the root resource
respectively.
* Rebase against master, regenerate proto
* Use nightly protoc gRPC plugin for Node
Newer versions of the Node gRPC plugin accept the 'minimum_node_version'
flag, which we can use to instruct protoc to not support Node versions
earlier than Node 6. This allows the compiler to use 'Buffer.from'
instead of the deprecated 'Buffer' constructor, which fixes a
deprecation warning on Node 10.
* Protobuf changes
- Do not require replacement of dynamic resources due to provider
changes. This is not necessary, and is almost certainly the wrong
thing to do if the dynamic provider is managing a physical resource.
- Return all inputs by default from a dynamic provider's check method.
Currently a dynamic provider that does not implement check will end up
receiving no inputs. This is confusing, and is not the correct default.
* Combine two gRPC servers into one for testing
For some reason, our current gRPC test setup has become flaky now that
we are spinning up two gRPC servers. Hopefully merging them into one
helps clarify what's going on.
* Add back error logging for CI
* Validate type tokens before using them
When registering or reading a resource, we take the type token given to
us from the language host and assume that it's valid, which resulted in
assertion failures in various places in the engine. This commit
validates the format of type tokens given to us from the language host
and issues an appropriate error if it's not valid.
Along the way, this commit also improves the way that fatal exceptions
are rendered in the Node language host.
* Pre-allocate an exception for ReadResource
* Fix integration test
* CR Feedback
This commit is a lower-impact change that fixes the bugs associated with
invalid types on component resources and only checks that a type is
valid on custom resources.
* CR Take 2: Fix up IsProviderType instead of fixing call sites
* Please gometalinter
Instead of trying to probe for the normal path ourselves, just use
node's `require.resolve` statement to find `@pulumi/pulumi/cmd/run`.
This allows run to be found in cases where either yarn workspaces are
used, or the module has been installed globally.
Part of #1868
`opts.providers` is currently only read by the `Resource` constructor if
either `opts.parent` or `getRootResource` is not `undefined`. In
scnearios where exactly one copy of `@pulumi/pulumi` is loaded, one of
these conditions will always be true. In SxS scenarios, however, it is
possible for neither of these conditions to be true, and the created
resource will end up without a `providers` map. These changes fix that
by always copying the contents of `opts.providers` if it is defined.
Node calls 'exit' event callbacks when a process is preparing to exit,
via process.exit or otherwise, but it does not execute the next callback
in the chain if a callback calls process.exit.
* Use Promise.resolve.
* Use `Inputs | Promise<Inputs> | Output<Inputs>` rather than
`Input<Inputs>`, which looks supremely bizarre.
* Update ComponentResource.registerOutputs also.
This change partly addresses pulumi/pulumi#1611, by permitting you
to export a promise at the top-level, and have it be recognized as
a stack output. In other words, you can now say things like
async function main() {
...
return {
a: "x",
...,
z: 42,
};
}
module.exports = main();
and your Pulumi program will record distinct outputs as you'd hope:
---outputs:---
a: "x"
...
z: 42
This is arguably just a bug in the way we implemented stack outputs.
The remainder of the requests in #1611 will remain open for future
design and discussion, as they have more subtle ramifications.
If a `tsconfig.json` file is not present at the root of the Pulumi
project, ts-node will look up the directory tree to see if there is
one. If there is, it will treat that as the root of the project. While
reasonable for some cases, this isn't the behavior we want for our use
of ts-node. We actually set compiler options such that in the common
case you don't even need a `tsconfig.json` and for pure JavaScript
projects, there wouldn't be a `tsconfig.json` file.
In both of these cases, there's a big foot-gun waiting. For example in
pulumi/pulumi#1772 we ran into a case where there was a tsconfig.json
file in $HOME, causing the entirety of $HOME to be analyzed by
TypeScript which made it look like Pulumi hung.
To address this, tell ts-node to not use a project in cases where
there is not a `tsconfig.json` at the root of the project.
Fixes#1772
This commit will introduce a field, `IsStatus` to `LogRequest`. A
"status" logging event will be displayed in the `Info` column of the
main display, but will not be printed out at the end, when resource
operations complete.
For example, for complex resource initialization, we'd like to display a
series of intermediate results: `[1/4] Service object created`, for
example. We'd like these to appear in the `Info` column, but not at the
end, where they are not helpful to the user.
This change adopts the code review suggestion to use a bag of options
for config constraints rather than having overloaded function names.
This is a much cleaner approach, lets us use more descriptive names,
and is far more future proof in case we decide to add more capabilities.
Everytime I convert a CloudFormation template to Pulumi, I inevitably
run into the fact that CloudFormation has advanced "schema" capabilities
for input variables, like min/max for numbers and string lengths, enums,
and regex pattern matching. This is always cumbersome to convert.
In this change, I've added a number of config helpers for these cases:
For string enums:
getEnum(key: string, values: string[]): string | undefined;
requireEnum(key: string: values: string[]): string;
For min/max strlen:
getMinMax(key: string, min: number, max: number): string | undefined;
requireMinMax(key: string, min: number, max: number): string;
For regex patterns:
getPattern(key: string, regexp: string | RegExp): string | undefined;
requirePattern(key: string, regexp: string | RegExp): string;
For min/max strlen _and_ regex patterns:
getMinMaxPattern(key: string, min: number, max: number,
regexp: string | RegExp): string | undefined;
requireMinMaxPattern(key: string, min: number, max: number,
regexp: string | RegExp): string;
For min/max numbers:
getNumberMinMax(key: string, min: number, max: number): number | undefined;
requireNumberMinMax(key: string, min: number, max: number): number;
Each function throws a detailed RunError-derived exception type if the
configuration value doesn't meet the constraint.
This fixespulumi/pulumi#1671.
* Fix an issue with NodeJS host logging
Related to pulumi/pulumi#1694. This issue prevented the language host
from being aware that an engine (logging endpoint) was available and
thus no log messages were sent to the engine. By default, the language
host wrote them to standard out instead, which resulted in a pretty bad
error experience.
This commit fixes the PR and adds machinery to the NodeJS langhost tests
for testing the engine RPC endpoint. It is now possible to give a "log"
function to tests which will be hooked up to the "log" RPC endpoint
normally provided by the Pulumi engine.
* Remove accidental console.log
Replace the Source-based implementation of refresh with a phase that
runs as the first part of plan execution and rewrites the snapshot in-memory.
In order to fit neatly within the existing framework for resource operations,
these changes introduce a new kind of step, RefreshStep, to represent
refreshes. RefreshSteps operate similar to ReadSteps but do not imply that
the resource being read is not managed by Pulumi.
In addition to the refresh reimplementation, these changes incorporate those
from #1394 to run refresh in the integration test framework.
Fixes#1598.
Fixespulumi/pulumi-terraform#165.
Contributes to #1449.
The plugin host can ask the language host to provide a list of
resource plugins that it thinks will be nessecary for use at
deployment time, so they can be eagerly loaded.
In NodeJS (the only language host that implements this RPC) This works
by walking the directory tree rooted at the CWD of the project,
looking for package.json files, parsing them and seeing it they have
some marker property set. If they do, we add information about them
which we return at the end of our walk.
If there is *any* error, the entire operation fails. We've seen a
bunch of cases where this happens:
- Broken symlinks written by some editors as part of autosave.
- Access denied errors when part of the tree is unwalkable (Eric ran
into this on Windows when he had a Pulumi program at the root of his
file system.
- Recusive symlinks leading to errors when trying to walk down the
infinite chain. (See #1634 for one such example).
The very frustrating thing about this is that when you hit an error
its not clear what is going on and fixing it can be non-trivial. Even
worse, in the normal case, all of these plugins are already installed
and could be loaded by the host (in the common case, plugins are
installed as a post install step when you run `npm install`) so if we
simply didn't do this check at all, things would work great.
This change does two things:
1. It does not stop at the first error we hit when discovering
plugins, instead we just record the error and continue.
2. Does not fail the overall operation if there was an error. Instead,
we return to the host what we have, which may be an incomplete view
of the world. We glog the errors we did discover for diagnostics if
we ever need them.
I believe that long term most of this code gets deleted anyway. I
expect we will move to a model long term where the engine faults in
the plugin (downloading it if needed) when a request for the plugin
arrives. But for now, we shouldn't block normal operations just
because we couldn't answer a question with full fidelity.
Fixes#1478
If a resource's options bag does not specify `protect` or `provider`,
pull a default value from the resource's parent.
In order to allow a parent resource to specify providers for multiple
resource types, component resources now accept an optional map from
package name to provider instance. When a custom resource needs a
default provider from its parent, it checks its parent provider bag for
an entry under its package. If a component resource does not have a
provider bag, its pulls a default from its parent.
These changes also add a `parent` field to `InvokeOptions` s.t. calls to
invoke can use the same behavior as resource creation w.r.t. providers.
Fixes#1735, #1736.
* Added dist target for make, will help with Homebrew
* Try to install go dependencies before building
* Make sure dep ensure is called before trying to build SDKs
* Removed dep ensure from dist initial step
### 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`.
When this argument is not provided, we'll default to the value of
pulumi.getProject(). This is what you want for application level code
anyway and it matches the CLI behavior where if you don't qualify a
key with a package we use the name of the current project.
Fixes#1581
The pulumi runtime used to lazily load and parse both config and
settings data set by the language host. The initial reason for this
design was that we wanted the runtime to be usable in a normal node
environment, but we have moved away from supporting that.
In addition, while we claimed we loaded these value "lazily", we
actually forced their loading quite eagerly when we started
up. However, when capturing config (or settings, as we now do), we
would capture all the logic about loading these values from the
environment.
Even worse, in the case where you had two copies of @pulumi/pulumi
loaded, it would be possible to capture a config object which was not
initialized and then at runtime the initialization logic would try to
read PULUMI_CONFIG from the process environment and fail.
So we adopt a new model where configuration and settings are parsed as
we load their containing modules. In addition, to support SxS
scinerios, we continue to use `process.env` as a way to control both
configuration and settings. This means that `run.ts` must now ensure
that these values are present in the environment before either the
config or runtime modules have been loaded.
Set the following compiler defaults:
```
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
```
Which allows us to not even include a tsconfig.json file. If one is
present, `ts-node` will use its options, but the above settings will
override any settings in a local tsconfig.json file. This means if you
want full control over the target, you'll need to go back to the raw
tsc workflow where you explicitly build ahead of time.
This change lets us set runtime specific options in Pulumi.yaml, which
will flow as arguments to the language hosts. We then teach the nodejs
host that when the `typescript` is set to `true` that it should load
ts-node before calling into user code. This allows using typescript
natively without an explicit compile step outside of Pulumi.
This works even when a tsconfig.json file is not present in the
application and should provide a nicer inner loop for folks writing
typescript (I'm pretty sure everyone has run into the "but I fixed
that bug! Why isn't it getting picked up? Oh, I forgot to run tsc"
problem.
Fixes#958
I tried to re-generate the Protobuf/gRPC files, but generate.sh seems to
have assumed I manually built the Dockerfile ahead-of-time (unless I'm
missing something -- very possible). Unfortunately, when I went to do
that, I ended up with a handful of errors, most of them due to
differences in versions. (We probably want to think about pinning them.)
To remedy both issues, I've fixed up the Dockerfile so that it works for
me at least, and added a build step to the front of generate.sh.
* Protobuf changes to record dependencies for read resources
* Add a number of tests for read resources, especially around replacement
* Place read resources in the snapshot with "external" bit set
Fixespulumi/pulumi#1521. This commit introduces two new step ops: Read
and ReadReplacement. The engine generates Read and ReadReplacement steps
when servicing ReadResource RPC calls from the language host.
* Fix an omission of OpReadReplace from the step list
* Rebase against master
* Transition to use V2 Resources by default
* Add a semantic "relinquish" operation to the engine
If the engine observes that a resource is read and also that the
resource exists in the snapshot as a non-external resource, it will not
delete the resource if the IDs of the old and new resources match.
* Typo fix
* CR: add missing comments, DeserializeDeployment -> DeserializeDeploymentV2, ID check
When a resource fails to initialize (i.e., it is successfully created,
but fails to transition to a fully-initialized state), and a user
subsequently runs `pulumi update` without changing that resource, our
CLI will fail to warn the user that this resource is not initialized.
This commit begins the process of allowing our CLI to report this by
storing a list of initialization errors in the checkpoint.
* Revert "Parallelize much more of resource creation in the JS language provider SDK (#1618)"
This reverts commit 4edd244a26.
* Revert "Process our async-work-queue in parallel. (#1619)"
This reverts commit b8c1cb9574.
This commit adds CLI support for resource providers to provide partial
state upon failure. For resource providers that model resource
operations across multiple API calls, the Provider RPC interface can now
accomodate saving bags of state for resource operations that failed.
This is a common pattern for Terraform-backed providers that try to do
post-creation steps on resource as part of Create or Update resource
operations.
A critical part of the partial update protocol is to return a structured
error when a resource is successfully created, but fails to initialize.
This structured error contains the properties of the
partially-initialized resource, and instructs the engine to halt.
Most languages implement this by attaching "details" to the error, i.e.,
an arbitrary proto message attached to the error. The JavaScript
implementation is not mature enough to include all the facilities
required to use this, so here we must add a `Status` message, which
protobuf requires as part of its structure for returning details.
* Test the Python language host end-to-end
This commit introduces an end-to-end language host testing framework for
the Python SDK, similar to what already exists for the Node SDK. The
real language host is used to run Pulumi programs written in Python
while mocking out the resource monitor.
* Add new tests
* Print out better diagnostics when the langhost fails to launch
* Use the in-tree executor for testing
* CR: Place tests and code being tested in the same directory for ease of understanding, add a README
* Turns out I misunderstood the semantics of resource registration - fix two tests so that they pass now and fix a few bugs in the test harness
This change includes the Python and Golang language hosts in the Windows
SDK. As part of this change, I had to adjust how we launched the second
stage of the language host, since we can't depend on the shebang, so now
we invoke `python` passing the executor and then the arguments.
Fixes#1509
1) Use a state block for *Outputs, just to protect against dereferencing
and aliasing. These are mutable due to concurrency.
2) Dig into *Output type aliases, like *URNOutput, et. al, during
RPC marshaling.
This change adds a config package. This is syntactic sugar atop the
underlying config functionality in the pulumi.Context, but mirrors what
we do in our other Node.js and Python SDKs more closely.
This includes three families of functions:
- config.Get*: returns the value or its default if missing.
- config.Require*: returns the value or panics if missing.
- config.Try*: returns the value or an error if missing.
In all cases, there are simple Get/Require/Try functions, that just
deal in terms of strings, in addition to type specific functions,
GetT/RequireT/TryT, for the most common Ts that you might need.
This commit implements unknown outputs in the same style as our Node.js
language provider. That is to say, during previews, it's possible that
certain outputs will not have known values. In those cases, we want to
flow sufficient information through the resolution of values, so that we
may skip applies. We also return this fact from the direct accessors.
This change primarily does two things:
* Adds output marshaling.
* Adds tests for roundtripping inputs to outputs.
It also
* Fixes a bug in the verification of asset archives.
* Change input types to simply `interface{}` and `map[string]interface{}`.
There is no need for wrapper types. This is more idiomatic.
* Reject output properties upon marshaling failure.
* Don't support time.Time as a marshaling concept. This was getting too
cute. It's not clear what its marshaling format ought to be.
This improves the strong typing of output properties, by leveraging the
cast library to support numeric conversions to and from many types,
without hitting interface{}-cast panics. Also adds strongly typed
applies and adds a number of additional tests for these functions.
This change adds some convenience functions and types, to make strongly
typed outputs more pleasant to interact with. It also includes tests
for output generally, in addition to these new functions and types.
This adds rudimentary support for Pulumi programs written in Go. It
is not complete yet but the basic resource registration works.
Note that, stylistically speaking, Go is a bit different from our other
languages. This made it a bit easier to build this initial prototype,
since what we want is actually a rather thin veneer atop our existing
RPC interfaces. The lack of generics, however, adds some friction and
is something I'm continuing to hammer on; this will most likely lead to
little specialized types (e.g. StringOutput) once the dust settles.
There are two primary components:
1) A new language host, `pulumi-language-go`, which is responsible for
communicating with the engine through the usual gRPC interfaces.
Because Go programs are pre-compiled, it very simply loads a binary
with the same name as the project.
2) A client SDK library that Pulumi programs bind against. This exports
the core resource types -- including assets -- properties -- including
output properties -- and configuration.
Most remaining TODOs are marked as such in the code, and this will not
be merged until they have been addressed, and some better tests written.
* Fix a few issues with the Python language host
1. Fix an issue where the UNKNOWN sentinel was leaking into user
programs
2. Fix an issue where Protobuf types were leaking into user programs
In fixing this issues I also added a framework for writing tests against
the Python SDK.
* License headers, and adopt a more idiomatic testing pattern
* Additional idiomatic Python
* That's what I get for trying to be fancy (Travis CI python version is very old and does not respect this form)
* CR feedback: use more comprehensions, typo fix
* Break a circular dependency between resource, runtime.resource, and runtime.rpc
* Don't check in .vscode
* CR: sort inputs, rename global variable, add a test for CustomResource serialization
* Remove accidental code duplication