Merge branch 'master' into iwahbe/2715/add-pulumi-about-command

This commit is contained in:
Ian Wahbe 2021-08-27 04:50:50 -04:00
commit 878ab50044
109 changed files with 4932 additions and 189 deletions

22
.readthedocs.yaml Normal file
View file

@ -0,0 +1,22 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
# Required
version: 2
# Build documentation in the developer-docs/ directory with Sphinx
sphinx:
configuration: developer-docs/conf.py
formats:
- pdf
# Optionally set the version of Python and requirements required to build your docs
python:
version: "3.6"
install:
- requirements: developer-docs/requirements.txt

View file

@ -1,6 +1,35 @@
CHANGELOG
=========
## 3.11.0 (2021-08-25)
### Improvements
- [auto/dotnet] - Add support for `--exact` and `--server` with `pulumi plugin install` via Automation API. BREAKING NOTE: If you are subclassing `Workspace` your `InstallPluginAsync` implementation will need to be updated to reflect the new `PluginInstallOptions` parameter.
[#7762](https://github.com/pulumi/pulumi/pull/7796)
- [codegen/go] - Add helper function forms `$fnOutput` that accept
`Input`s, return an `Output`, and wrap the underlying `$fn` call.
This change addreses
[#5758](https://github.com/pulumi/pulumi/issues/) for Go, making it
easier to compose functions/datasources with Pulumi resources.
[#7784](https://github.com/pulumi/pulumi/pull/7784)
- [sdk/python] - Speed up `pulumi up` on Python projects by optimizing
`pip` invocations
[#7819](https://github.com/pulumi/pulumi/pull/7819)
- [sdk/dotnet] - Support for calling methods.
[#7582](https://github.com/pulumi/pulumi/pull/7582)
### Bug Fixes
- [cli] - Avoid `missing go.sum entry for module` for new Go projects.
[#7808](https://github.com/pulumi/pulumi/pull/7808)
- [codegen/schema] - Allow hyphen in schema path reference.
[#7824](https://github.com/pulumi/pulumi/pull/7824)
## 3.10.3 (2021-08-19)
### Improvements

View file

@ -7,6 +7,3 @@
- [cli/about] - Add comand for debug information
[#7817](https://github.com/pulumi/pulumi/pull/7817)
- [cli] - Avoid `missing go.sum entry for module` for new Go projects.
[#7808](https://github.com/pulumi/pulumi/pull/7808)

View file

@ -36,6 +36,9 @@ build:: generate
build_debug:: generate
cd pkg && go install -gcflags="all=-N -l" -ldflags "-X github.com/pulumi/pulumi/pkg/v3/version.Version=${VERSION}" ${PROJECT}
developer_docs::
cd developer-docs && make html
install:: generate
cd pkg && GOBIN=$(PULUMI_BIN) go install -ldflags "-X github.com/pulumi/pulumi/pkg/v3/version.Version=${VERSION}" ${PROJECT}

1
developer-docs/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
_build

28
developer-docs/Makefile Normal file
View file

@ -0,0 +1,28 @@
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build
html: Makefile graphics
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
pdf: Makefile graphics
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: graphics Makefile
SVG_FILES = \
providers/resource-lifecycle.svg \
architecture/construct.svg \
architecture/create.svg \
architecture/delete-before-replace-graph.svg \
architecture/delete-before-replace.svg \
architecture/import.svg \
architecture/replace.svg \
architecture/same.svg \
architecture/update.svg
%.svg: %.uml
plantuml -tsvg $<
graphics: Makefile $(SVG_FILES)

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -0,0 +1,13 @@
@startuml
participant "Language SDK" order 10
box "Engine"
participant "Resource Monitor" order 15
end box
participant "Resource Provider" order 30
"Language SDK" -> "Resource Monitor" ++ : RegisterResourceRequest(type, name, inputs, options)
"Resource Monitor" -> "Resource Provider" ++ : ConstructRequest(monitor address, type, name, inputs, options)
"Resource Provider" <--> "Resource Monitor": Component resource + child resource registrations
"Resource Monitor" <- "Resource Provider" -- : ConstructResponse(outputs)
"Language SDK" <- "Resource Monitor" -- : RegisterResourceResponse(urn, ID, new state)
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,23 @@
@startuml
participant "Language SDK" order 10
box "Engine"
participant "Resource Monitor" order 15
participant "Step Generator" order 20
participant "Step Executor" order 25
end box
participant "Resource Provider" order 30
"Language SDK" -> "Resource Monitor" ++ : RegisterResourceRequest(type, name, inputs, options)
"Resource Monitor" -> "Step Generator" ++ : RegisterResourceEvent(type, name, inputs, options)
"Step Generator" -> "Resource Provider" ++ : CheckRequest(type, inputs)
"Step Generator" <- "Resource Provider" -- : CheckResponse(inputs', failures)
"Step Generator" -> "Step Executor" --++ : CreateStep(inputs', options)
note left
This is fire-and-forget on the part of the step generator.
The step will run in parallel with steps for other resources.
end note
"Step Executor" -> "Resource Provider" ++ : CreateRequest(type, inputs')
"Step Executor" <- "Resource Provider" -- : CreateResponse(new state)
"Resource Monitor" <- "Step Executor" -- : done(new state)
"Language SDK" <- "Resource Monitor" -- : RegisterResourceResponse(urn, ID, new state)
@enduml

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="247px" preserveAspectRatio="none" style="width:175px;height:247px;background:#FFFFFF;" version="1.1" viewBox="0 0 175 247" width="175px" zoomAndPan="magnify"><defs><filter height="300%" id="f1xo3jf5eexdn" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><!--MD5=[770389ab9df153645bc6ef28055eb2b5]
entity A--><rect fill="#FEFECE" filter="url(#f1xo3jf5eexdn)" height="36.4883" style="stroke:#A80036;stroke-width:1.5;" width="30" x="39" y="199"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="10" x="49" y="222.5352">A</text><!--MD5=[b2d39259b6aeabc16b394deeb0238426]
entity B--><rect fill="#FEFECE" filter="url(#f1xo3jf5eexdn)" height="36.4883" style="stroke:#A80036;stroke-width:1.5;" width="28" x="8" y="103"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="8" x="18" y="126.5352">B</text><!--MD5=[16fab723be418f7eaf2ea4bd895a8e51]
entity C--><rect fill="#FEFECE" filter="url(#f1xo3jf5eexdn)" height="36.4883" style="stroke:#A80036;stroke-width:1.5;" width="30" x="71" y="103"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="10" x="81" y="126.5352">C</text><!--MD5=[118f42602524ad482f02b27ef22fc383]
entity D--><rect fill="#FEFECE" filter="url(#f1xo3jf5eexdn)" height="36.4883" style="stroke:#A80036;stroke-width:1.5;" width="30" x="7" y="7"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="10" x="17" y="30.5352">D</text><!--MD5=[68f82070d0aec4ff4b64d9b1102926da]
entity E--><rect fill="#FEFECE" filter="url(#f1xo3jf5eexdn)" height="36.4883" style="stroke:#A80036;stroke-width:1.5;" width="28" x="72" y="7"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="8" x="82" y="30.5352">E</text><!--MD5=[22029b2902cbfefb11350e8ee6e306b3]
entity F--><rect fill="#FEFECE" filter="url(#f1xo3jf5eexdn)" height="36.4883" style="stroke:#A80036;stroke-width:1.5;" width="28" x="135" y="7"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="8" x="145" y="30.5352">F</text><!--MD5=[72912e6cd343fd0b615113a50578b9b8]
link E to C--><path d="M86,43.24 C86,58.48 86,80.81 86,97.46 " fill="none" id="E-to-C" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="86,102.87,90,93.87,86,97.87,82,93.87,86,102.87" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[63e03b6ea79d913a67ba6fcf5a4ae973]
link F to C--><path d="M137.44,43.24 C127.05,58.74 111.75,81.59 100.53,98.32 " fill="none" id="F-to-C" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="97.48,102.87,105.813,97.6201,100.2634,98.7163,99.1672,93.1667,97.48,102.87" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[1454d5cde7bc0c276b7bdc83fba84c24]
link C to A--><path d="M80.13,139.24 C74.9,154.61 67.21,177.2 61.53,193.89 " fill="none" id="C-to-A" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="59.83,198.87,66.5232,191.645,61.4454,194.1381,58.9522,189.0603,59.83,198.87" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[5ebc1f44a7c66b9e925829b6b9c43293]
link D to B--><path d="M22,43.24 C22,58.48 22,80.81 22,97.46 " fill="none" id="D-to-B" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="22,102.87,26,93.87,22,97.87,18,93.87,22,102.87" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[2c777c0c38089c390787dfc0786ecb92]
link B to A--><path d="M27.87,139.24 C33.1,154.61 40.79,177.2 46.47,193.89 " fill="none" id="B-to-A" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="48.17,198.87,49.0478,189.0603,46.5546,194.1381,41.4768,191.645,48.17,198.87" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[6f1b4fca46cfefae17b5bfbc8573426e]
@startuml
agent A
agent B
agent C
agent D
agent E
agent F
E - -> C
F - -> C
C - -> A
D - -> B
B - -> A
@enduml
PlantUML version 1.2021.9(Sun Jul 25 03:13:56 PDT 2021)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

@ -0,0 +1,14 @@
@startuml
agent A
agent B
agent C
agent D
agent E
agent F
E --> C
F --> C
C --> A
D --> B
B --> A
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,27 @@
@startuml
participant "Language SDK" order 10
box "Engine"
participant "Resource Monitor" order 15
participant "Step Generator" order 20
participant "Step Executor" order 25
end box
participant "Resource Provider" order 30
"Language SDK" -> "Resource Monitor" ++ : RegisterResourceRequest(type, name, inputs, options)
"Resource Monitor" -> "Step Generator" ++ : RegisterResourceEvent(type, name, inputs, options)
"Step Generator" -> "Resource Provider" ++ : CheckRequest(type, inputs, old inputs)
"Step Generator" <- "Resource Provider" -- : CheckResponse(inputs', failures)
"Step Generator" -> "Resource Provider" ++ : DiffRequest(type, inputs', old state, options)
"Step Generator" <- "Resource Provider" -- : DiffResponse(diffs)
"Step Generator" -> "Step Executor" --++ : [DeleteStep(old state), CreateStep(inputs', options)]
note left
This is fire-and-forget on the part of the step generator.
The steps will run in parallel with steps for other resources.
end note
"Step Executor" -> "Resource Provider" ++ : DeleteRequest(type, old state)
"Step Executor" <- "Resource Provider" -- : DeleteResponse()
"Step Executor" -> "Resource Provider" ++ : CreateRequest(type, inputs', old state)
"Step Executor" <- "Resource Provider" -- : CreateResponse(new state)
"Resource Monitor" <- "Step Executor" -- : done(new state)
"Language SDK" <- "Resource Monitor" -- : RegisterResourceResponse(urn, ID, new state)
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,25 @@
@startuml
participant "Language SDK" order 10
box "Engine"
participant "Resource Monitor" order 15
participant "Step Generator" order 20
participant "Step Executor" order 25
end box
participant "Resource Provider" order 30
"Language SDK" -> "Resource Monitor" ++ : RegisterResourceRequest(type, name, inputs, options)
"Resource Monitor" -> "Step Generator" ++ : RegisterResourceEvent(type, name, inputs, options)
"Step Generator" -> "Step Executor" --++ : ImportStep(inputs, options)
note left
This is fire-and-forget on the part of the step generator.
The step will run in parallel with steps for other resources.
end note
"Step Executor" -> "Resource Provider" ++ : ReadRequest(type, id)
"Step Executor" <- "Resource Provider" -- : ReadResponse(current inputs, current state)
"Step Executor" -> "Resource Provider" ++ : CheckRequest(type, inputs, current inputs)
"Step Executor" <- "Resource Provider" -- : CheckResponse(inputs', failures)
"Step Executor" -> "Resource Provider" ++ : DiffRequest(type, inputs', current state, options)
"Step Executor" <- "Resource Provider" -- : DiffResponse(diffs)
"Resource Monitor" <- "Step Executor" -- : done(current state)
"Language SDK" <- "Resource Monitor" -- : RegisterResourceResponse(urn, ID, current state)
@enduml

View file

@ -0,0 +1,19 @@
# Pulumi Architecture Overview
Broadly speaking, Pulumi is composed of five components:
1. The deployment engine
2. State storage backends
3. Language SDKs
4. Resource providers
5. Package schemas and code generators
## The Deployment Engine
## State Storage Backends
## Language SDKs
## Resource Providers
## Package Schemas and Code Generators

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -0,0 +1,30 @@
@startuml
participant "Language SDK" order 10
box "Engine"
participant "Resource Monitor" order 15
participant "Step Generator" order 20
participant "Step Executor" order 25
end box
participant "Resource Provider" order 30
"Language SDK" -> "Resource Monitor" ++ : RegisterResourceRequest(type, name, inputs, options)
"Resource Monitor" -> "Step Generator" ++ : RegisterResourceEvent(type, name, inputs, options)
"Step Generator" -> "Resource Provider" ++ : CheckRequest(type, inputs, old inputs)
"Step Generator" <- "Resource Provider" -- : CheckResponse(inputs', failures)
"Step Generator" -> "Resource Provider" ++ : DiffRequest(type, inputs', old state, options)
"Step Generator" <- "Resource Provider" -- : DiffResponse(diffs)
"Step Generator" -> "Step Executor" --++ : CreateStep(inputs', old state, options)
note left
This is fire-and-forget on the part of the step generator.
The step will run in parallel with steps for other resources.
end note
"Step Executor" -> "Resource Provider" ++ : CreateRequest(type, inputs', old state)
"Step Executor" <- "Resource Provider" -- : CreateResponse(new state)
"Resource Monitor" <- "Step Executor" -- : done(new state)
"Language SDK" <- "Resource Monitor" -- : RegisterResourceResponse(urn, ID, new state)
...Pulumi program exits...
"Step Generator" -> "Step Generator": Generate delete steps
"Step Generator" -> "Step Executor" ++ : DeleteStep(old state)
"Step Executor" -> "Resource Provider" ++ : DeleteRequest(type, old state)
"Step Executor" <- "Resource Provider" -- : DeleteResponse()
@enduml

View file

@ -0,0 +1,255 @@
# Resource Registration
A Pulumi program declares the desired states of its stack's resources by sending `RegisterResource` requests to the
Pulumi engine. Each `RegisterResource` request contains the type, name, and parent (if any) of the resource, a
reference to the provider instance that manages the resource (where an empty reference indicates that the resource
uses the default provider instance for its package + version), the values of the resource's input properties, and
any options that apply to the resource. The engine decides what step to take in order to drive a resource to its
goal state by diffing the resource's current state as present in the statefile with its desired state. If there is
no current state, the resource is created. Otherwise, the engine calls the resource's provider's `Diff` method to
determine wither the resource is unchanged, updated, or replaced. Once the required action (or actions, in the case
of a replacement) has been determined, the engine calls the resource's provider's `Create`, `Update`, or `Delete`
methods to perform it. After the action completes, the engine returns the new state of the resource to the Pulumi
program.
Although we typically treat the engine as a single unit, in the case of resource registrations it helps to break it
down into a few of its internal components: the resource monitor, the step generator, and the step executor. Each
of these components is a participant in the response to a `RegisterResourceRequest`.
## The Resource Monitor
The resource monitor provides serves the `ResourceMonitor` gRPC interface, and provides a shim between language SDKs
and the rest of the engine. There is a single resource monitor per deployment. As the engine's feature set has grown,
the resource monitor has taken on responsibilities beyond its original use as a simple marshaling/unmarshaling layer.
It is now responsible for handling default providers (providers for resource registrations that do not reference a
provider instance) and for dispatching `RegisterResourceRequest`s for multi-language components into appropriate
`Construct` calls.
When the resource monitor receives a resource registration, it does the following:
1. Unmarshals data from the gRPC wire format to the engine's internal representation.
2. If the registration request does not name a provider instance, handles the resolution of the resource's default
provider.
3. If the request is for a multi-language component, dispatches a `Construct` call to the component's provider and
waits for the result.
4. If the request is not for a multi-langauge component, sends a `RegisterResourceEvent` to the step generator and
waits for the result.
5. Marshals the result of the `Construct` call or `RegisterResourceEvent` from the engine's internal representation
to the gRPC wire format and returns from the RPC call.
### Default Providers
Default providers demand some amount of special attention. A _default provider_ for a package and version is the
provider instance that is used for resources at that package and version that do not otherwise reference a provider
instance when they are registered. For example, consider the following program that creates an AWS S3 bucket:
```typescript
import * as aws from "@pulumi/aws";
new aws.s3.Bucket("myBucket");
```
The constructor call will become a `RegisterResourceRequest` like:
```
RegisterResourceRequest{
type: "aws:s3/bucket:Bucket",
name: "myBucket",
parent: "urn:pulumi:dev::project::pulumi:pulumi:Stack::project",
custom: true,
object: {},
version: "4.16.0",
}
```
Becuase this request does not contain a value for the `provider` field, it will use the default provider for the
`aws` package at version 4.16.0. The resource monitor ensures that only a single default provider instance exists
for each particular package version, and only creates default provider instances if they are needed. Default provider
instances are registered by synthesizing an appropriate `RegisterResourceEvent` with input properties sourced from the
stack's configuration values for the provider's package. In the example above, the AWS default provider would be
configured using any stack configuration values whose keys begin with `aws:` (e.g. `aws:region`).
If we change the program slightly to create and reference a provider instance, the default provider will no longer
be used:
```typescript
import * as aws from "@pulumi/aws";
const usWest2 = new aws.Provider("us-west-2", {region: "us-west-2"});
new aws.s3.Bucket("myBucket", {}, {provider: usWest2});
```
The constructor call will become a `RegisterResourceRequest` like:
```
RegisterResourceRequest{
type: "aws:s3/bucket:Bucket",
name: "myBucket",
parent: "urn:pulumi:dev::project::pulumi:pulumi:Stack::project",
custom: true,
object: {},
provider: "urn:pulumi:dev::vpc-2::pulumi:providers:aws::us-west-2::308b79ee-8249-40fb-a203-de190cb8faa8",
version: "4.16.0",
}
```
Note that this request _does_ contain a value for the `provider` field.
## The Step Generator
The step generator is responsible for processing `RegisterResourceEvent`s from the resource monitor. The generator
implements the core logic that determines which actions to take in order to drive the actual state of a resource to
its desired state as represented by the input properties in its `RegisterResourceEvent`. In order to simplify
reasoning about the actual state of a stack's resources, the step generator processes `RegisterResourceEvent`s
serially. It is important to note that this approach puts the step generator on a deployment's critical path, so
any significant blocking in the step generator may slow down deployments accordingly. In the case of updates, step
generator latency is generally insignificant compared to the time spent performing resource operations, but this is
not the case for updates where most resources are unchanged or for previews, which spend very little time in resource
providers in general.
When the step generator receives a `RegisterResourceEvent`, it does the following:
1. Generate a URN for the resource using the resource's type, name, and parent.
2. Look up the existing state for the resource, if any. If the event contains aliases for the resource, this includes
checking for existing state under those aliases. It is an error if a resource's aliases match multiple existing
states.
3. Pre-process input properties for ignored changes by setting any properties mentioned in the event's ignore changes
list to their old value (if any)
4. If the event indicates that the resource should be imported, issue an `ImportStep` to the step executor and return.
5. Call the resource's provider's `Check` method with the event's input properties and the resource's existing inputs,
if any. The existing inputs may be used by the provider to repopulate default values for input properties that are
automatically generated when the resource is created but should not be changed with subsequent updates (e.g.
automatically generated names). `Check` returns a pre-processed bag of input values to be used with later calls to
`Diff`, `Create`, and `Update`.
6. Invoke any analyzers for the stack to perform additional validation of the resource's input properties.
7. If the resource has no existing state, it is being created. Issue a `CreateStep` to the step executor and return.
8. Diff the resource in order to determine whether it must be updated, replaced, delete-before-replaced, or has no
changes. Diffing is covered in detail later on, but typically consists of calling the reosource's provider's
`Diff` method with the checked inputs from step 5.
9. If the resource has no changes, issue a `SameStep` to the step executor and return.
10. If the resource is not being replaced, issue an `UpdateStep` to the step executor and return.
11. If the resource is being replaced, call the resource's provider's `Check` method again, but with no existing
inputs. This call ensures that the input properties used to create the replacement resource do not reuse
generated defaults from the existing resource.
12. If the replacement resource is being created before the original is deleted (a normal replacement), issue a
`CreateStep` and a `DeleteStep` to the step executor and return.
13. At this point, the resource must be deleted before its replacement is created (this is the "delete-before-replace"
case). Calculate the set of dependent resources that must be deleted prior to deleting the resource being replaced.
The details of this calculation are covered in a later section. Once the set of deletions has been calculated,
issue a sequence of `DeleteStep`s followed by a single `CreateStep` to the step executor.
Note that all steps that are issued to the step generator are fire-and-forget. Once steps have been issues, the step
generator moves on to process the next `RegisterResourceEvent`. It is the responsibility of the step executor to
communicate the results of each step back to the resource monitor.
Once the Pulumi program has exited, the step generator determines which existing resources must be deleted by taking
the difference between the set of registered resources and the set of existing resources. These resources are scheduled
for deletion by first sorting the list of resources to delete using the topological order of their reverse-dependency
grapth, then decomposing the list into a list of lists where each list can be executed in parallel but a previous list
must be executed to completion before advancing to the next list.
In lieu of tracking per-step dependencies and orienting the step executor around these dependencies, this approach
provides a conservative approximation of what deletions can safely occur in parallel. The insight here is that the
resource dependency graph is a partially-ordered set and all partially-ordered sets can be easily decomposed into
antichains--subsets of the set that are all not comparable to one another (in this definition, "not comparable"
means "do not depend on one another").
The algorithm for decomposing a poset into antichains is:
1. While there exist elements in the poset,
a. There must exist at least one "maximal" element of the poset. Let `E_max` be those elements.
b. Remove all elements E_max from the poset. `E_max` is an antichain.
c. Goto 1.
Translated to a resource dependency graph:
1. While the set of condemned resources is not empty:
a. Remove all resources with no outgoing edges from the graph and add them to the current antichain.
b. Goto 1.
The resulting list of antichains is a list of list of delete steps that can be safely executed in parallel. Since
deletes must be processed in reverse order (so that resources are not deleted prior to their dependents), the step
generator reverses the list and then issues each sublist to the step executor.
### Resource Diffing
Although resource diffing is simple in most cases, there are several possibilities that the step generator must
consider as part of performing a diff. The algorithm for diffing a resource is outlined here.
1. If the resource has been marked for replacement out of band (e.g. by the use of the `--target-replace` command-line
option of the Pulumi CLI), the resource must be replaced.
2. If the resource's provider has changed, the resource must be replaced. Default providers are allowed to change
without requiring replacement if and only if the provider's configuration allows the new default provider to continue
to manage existing resources (this is intended to allow default providers to be upgraded without requiring that
all the resources they manage are replaced).
3. If the engine is configured to use pre-1.0-style diffs, compare the resource's old and new inputs. If the old and
new inputs differ, the resource must be updated.
4. Otherwise, call the resource's provider's `Diff` method with the resource's new inputs, old state, and ignore changes
set to determine whether the resource has changed, and if so, if it must be replaced.
Once the diff has been calculated, the step generator applies any replace-on-change options specified by the
resource. These options force a resource to require that it is replaced if any of a particular set of properties has
changed.
### Dependent Replacements
When a resource must be deleted before it is replaced--whether this is required by the resource's provider or is forced
using the `deleteBeforeReplace` resource option--it may be necessary to first delete dependent resources. The step
generator does 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. It determines whether or not a
resource must be replaced by substituting unknowns for any input properties that may change due to deletion of the
resources their value depends on and calling the resource's provider's `Diff` method.
This is perhaps clearer when described by example. Consider the following dependency graph:
![Delete-before-replace example graph](./delete-before-replace-graph.svg)
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. More commonly, the edge from B to A may be due
to a property from A being used as the input to a property of B that does not require B to be replaced upon a change.
In these cases, neither B nor D would need to be deleted before A could be deleted.
## The Step Executor
The step executor is responsible for executing sequences of steps (called "chains") that perform the resource actions
for a deployment. These chains are issued by the step generator, and most often consist of a single step. While the
steps the make up a chain must be performed serially, chains may be executed in parallel. The step executor uses a
(potentially infinite) pool of workers to execute steps. Once a step completes, the step executor communicates its
results to the resource monitor if necessary. If a step fails, the step executor notes the failure and cancels the
deployment. Once the Pulumi program has exited and the step generator has issued all required deletions, the step
executor waits for all outstanding steps to complete and then returns.
## Example Resource Registration Sequences
### Custom Resources
Each of the diagrams below demonstrates a sequence of events that occur when a custom resource is registered. Examples
are given for each possible action: create, update, replace, delete-before-replace, import, and no change.
#### Create
![Create diagram](./create.svg)
#### Update
![Update diagram](./update.svg)
#### Replace
![Replace diagram](./replace.svg)
#### Delete-before-replace
![Delete-before-replace diagram](./delete-before-replace.svg)
#### Import
![Import diagram](./import.svg)
#### No change
![No change diagram](./same.svg)
### Multi-language Components
The diagram below illustrates the sequence of events that occurs when a multi-language component is registered. The
registration of the component's children is elided.
![Multi-language component construction](./construct.svg)

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,23 @@
@startuml
participant "Language SDK" order 10
box "Engine"
participant "Resource Monitor" order 15
participant "Step Generator" order 20
participant "Step Executor" order 25
end box
participant "Resource Provider" order 30
"Language SDK" -> "Resource Monitor" ++ : RegisterResourceRequest(type, name, inputs, options)
"Resource Monitor" -> "Step Generator" ++ : RegisterResourceEvent(type, name, inputs, options)
"Step Generator" -> "Resource Provider" ++ : CheckRequest(type, inputs, old inputs)
"Step Generator" <- "Resource Provider" -- : CheckResponse(inputs', failures)
"Step Generator" -> "Resource Provider" ++ : DiffRequest(type, inputs', old state)
"Step Generator" <- "Resource Provider" -- : DiffResponse(diffs)
"Step Generator" -> "Step Executor" --++ : SameStep(inputs', old state, options)
note left
This is fire-and-forget on the part of the step generator.
The step will run in parallel with steps for other resources.
end note
"Resource Monitor" <- "Step Executor" -- : done(old state)
"Language SDK" <- "Resource Monitor" -- : RegisterResourceResponse(urn, ID, old tate)
@enduml

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,25 @@
@startuml
participant "Language SDK" order 10
box "Engine"
participant "Resource Monitor" order 15
participant "Step Generator" order 20
participant "Step Executor" order 25
end box
participant "Resource Provider" order 30
"Language SDK" -> "Resource Monitor" ++ : RegisterResourceRequest(type, name, inputs, options)
"Resource Monitor" -> "Step Generator" ++ : RegisterResourceEvent(type, name, inputs, options)
"Step Generator" -> "Resource Provider" ++ : CheckRequest(type, inputs, old inputs)
"Step Generator" <- "Resource Provider" -- : CheckResponse(inputs', failures)
"Step Generator" -> "Resource Provider" ++ : DiffRequest(type, inputs', old state, options)
"Step Generator" <- "Resource Provider" -- : DiffResponse(diffs)
"Step Generator" -> "Step Executor" --++ : UpdateStep(inputs', old state, options)
note left
This is fire-and-forget on the part of the step generator.
The step will run in parallel with steps for other resources.
end note
"Step Executor" -> "Resource Provider" ++ : UpdateRequest(type, inputs', old state)
"Step Executor" <- "Resource Provider" -- : UpdateResponse(new state)
"Resource Monitor" <- "Step Executor" -- : done(new state)
"Language SDK" <- "Resource Monitor" -- : RegisterResourceResponse(urn, ID, new state)
@enduml

19
developer-docs/build.md Normal file
View file

@ -0,0 +1,19 @@
# Building the Docs
In order to build the devloper documentation:
1. Install [PlantUML](https://plantuml.com). On macOS, this can be done via `brew install plantuml`.
2. Install the requirements for Sphinx:
```bash
$ pip install requirements.txt
```
3. Run `make` to build the HTML documentation:
```bash
$ make
```
This will regenerate any out-of-date SVGs and build the a local version of the HTML documentation. The documentation
can also be built from the repository root by running `make developer_docs`.

55
developer-docs/conf.py Normal file
View file

@ -0,0 +1,55 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- Project information -----------------------------------------------------
project = 'Pulumi'
copyright = '2021, Pulumi Corporation'
author = 'Pulumi'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autosectionlabel',
'sphinx_tabs.tabs',
'myst_parser',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

32
developer-docs/index.md Normal file
View file

@ -0,0 +1,32 @@
# Pulumi Developer Documentation
Welcome to the Pulumi developer documentation! This documentation provides details on Pulumi internals, including but
not limited to:
- How to build and test Pulumi
- Pulumi architectural details
- Specifications
Use the navigation bar to the left to browse the docs.
```{toctree}
:hidden:
:caption: System Architecture
architecture/overview
architecture/resource-registration
```
```{toctree}
:hidden:
:caption: Resource Providers
providers/implementers-guide
```
```{toctree}
:hidden:
:caption: Meta
build
```

View file

@ -338,7 +338,7 @@ last refereshed state.
The diagram below summarizes the custom resource lifecycle. Detailed descriptions of each
resource operation follow.
![Custom Resource Lifeycle Diagram](./resource_lifecycle.svg)
![Custom Resource Lifeycle Diagram](./resource-lifecycle.svg)
### Lifecycle Methods

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="795px" preserveAspectRatio="none" style="width:1385px;height:795px;background:#FFFFFF;" version="1.1" viewBox="0 0 1385 795" width="1385px" zoomAndPan="magnify"><defs><filter height="300%" id="f1ht2b1gslamyn" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><ellipse cx="453" cy="16" fill="#000000" filter="url(#f1ht2b1gslamyn)" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="150.4883" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="256" x="7" y="368"/><rect fill="#FFFFFF" height="118" rx="12.5" ry="12.5" style="stroke:#FFFFFF;stroke-width:1.0;" width="250" x="10" y="397.4883"/><line style="stroke:#A80036;stroke-width:1.5;" x1="7" x2="263" y1="394.4883" y2="394.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="34" x="118" y="386.5352">Read</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="228" x="19" y="406.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="218" x="24" y="431.7793">Read(reg.URN, reg.ID, reg.State)</text><ellipse cx="133" cy="492.4883" filter="url(#f1ht2b1gslamyn)" rx="10" ry="10" style="stroke:#000000;stroke-width:1.0;fill:none;"/><ellipse cx="133.5" cy="492.9883" fill="#000000" rx="6" ry="6" style="stroke:none;stroke-width:1.0;"/><!--MD5=[a9f1eddd24a2a537be099c93a63c087b]
link read_read to *end*Read--><path d="M133,446.6883 C133,456.4483 133,468.1083 133,477.0783 " fill="none" id="read_read-to-*end*Read" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="133,482.2883,137,473.2883,133,477.2883,129,473.2883,133,482.2883" style="stroke:#A80036;stroke-width:1.0;"/><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="302.4883" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="310" x="298" y="292"/><rect fill="#FFFFFF" height="270" rx="12.5" ry="12.5" style="stroke:#FFFFFF;stroke-width:1.0;" width="304" x="301" y="321.4883"/><line style="stroke:#A80036;stroke-width:1.5;" x1="298" x2="608" y1="318.4883" y2="318.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="46" x="430" y="310.5352">Import</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="159" x="371.5" y="330.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="149" x="376.5" y="355.7793">Read(reg.URN, reg.ID)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="282" x="310" y="406.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="272" x="315" y="431.7793">Check(reg.URN, reg.Inputs, read.Inputs)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="271" x="315.5" y="482.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="261" x="320.5" y="507.7793">Diff(reg.URN, check.Inputs, read.State)</text><ellipse cx="451" cy="568.4883" filter="url(#f1ht2b1gslamyn)" rx="10" ry="10" style="stroke:#000000;stroke-width:1.0;fill:none;"/><ellipse cx="451.5" cy="568.9883" fill="#000000" rx="6" ry="6" style="stroke:none;stroke-width:1.0;"/><!--MD5=[ae6d5a98713f46cd29b3aff73c0432aa]
link import_read to import_check--><path d="M451,370.5483 C451,379.8783 451,391.2283 451,401.1783 " fill="none" id="import_read-to-import_check" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="451,406.2383,455,397.2383,451,401.2383,447,397.2383,451,406.2383" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[430f2e2903cceea4610401c9d1b5b4d3]
link import_check to import_diff--><path d="M451,446.5483 C451,455.8783 451,467.2283 451,477.1783 " fill="none" id="import_check-to-import_diff" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="451,482.2383,455,473.2383,451,477.2383,447,473.2383,451,482.2383" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[95fe03e3183800fd46e941677e7205f9]
link import_diff to *end*Import--><path d="M451,522.6883 C451,532.4483 451,544.1083 451,553.0783 " fill="none" id="import_diff-to-*end*Import" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="451,558.2883,455,549.2883,451,553.2883,447,549.2883,451,558.2883" style="stroke:#A80036;stroke-width:1.0;"/><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="680.4883" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="730" x="643" y="103"/><rect fill="#FFFFFF" height="648" rx="12.5" ry="12.5" style="stroke:#FFFFFF;stroke-width:1.0;" width="724" x="646" y="132.4883"/><line style="stroke:#A80036;stroke-width:1.5;" x1="643" x2="1373" y1="129.4883" y2="129.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="54" x="981" y="121.5352">Manage</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="281" x="673" y="141.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="271" x="678" y="166.7793">Check(reg.URN, reg.Inputs, last?.Inputs)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="215" x="655" y="292.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="205" x="660" y="317.7793">Create(reg.URN, check.Inputs)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="314" x="790.5" y="234.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="304" x="795.5" y="259.7793">Diff(reg.URN, check.Inputs, last.ID, last.State)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="245" x="778" y="408.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="235" x="783" y="433.7793">Update(reg.URN, last.ID, last.State)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="196" x="948.5" y="350.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="186" x="953.5" y="375.7793">Check(reg.URN, reg.Inputs)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="199" x="932" y="466.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="189" x="937" y="491.7793">Create(reg.URN, reg.Inputs)</text><g id="Manage.manage_replace_delete_after_create"><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="50.6211" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="391" x="832" y="601.4883"/><line style="stroke:#A80036;stroke-width:1.5;" x1="832" x2="1223" y1="627.9766" y2="627.9766"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="229" x="913" y="620.0234">Delete(reg.URN, last.ID, last.State)</text><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="371" x="837" y="644.5781">note that this step happens once the Pulumi program has exited</text></g><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="138" x="1161.5" y="466.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="128" x="1166.5" y="491.7793">Delete dependents</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="239" x="1118" y="543.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="229" x="1123" y="568.7793">Delete(reg.URN, last.ID, last.State)</text><rect fill="#FEFECE" filter="url(#f1ht2b1gslamyn)" height="40" rx="12.5" ry="12.5" style="stroke:#A80036;stroke-width:1.5;" width="215" x="1050" y="670.4883"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="205" x="1055" y="695.7793">Create(reg.URN, check.Inputs)</text><ellipse cx="878.5" cy="757.4883" filter="url(#f1ht2b1gslamyn)" rx="10" ry="10" style="stroke:#000000;stroke-width:1.0;fill:none;"/><ellipse cx="879" cy="757.9883" fill="#000000" rx="6" ry="6" style="stroke:none;stroke-width:1.0;"/><!--MD5=[6a24f9d7a6384fcc9dfe0e40779635cd]
link manage_check to manage_create--><path d="M795.02,181.6183 C790.65,187.0283 786.42,193.1883 783.5,199.4883 C770.37,227.8683 765.45,263.8883 763.6,287.3083 " fill="none" id="manage_check-to-manage_create" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="763.24,292.3983,767.8976,283.7203,763.6115,287.4121,759.9197,283.126,763.24,292.3983" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="78" x="784.5" y="213.0566">no last state</text><!--MD5=[6c1279eb02b9d63b68e4e867d2945e06]
link manage_check to manage_diff--><path d="M841.59,181.5683 C863.03,196.1283 892.61,216.2083 915.06,231.4583 " fill="none" id="manage_check-to-manage_diff" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="919.45,234.4383,914.2332,226.0845,915.3074,231.6385,909.7535,232.7127,919.45,234.4383" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="84" x="893.5" y="213.0566">has last state</text><!--MD5=[75cf380d1867293c2c38d7b5794ac0ca]
link manage_diff to manage_update--><path d="M923.37,274.5383 C918.28,279.7883 913.53,285.8783 910.5,292.4883 C894.09,328.2883 894.88,375.0683 897.38,403.1083 " fill="none" id="manage_diff-to-manage_update" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="897.87,408.1183,901.005,398.7817,897.3993,403.1405,893.0405,399.5348,897.87,408.1183" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="96" x="911.5" y="317.5566">can be updated</text><!--MD5=[475bf7a6d5f74542d3094a3e4c006f3f]
link manage_diff to manage_replace_check--><path d="M990.26,274.5983 C998.35,279.5883 1006.23,285.5483 1012.5,292.4883 C1026.08,307.5283 1034.92,328.8583 1040.18,345.2583 " fill="none" id="manage_diff-to-manage_replace_check" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1041.69,350.1783,1042.8602,340.3992,1040.2166,345.4003,1035.2154,342.7567,1041.69,350.1783" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="108" x="1035.5" y="317.5566">must be replaced</text><!--MD5=[0cac4c5aae92b7da67549b590f22b20b]
link manage_replace_check to manage_replace_create_before_delete--><path d="M1043.99,390.5683 C1041.44,409.9683 1037.47,440.0983 1034.7,461.1883 " fill="none" id="manage_replace_check-to-manage_replace_create_before_delete" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1034.02,466.3483,1039.168,457.952,1034.6771,461.3916,1031.2374,456.9007,1034.02,466.3483" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="124" x="1041.5" y="433.5566">create before delete</text><!--MD5=[bb163b3a3cac95fb1660d5b3316a4ec8]
link manage_replace_check to manage_replace_delete_dependents--><path d="M1135.31,390.5783 C1147.7,395.3183 1159.83,401.1983 1170.5,408.4883 C1190.45,422.1183 1206.79,444.4583 1217.36,461.5683 " fill="none" id="manage_replace_check-to-manage_replace_delete_dependents" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1220.18,466.2483,1218.9411,456.4776,1217.5907,461.9709,1212.0974,460.6205,1220.18,466.2483" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="113" x="1209.5" y="433.5566">delete after craete</text><!--MD5=[fd5f046217bb41c91b57f94b75c028e6]
link manage_replace_create_before_delete to manage_replace_delete_after_create--><path d="M1030.94,506.7483 C1030.28,529.8783 1029.15,568.9583 1028.36,596.0383 " fill="none" id="manage_replace_create_before_delete-to-manage_replace_delete_after_create" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1028.21,601.2883,1032.4654,592.4062,1028.3528,596.2903,1024.4687,592.1777,1028.21,601.2883" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[d9dd268e8ab66b521b1fbb3d30a1afd6]
link manage_replace_delete_dependents to manage_replace_delete_before_create--><path d="M1232.3,506.7983 C1233.19,516.3383 1234.28,527.9483 1235.22,538.0883 " fill="none" id="manage_replace_delete_dependents-to-manage_replace_delete_before_create" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1235.7,543.2383,1238.8325,533.9009,1235.228,538.2606,1230.8682,534.6561,1235.7,543.2383" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[4c01834528a54528affee7556f74f604]
link manage_replace_delete_before_create to manage_replace_create_after_delete--><path d="M1239.33,583.7683 C1240.14,602.8883 1238.58,632.1883 1224.5,652.4883 C1220.58,658.1483 1215.5,663.0283 1209.89,667.2183 " fill="none" id="manage_replace_delete_before_create-to-manage_replace_create_after_delete" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="1205.51,670.2883,1215.1765,668.4018,1209.6055,667.42,1210.5873,661.849,1205.51,670.2883" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[58bd43061bbf4734b2332235cc2ce9d5]
link manage_create to *end*Manage--><path d="M762.5,332.8483 C762.5,355.5283 762.5,394.2383 762.5,427.4883 C762.5,427.4883 762.5,427.4883 762.5,691.4883 C762.5,737.3183 832.25,751.1583 863.58,755.0583 " fill="none" id="manage_create-to-*end*Manage" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="868.61,755.6383,860.1256,750.6367,863.6427,755.0673,859.2121,758.5844,868.61,755.6383" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[f306adc3f87ccc87da18b0dfd6870354]
link manage_update to *end*Manage--><path d="M868.26,448.5483 C844.58,465.2483 816.5,491.9083 816.5,524.4883 C816.5,524.4883 816.5,524.4883 816.5,691.4883 C816.5,719.2883 846.56,739.8883 864.81,749.8383 " fill="none" id="manage_update-to-*end*Manage" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="869.62,752.3583,863.4961,744.6448,865.1886,750.0425,859.7909,751.735,869.62,752.3583" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[dfbdada2b400b3d1f7c1a8b46fc52c5b]
link manage_replace_delete_after_create to *end*Manage--><path d="M998.77,652.7683 C965.49,681.4583 912.32,727.3183 889.5,747.0083 " fill="none" id="manage_replace_delete_after_create-to-*end*Manage" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="885.6,750.3683,895.025,747.5102,889.3832,747.0991,889.7943,741.4572,885.6,750.3683" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[ecbac8beeac4b28b80eae4b88efdf6ad]
link manage_replace_create_after_delete to *end*Manage--><path d="M1075.68,710.5483 C1011.27,725.5583 926.95,745.1983 893.3,753.0383 " fill="none" id="manage_replace_create_after_delete-to-*end*Manage" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="888.35,754.1983,898.0206,756.0638,893.221,753.0698,896.215,748.2702,888.35,754.1983" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[a1863298862c1f16686f7212d047fbdc]
link *start to Read--><path d="M442.98,16.87 C416.9,17.05 345.92,20.93 303,56 C208.29,133.38 165.62,274.52 147.42,363.01 " fill="none" id="*start-to-Read" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="146.41,367.97,152.1064,359.9356,147.3961,363.0682,144.2635,358.3579,146.41,367.97" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="140" x="304" y="69.5684">read existing resource</text><!--MD5=[4d808eca49b36bf39c9ca2e13f8697a2]
link *start to Import--><path d="M453,26.27 C453,60.53 453,183.35 453,286.68 " fill="none" id="*start-to-Import" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="453,291.89,457,282.89,453,286.89,449,282.89,453,291.89" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="155" x="454" y="69.5684">import existing resource</text><!--MD5=[9fa6da595ff909d93bcc26d44388e242]
link *start to Manage--><path d="M462.96,17.49 C489.72,19.19 564.71,26.46 618,56 C641.43,68.99 664.42,83.78 686.79,99.83 " fill="none" id="*start-to-Manage" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="690.96,102.84,686.0037,94.3291,686.9059,99.9136,681.3214,100.8158,690.96,102.84" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="107" x="644" y="69.5684">manage resource</text><!--MD5=[318e06d7f4389017c1755234a013d98c]
@startuml
hide empty description
[*] - -> Read: read existing resource
[*] - -> Import: import existing resource
[*] - -> Manage: manage resource
state Read {
state "Read(reg.URN, reg.ID, reg.State)" as read_read
read_read - -> [*]
}
state Import {
state "Read(reg.URN, reg.ID)" as import_read
state "Check(reg.URN, reg.Inputs, read.Inputs)" as import_check
state "Diff(reg.URN, check.Inputs, read.State)" as import_diff
import_read - -> import_check
import_check - -> import_diff
import_diff - -> [*]
}
state Manage {
state "Check(reg.URN, reg.Inputs, last?.Inputs)" as manage_check
state "Create(reg.URN, check.Inputs)" as manage_create
state "Diff(reg.URN, check.Inputs, last.ID, last.State)" as manage_diff
state "Update(reg.URN, last.ID, last.State)" as manage_update
state "Check(reg.URN, reg.Inputs)" as manage_replace_check
state "Create(reg.URN, reg.Inputs)" as manage_replace_create_before_delete
state "Delete(reg.URN, last.ID, last.State)" as manage_replace_delete_after_create
state "Delete dependents" as manage_replace_delete_dependents
state "Delete(reg.URN, last.ID, last.State)" as manage_replace_delete_before_create
state "Create(reg.URN, check.Inputs)" as manage_replace_create_after_delete
manage_replace_delete_after_create: note that this step happens once the Pulumi program has exited
manage_check - -> manage_create: no last state
manage_check - -> manage_diff: has last state
manage_diff - -> manage_update: can be updated
manage_diff - -> manage_replace_check: must be replaced
manage_replace_check - -> manage_replace_create_before_delete: create before delete
manage_replace_check - -> manage_replace_delete_dependents: delete after craete
manage_replace_create_before_delete - -> manage_replace_delete_after_create
manage_replace_delete_dependents - -> manage_replace_delete_before_create
manage_replace_delete_before_create - -> manage_replace_create_after_delete
manage_create - -> [*]
manage_update - -> [*]
manage_replace_delete_after_create - -> [*]
manage_replace_create_after_delete - -> [*]
}
@enduml
PlantUML version 1.2021.9(Sun Jul 25 03:13:56 PDT 2021)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,52 @@
@startuml
hide empty description
[*] --> Read: read existing resource
[*] --> Import: import existing resource
[*] --> Manage: manage resource
state Read {
state "Read(reg.URN, reg.ID, reg.State)" as read_read
read_read --> [*]
}
state Import {
state "Read(reg.URN, reg.ID)" as import_read
state "Check(reg.URN, reg.Inputs, read.Inputs)" as import_check
state "Diff(reg.URN, check.Inputs, read.State)" as import_diff
import_read --> import_check
import_check --> import_diff
import_diff --> [*]
}
state Manage {
state "Check(reg.URN, reg.Inputs, last?.Inputs)" as manage_check
state "Create(reg.URN, check.Inputs)" as manage_create
state "Diff(reg.URN, check.Inputs, last.ID, last.State)" as manage_diff
state "Update(reg.URN, last.ID, last.State)" as manage_update
state "Check(reg.URN, reg.Inputs)" as manage_replace_check
state "Create(reg.URN, reg.Inputs)" as manage_replace_create_before_delete
state "Delete(reg.URN, last.ID, last.State)" as manage_replace_delete_after_create
state "Delete dependents" as manage_replace_delete_dependents
state "Delete(reg.URN, last.ID, last.State)" as manage_replace_delete_before_create
state "Create(reg.URN, check.Inputs)" as manage_replace_create_after_delete
manage_replace_delete_after_create: note that this step happens once the Pulumi program has exited
manage_check --> manage_create: no last state
manage_check --> manage_diff: has last state
manage_diff --> manage_update: can be updated
manage_diff --> manage_replace_check: must be replaced
manage_replace_check --> manage_replace_create_before_delete: create before delete
manage_replace_check --> manage_replace_delete_dependents: delete after craete
manage_replace_create_before_delete --> manage_replace_delete_after_create
manage_replace_delete_dependents --> manage_replace_delete_before_create
manage_replace_delete_before_create --> manage_replace_create_after_delete
manage_create --> [*]
manage_update --> [*]
manage_replace_delete_after_create --> [*]
manage_replace_create_after_delete --> [*]
}
@enduml

View file

@ -0,0 +1,4 @@
sphinx==4.0.2
sphinx_rtd_theme==0.5.2
sphinx-tabs==3.1.0
myst-parser==0.15.1

View file

@ -1,4 +1,4 @@
// Copyright 2016-2020, Pulumi Corporation.
// Copyright 2016-2021, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -706,7 +706,32 @@ func (pkg *pkgContext) getInputUsage(name string) string {
}, "\n")
}
type genInputImplementationArgs struct {
name string
receiverType string
elementType string
ptrMethods bool
toOutputMethods bool
resourceType bool
}
func genInputImplementation(w io.Writer, name, receiverType, elementType string, ptrMethods, resourceType bool) {
genInputImplementationWithArgs(w, genInputImplementationArgs{
name: name,
receiverType: receiverType,
elementType: elementType,
ptrMethods: ptrMethods,
resourceType: resourceType,
toOutputMethods: true,
})
}
func genInputImplementationWithArgs(w io.Writer, genArgs genInputImplementationArgs) {
name := genArgs.name
receiverType := genArgs.receiverType
elementType := genArgs.elementType
resourceType := genArgs.resourceType
fmt.Fprintf(w, "func (%s) ElementType() reflect.Type {\n", receiverType)
if resourceType {
fmt.Fprintf(w, "\treturn reflect.TypeOf((*%s)(nil))\n", elementType)
@ -715,15 +740,17 @@ func genInputImplementation(w io.Writer, name, receiverType, elementType string,
}
fmt.Fprintf(w, "}\n\n")
fmt.Fprintf(w, "func (i %s) To%sOutput() %sOutput {\n", receiverType, Title(name), name)
fmt.Fprintf(w, "\treturn i.To%sOutputWithContext(context.Background())\n", Title(name))
fmt.Fprintf(w, "}\n\n")
if genArgs.toOutputMethods {
fmt.Fprintf(w, "func (i %s) To%sOutput() %sOutput {\n", receiverType, Title(name), name)
fmt.Fprintf(w, "\treturn i.To%sOutputWithContext(context.Background())\n", Title(name))
fmt.Fprintf(w, "}\n\n")
fmt.Fprintf(w, "func (i %s) To%sOutputWithContext(ctx context.Context) %sOutput {\n", receiverType, Title(name), name)
fmt.Fprintf(w, "\treturn pulumi.ToOutputWithContext(ctx, i).(%sOutput)\n", name)
fmt.Fprintf(w, "}\n\n")
fmt.Fprintf(w, "func (i %s) To%sOutputWithContext(ctx context.Context) %sOutput {\n", receiverType, Title(name), name)
fmt.Fprintf(w, "\treturn pulumi.ToOutputWithContext(ctx, i).(%sOutput)\n", name)
fmt.Fprintf(w, "}\n\n")
}
if ptrMethods {
if genArgs.ptrMethods {
fmt.Fprintf(w, "func (i %s) To%sPtrOutput() %sPtrOutput {\n", receiverType, Title(name), name)
fmt.Fprintf(w, "\treturn i.To%sPtrOutputWithContext(context.Background())\n", Title(name))
fmt.Fprintf(w, "}\n\n")
@ -1054,13 +1081,7 @@ func (pkg *pkgContext) genInputTypes(w io.Writer, t *schema.ObjectType, details
// Generate the plain inputs.
pkg.genInputInterface(w, name)
printComment(w, t.Comment, false)
fmt.Fprintf(w, "type %sArgs struct {\n", name)
for _, p := range t.Properties {
printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", Title(p.Name), pkg.typeString(p.Type), p.Name)
}
fmt.Fprintf(w, "}\n\n")
pkg.genInputArgsStruct(w, name+"Args", t)
genInputImplementation(w, name, name+"Args", name, details.ptrElement, false)
@ -1098,14 +1119,43 @@ func (pkg *pkgContext) genInputTypes(w io.Writer, t *schema.ObjectType, details
}
}
func (pkg *pkgContext) genOutputTypes(w io.Writer, t *schema.ObjectType, details *typeDetails) {
contract.Assert(!t.IsInputShape())
name := pkg.tokenToType(t.Token)
func (pkg *pkgContext) genInputArgsStruct(w io.Writer, typeName string, t *schema.ObjectType) {
contract.Assert(t.IsInputShape())
printComment(w, t.Comment, false)
fmt.Fprintf(w, "type %s struct {\n", typeName)
for _, p := range t.Properties {
printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", Title(p.Name), pkg.typeString(p.Type), p.Name)
}
fmt.Fprintf(w, "}\n\n")
}
genOutputType(w, name, name, details.ptrElement, false)
type genOutputTypesArgs struct {
t *schema.ObjectType
// optional type name override
name string
}
func (pkg *pkgContext) genOutputTypes(w io.Writer, genArgs genOutputTypesArgs) {
t := genArgs.t
details := pkg.detailsForType(t)
contract.Assert(!t.IsInputShape())
name := genArgs.name
if name == "" {
name = pkg.tokenToType(t.Token)
}
printComment(w, t.Comment, false)
genOutputType(w,
name, /* baseName */
name, /* elementType */
details.ptrElement, /* ptrMethods */
false, /* resourceType */
)
for _, p := range t.Properties {
printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, false)
@ -1117,7 +1167,8 @@ func (pkg *pkgContext) genOutputTypes(w io.Writer, t *schema.ObjectType, details
propName = "Get" + propName
}
fmt.Fprintf(w, "func (o %sOutput) %s() %s {\n", name, propName, outputType)
fmt.Fprintf(w, "\treturn o.ApplyT(func (v %s) %s { return v.%s }).(%s)\n", name, applyType, Title(p.Name), outputType)
fmt.Fprintf(w, "\treturn o.ApplyT(func (v %s) %s { return v.%s }).(%s)\n",
name, applyType, Title(p.Name), outputType)
fmt.Fprintf(w, "}\n\n")
}
@ -1618,10 +1669,24 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso
return nil
}
func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) {
// If the function starts with New or Get, it will conflict; so rename them.
name := pkg.functionNames[f]
func (pkg *pkgContext) genFunctionCodeFile(f *schema.Function) string {
importsAndAliases := map[string]string{}
pkg.getImports(f, importsAndAliases)
buffer := &bytes.Buffer{}
var imports []string
if f.NeedsOutputVersion() {
imports = []string{"context", "reflect"}
}
pkg.genHeader(buffer, imports, importsAndAliases)
pkg.genFunction(buffer, f)
pkg.genFunctionOutputVersion(buffer, f)
return buffer.String()
}
func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) {
name := pkg.functionName(f)
printCommentWithDeprecationMessage(w, f.Comment, f.DeprecationMessage, false)
// Now, emit the function signature.
@ -1671,20 +1736,91 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) {
// If there are argument and/or return types, emit them.
if f.Inputs != nil {
fmt.Fprintf(w, "\n")
pkg.genPlainType(w, fmt.Sprintf("%sArgs", name), f.Inputs.Comment, "", f.Inputs.Properties)
pkg.genPlainType(w, pkg.functionArgsTypeName(f), f.Inputs.Comment, "", f.Inputs.Properties)
}
if f.Outputs != nil {
fmt.Fprintf(w, "\n")
pkg.genPlainType(w, fmt.Sprintf("%sResult", name), f.Outputs.Comment, "", f.Outputs.Properties)
pkg.genPlainType(w, pkg.functionResultTypeName(f), f.Outputs.Comment, "", f.Outputs.Properties)
}
}
func (pkg *pkgContext) functionName(f *schema.Function) string {
// If the function starts with New or Get, it will conflict; so rename them.
name, hasName := pkg.functionNames[f]
if !hasName {
panic(fmt.Sprintf("No function name found for %v", f))
}
return name
}
func (pkg *pkgContext) functionArgsTypeName(f *schema.Function) string {
name := pkg.functionName(f)
return fmt.Sprintf("%sArgs", name)
}
func (pkg *pkgContext) functionResultTypeName(f *schema.Function) string {
name := pkg.functionName(f)
return fmt.Sprintf("%sResult", name)
}
func (pkg *pkgContext) genFunctionOutputVersion(w io.Writer, f *schema.Function) {
if !f.NeedsOutputVersion() {
return
}
originalName := pkg.functionName(f)
name := originalName + "Output"
originalResultTypeName := pkg.functionResultTypeName(f)
resultTypeName := originalResultTypeName + "Output"
code := `
func ${fn}Output(ctx *pulumi.Context, args ${fn}OutputArgs, opts ...pulumi.InvokeOption) ${outputType} {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (${fn}Result, error) {
args := v.(${fn}Args)
r, err := ${fn}(ctx, &args, opts...)
return *r, err
}).(${outputType})
}
`
code = strings.ReplaceAll(code, "${fn}", originalName)
code = strings.ReplaceAll(code, "${outputType}", resultTypeName)
fmt.Fprintf(w, code)
pkg.genInputArgsStruct(w, name+"Args", f.Inputs.InputShape)
genInputImplementationWithArgs(w, genInputImplementationArgs{
name: name + "Args",
receiverType: name + "Args",
elementType: pkg.functionArgsTypeName(f),
})
pkg.genOutputTypes(w, genOutputTypesArgs{
t: f.Outputs,
name: originalResultTypeName,
})
// Assuming the file represented by `w` only has one function,
// generate an `init()` for Output type init.
initCode := `
func init() {
pulumi.RegisterOutputType(${outputType}{})
}
`
initCode = strings.ReplaceAll(initCode, "${outputType}", resultTypeName)
fmt.Fprintf(w, initCode)
}
func (pkg *pkgContext) genType(w io.Writer, obj *schema.ObjectType) {
contract.Assert(!obj.IsInputShape())
pkg.genPlainType(w, pkg.tokenToType(obj.Token), obj.Comment, "", obj.Properties)
pkg.genInputTypes(w, obj.InputShape, pkg.detailsForType(obj))
pkg.genOutputTypes(w, obj, pkg.detailsForType(obj))
pkg.genOutputTypes(w, genOutputTypesArgs{t: obj})
}
func (pkg *pkgContext) addSuffixesToName(typ schema.Type, name string) []string {
@ -2377,6 +2513,19 @@ func generatePackageContextMap(tool string, pkg *schema.Package, goInfo GoPackag
scanResource(r)
}
// For fnApply function versions, we need to register any
// input or output property type metadata, in case they have
// types used in array or pointer element positions.
for _, f := range pkg.Functions {
parentOptional := false
if f.Inputs != nil {
populateDetailsForPropertyTypes(seenMap, f.Inputs.Properties, parentOptional)
}
if f.Outputs != nil {
populateDetailsForPropertyTypes(seenMap, f.Outputs.Properties, parentOptional)
}
}
for _, f := range pkg.Functions {
if f.IsMethod {
continue
@ -2554,15 +2703,9 @@ func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error
// Functions
for _, f := range pkg.functions {
importsAndAliases := map[string]string{}
pkg.getImports(f, importsAndAliases)
buffer := &bytes.Buffer{}
pkg.genHeader(buffer, nil, importsAndAliases)
pkg.genFunction(buffer, f)
setFile(path.Join(mod, camel(tokenToName(f.Token))+".go"), buffer.String())
fileName := path.Join(mod, camel(tokenToName(f.Token))+".go")
code := pkg.genFunctionCodeFile(f)
setFile(fileName, code)
}
knownTypes := make(map[schema.Type]struct{}, len(pkg.typeDetails))

View file

@ -1,6 +1,14 @@
package gen
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os/exec"
"path/filepath"
"sort"
"strings"
"sync"
"testing"
@ -250,3 +258,88 @@ func TestEnumUsage(t *testing.T) {
}, pulumi.WithMocks("project", "stack", mocks(1))))
})
}
func TestGenerateOutputFuncs(t *testing.T) {
testDir := filepath.Join("..", "internal", "test", "testdata", "output-funcs")
files, err := ioutil.ReadDir(testDir)
if err != nil {
assert.NoError(t, err)
return
}
var examples []string
for _, f := range files {
name := f.Name()
if strings.HasSuffix(name, ".json") {
examples = append(examples, strings.TrimSuffix(name, ".json"))
}
}
sort.Slice(examples, func(i, j int) bool { return examples[i] < examples[j] })
gen := func(reader io.Reader, writer io.Writer) error {
var pkgSpec schema.PackageSpec
err := json.NewDecoder(reader).Decode(&pkgSpec)
if err != nil {
return err
}
pkg, err := schema.ImportSpec(pkgSpec, nil)
if err != nil {
return err
}
tool := "tool"
var goPkgInfo GoPackageInfo
if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
goPkgInfo = goInfo
}
pkgContexts := generatePackageContextMap(tool, pkg, goPkgInfo)
var pkgContext *pkgContext
for _, c := range pkgContexts {
if len(c.functionNames) == 1 {
pkgContext = c
}
}
if pkgContext == nil {
return fmt.Errorf("Cannot find a package with 1 function in generatePackageContextMap result")
}
fun := pkg.Functions[0]
_, err = writer.Write([]byte(pkgContext.genFunctionCodeFile(fun)))
return err
}
for _, ex := range examples {
t.Run(ex, func(t *testing.T) {
inputFile := filepath.Join(testDir, fmt.Sprintf("%s.json", ex))
expectedOutputFile := filepath.Join(testDir, "go", fmt.Sprintf("%s.go", ex))
test.ValidateFileTransformer(t, inputFile, expectedOutputFile, gen)
})
}
goDir := filepath.Join("..", "internal", "test", "testdata", "output-funcs", "go")
t.Run("compileGeneratedCode", func(t *testing.T) {
t.Logf("cd %s && go mod tidy", goDir)
cmd := exec.Command("go", "mod", "tidy")
cmd.Dir = goDir
assert.NoError(t, cmd.Run())
t.Logf("cd %s && go build .", goDir)
cmd = exec.Command("go", "build", ".")
cmd.Dir = goDir
assert.NoError(t, cmd.Run())
})
t.Run("testGeneratedCode", func(t *testing.T) {
t.Logf("cd %s && go test .", goDir)
cmd := exec.Command("go", "test", ".")
cmd.Dir = goDir
assert.NoError(t, cmd.Run())
})
}

View file

@ -15,7 +15,9 @@
package test
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"os"
"path/filepath"
@ -185,3 +187,47 @@ func CheckAllFilesGenerated(t *testing.T, actual, expected map[string][]byte) {
assert.Fail(t, "No content generated for expected file %s", s)
}
}
// Validates a transformer on a single file.
func ValidateFileTransformer(
t *testing.T,
inputFile string,
expectedOutputFile string,
transformer func(reader io.Reader, writer io.Writer) error) {
reader, err := os.Open(inputFile)
if err != nil {
t.Error(err)
return
}
var buf bytes.Buffer
err = transformer(reader, &buf)
if err != nil {
t.Error(err)
return
}
actualBytes := buf.Bytes()
if os.Getenv("PULUMI_ACCEPT") != "" {
err := ioutil.WriteFile(expectedOutputFile, actualBytes, 0600)
if err != nil {
t.Error(err)
return
}
}
actual := map[string][]byte{expectedOutputFile: actualBytes}
expectedBytes, err := ioutil.ReadFile(expectedOutputFile)
if err != nil {
t.Error(err)
return
}
expected := map[string][]byte{expectedOutputFile: expectedBytes}
ValidateFileEquality(t, actual, expected)
}

View file

@ -4,6 +4,9 @@
package example
import (
"context"
"reflect"
"github.com/pulumi/pulumi-random/sdk/v2/go/random"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
@ -24,3 +27,42 @@ type ArgFunctionArgs struct {
type ArgFunctionResult struct {
Age *int `pulumi:"age"`
}
func ArgFunctionOutput(ctx *pulumi.Context, args ArgFunctionOutputArgs, opts ...pulumi.InvokeOption) ArgFunctionResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (ArgFunctionResult, error) {
args := v.(ArgFunctionArgs)
r, err := ArgFunction(ctx, &args, opts...)
return *r, err
}).(ArgFunctionResultOutput)
}
type ArgFunctionOutputArgs struct {
Name random.RandomPetInput `pulumi:"name"`
}
func (ArgFunctionOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionArgs)(nil)).Elem()
}
type ArgFunctionResultOutput struct{ *pulumi.OutputState }
func (ArgFunctionResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionResult)(nil)).Elem()
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutput() ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutputWithContext(ctx context.Context) ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) Age() pulumi.IntPtrOutput {
return o.ApplyT(func(v ArgFunctionResult) *int { return v.Age }).(pulumi.IntPtrOutput)
}
func init() {
pulumi.RegisterOutputType(ArgFunctionResultOutput{})
}

View file

@ -0,0 +1,29 @@
{
"functions": {
"madeup-package:codegentest:funcWithAllOptionalInputs": {
"description": "Check codegen of functions with all optional inputs.",
"inputs": {
"type": "object",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
}
}
},
"outputs": {
"properties": {
"r": {
"type": "string"
}
},
"type": "object",
"required": [
"r"
]
}
}
}
}

View file

@ -0,0 +1,16 @@
{
"functions": {
"madeup-package:codegentest:funcWithConstInput": {
"description": "Codegen demo with const inputs",
"inputs": {
"type": "object",
"properties": {
"plainInput": {
"type": "string",
"const": "fixed"
}
}
}
}
}
}

View file

@ -0,0 +1,33 @@
{
"functions": {
"madeup-package:codegentest:funcWithDefaultValue": {
"description": "Check codegen of functions with default values.",
"inputs": {
"type": "object",
"required": [
"a"
],
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string",
"default": "b-default"
}
}
},
"outputs": {
"properties": {
"r": {
"type": "string"
}
},
"type": "object",
"required": [
"r"
]
}
}
}
}

View file

@ -0,0 +1,32 @@
{
"functions": {
"madeup-package:codegentest:funcWithDictParam": {
"description": "Check codegen of functions with a Dict<str,str> parameter.",
"inputs": {
"type": "object",
"properties": {
"a": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"b": {
"type": "string"
}
}
},
"outputs": {
"properties": {
"r": {
"type": "string"
}
},
"type": "object",
"required": [
"r"
]
}
}
}
}

View file

@ -0,0 +1,32 @@
{
"functions": {
"madeup-package:codegentest:funcWithListParam": {
"description": "Check codegen of functions with a List parameter.",
"inputs": {
"type": "object",
"properties": {
"a": {
"type": "array",
"items": {
"type": "string"
}
},
"b": {
"type": "string"
}
}
},
"outputs": {
"properties": {
"r": {
"type": "string"
}
},
"type": "object",
"required": [
"r"
]
}
}
}
}

View file

@ -0,0 +1,35 @@
{
"functions": {
"azure-native:codegentest:getClientConfig": {
"description": "Use this function to access the current configuration of the native Azure provider.",
"outputs": {
"description": "Configuration values returned by getClientConfig.",
"properties": {
"clientId": {
"type": "string",
"description": "Azure Client ID (Application Object ID)."
},
"objectId": {
"type": "string",
"description": "Azure Object ID of the current user or service principal."
},
"subscriptionId": {
"type": "string",
"description": "Azure Subscription ID"
},
"tenantId": {
"type": "string",
"description": "Azure Tenant ID"
}
},
"type": "object",
"required": [
"clientId",
"objectId",
"subscriptionId",
"tenantId"
]
}
}
}
}

View file

@ -0,0 +1,348 @@
{
"functions": {
"azure-native:codegentest:getIntegrationRuntimeObjectMetadatum": {
"description": "A list of SSIS object metadata.\nAPI Version: 2018-06-01.",
"inputs": {
"properties": {
"factoryName": {
"type": "string",
"description": "The factory name."
},
"integrationRuntimeName": {
"type": "string",
"description": "The integration runtime name."
},
"metadataPath": {
"type": "string",
"description": "Metadata path."
},
"resourceGroupName": {
"type": "string",
"description": "The resource group name."
}
},
"type": "object",
"required": [
"factoryName",
"integrationRuntimeName",
"resourceGroupName"
]
},
"outputs": {
"description": "A list of SSIS object metadata.",
"properties": {
"nextLink": {
"type": "string",
"description": "The link to the next page of results, if any remaining results exist."
},
"value": {
"type": "array",
"items": {
"oneOf": [
{
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisEnvironmentResponse"
},
{
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisFolderResponse"
},
{
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisPackageResponse"
},
{
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisProjectResponse"
}
],
"discriminator": {
"propertyName": "type",
"mapping": {
"Environment": "#/types/azure-native:codegentest:SsisEnvironmentResponse",
"Folder": "#/types/azure-native:codegentest:SsisFolderResponse",
"Package": "#/types/azure-native:codegentest:SsisPackageResponse",
"Project": "#/types/azure-native:codegentest:SsisProjectResponse"
}
}
},
"description": "List of SSIS object metadata."
}
},
"type": "object"
}
}
},
"types": {
"azure-native:codegentest:SsisEnvironmentResponse": {
"description": "Ssis environment.",
"properties": {
"description": {
"type": "string",
"description": "Metadata description."
},
"folderId": {
"type": "number",
"description": "Folder id which contains environment."
},
"id": {
"type": "number",
"description": "Metadata id."
},
"name": {
"type": "string",
"description": "Metadata name."
},
"type": {
"type": "string",
"description": "The type of SSIS object metadata.\nExpected value is 'Environment'.",
"const": "Environment"
},
"variables": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisVariableResponse"
},
"description": "Variable in environment"
}
},
"type": "object",
"required": [
"type"
]
},
"azure-native:codegentest:SsisFolderResponse": {
"description": "Ssis folder.",
"properties": {
"description": {
"type": "string",
"description": "Metadata description."
},
"id": {
"type": "number",
"description": "Metadata id."
},
"name": {
"type": "string",
"description": "Metadata name."
},
"type": {
"type": "string",
"description": "The type of SSIS object metadata.\nExpected value is 'Folder'.",
"const": "Folder"
}
},
"type": "object",
"required": [
"type"
]
},
"azure-native:codegentest:SsisPackageResponse": {
"description": "Ssis Package.",
"properties": {
"description": {
"type": "string",
"description": "Metadata description."
},
"folderId": {
"type": "number",
"description": "Folder id which contains package."
},
"id": {
"type": "number",
"description": "Metadata id."
},
"name": {
"type": "string",
"description": "Metadata name."
},
"parameters": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisParameterResponse"
},
"description": "Parameters in package"
},
"projectId": {
"type": "number",
"description": "Project id which contains package."
},
"projectVersion": {
"type": "number",
"description": "Project version which contains package."
},
"type": {
"type": "string",
"description": "The type of SSIS object metadata.\nExpected value is 'Package'.",
"const": "Package"
}
},
"type": "object",
"required": [
"type"
]
},
"azure-native:codegentest:SsisProjectResponse": {
"description": "Ssis project.",
"properties": {
"description": {
"type": "string",
"description": "Metadata description."
},
"environmentRefs": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisEnvironmentReferenceResponse"
},
"description": "Environment reference in project"
},
"folderId": {
"type": "number",
"description": "Folder id which contains project."
},
"id": {
"type": "number",
"description": "Metadata id."
},
"name": {
"type": "string",
"description": "Metadata name."
},
"parameters": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/types/azure-native:codegentest:SsisParameterResponse"
},
"description": "Parameters in project"
},
"type": {
"type": "string",
"description": "The type of SSIS object metadata.\nExpected value is 'Project'.",
"const": "Project"
},
"version": {
"type": "number",
"description": "Project version."
}
},
"type": "object",
"required": [
"type"
]
},
"azure-native:codegentest:SsisEnvironmentReferenceResponse": {
"description": "Ssis environment reference.",
"properties": {
"environmentFolderName": {
"type": "string",
"description": "Environment folder name."
},
"environmentName": {
"type": "string",
"description": "Environment name."
},
"id": {
"type": "number",
"description": "Environment reference id."
},
"referenceType": {
"type": "string",
"description": "Reference type"
}
},
"type": "object"
},
"azure-native:codegentest:SsisParameterResponse": {
"description": "Ssis parameter.",
"properties": {
"dataType": {
"type": "string",
"description": "Parameter type."
},
"defaultValue": {
"type": "string",
"description": "Default value of parameter."
},
"description": {
"type": "string",
"description": "Parameter description."
},
"designDefaultValue": {
"type": "string",
"description": "Design default value of parameter."
},
"id": {
"type": "number",
"description": "Parameter id."
},
"name": {
"type": "string",
"description": "Parameter name."
},
"required": {
"type": "boolean",
"description": "Whether parameter is required."
},
"sensitive": {
"type": "boolean",
"description": "Whether parameter is sensitive."
},
"sensitiveDefaultValue": {
"type": "string",
"description": "Default sensitive value of parameter."
},
"valueSet": {
"type": "boolean",
"description": "Parameter value set."
},
"valueType": {
"type": "string",
"description": "Parameter value type."
},
"variable": {
"type": "string",
"description": "Parameter reference variable."
}
},
"type": "object"
},
"azure-native:codegentest:SsisVariableResponse": {
"description": "Ssis variable.",
"properties": {
"dataType": {
"type": "string",
"description": "Variable type."
},
"description": {
"type": "string",
"description": "Variable description."
},
"id": {
"type": "number",
"description": "Variable id."
},
"name": {
"type": "string",
"description": "Variable name."
},
"sensitive": {
"type": "boolean",
"description": "Whether variable is sensitive."
},
"sensitiveValue": {
"type": "string",
"description": "Variable sensitive value."
},
"value": {
"type": "string",
"description": "Variable value."
}
},
"type": "object"
}
}
}

View file

@ -0,0 +1,255 @@
// Copyright 2016-2021, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package codegentest
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
type mocks int
// Create the mock.
func (mocks) NewResource(args pulumi.MockResourceArgs) (string, resource.PropertyMap, error) {
panic("NewResource not supported")
}
func (mocks) Call(args pulumi.MockCallArgs) (resource.PropertyMap, error) {
if args.Token == "azure-native:codegentest:listStorageAccountKeys" {
targs := ListStorageAccountKeysArgs{}
for k, v := range args.Args {
switch k {
case "accountName":
targs.AccountName = v.V.(string)
case "expand":
expand := v.V.(string)
targs.Expand = &expand
case "resourceGroupName":
targs.ResourceGroupName = v.V.(string)
}
}
var expand string
if targs.Expand != nil {
expand = *targs.Expand
}
inputs := []StorageAccountKeyResponse{
{
KeyName: "key",
Permissions: "permissions",
Value: fmt.Sprintf("accountName=%v, resourceGroupName=%v, expand=%v",
targs.AccountName,
targs.ResourceGroupName,
expand),
},
}
result := ListStorageAccountKeysResult{
Keys: inputs,
}
outputs := map[string]interface{}{
"keys": result.Keys,
}
return resource.NewPropertyMapFromMap(outputs), nil
}
if args.Token == "madeup-package:codegentest:funcWithDefaultValue" ||
args.Token == "madeup-package:codegentest:funcWithAllOptionalInputs" ||
args.Token == "madeup-package:codegentest:funcWithListParam" ||
args.Token == "madeup-package:codegentest:funcWithDictParam" {
result := FuncWithDefaultValueResult{
R: fmt.Sprintf("%v", args.Args),
}
outputs := map[string]interface{}{
"r": result.R,
}
return resource.NewPropertyMapFromMap(outputs), nil
}
if args.Token == "azure-native:codegentest:getIntegrationRuntimeObjectMetadatum" {
targs := GetIntegrationRuntimeObjectMetadatumArgs{}
for k, v := range args.Args {
switch k {
case "factoryName":
targs.FactoryName = v.V.(string)
case "integrationRuntimeName":
targs.IntegrationRuntimeName = v.V.(string)
case "metadataPath":
metadataPath := v.V.(string)
targs.MetadataPath = &metadataPath
case "resourceGroupName":
targs.ResourceGroupName = v.V.(string)
}
}
nextLink := "my-next-link"
result := GetIntegrationRuntimeObjectMetadatumResult{
NextLink: &nextLink,
Value: []interface{}{targs},
}
outputs := map[string]interface{}{
"nextLink": result.NextLink,
"value": []interface{}{fmt.Sprintf("factoryName=%s", targs.FactoryName)},
}
return resource.NewPropertyMapFromMap(outputs), nil
}
panic(fmt.Errorf("Unknown token: %s", args.Token))
}
func TestListStorageAccountKeysOutput(t *testing.T) {
pulumiTest(t, func(ctx *pulumi.Context) error {
output := ListStorageAccountKeysOutput(ctx, ListStorageAccountKeysOutputArgs{
AccountName: pulumi.String("my-account-name"),
ResourceGroupName: pulumi.String("my-resource-group-name"),
})
keys := waitOut(t, output.Keys()).([]StorageAccountKeyResponse)
assert.Equal(t, 1, len(keys))
assert.Equal(t, "key", keys[0].KeyName)
assert.Equal(t, "permissions", keys[0].Permissions)
assert.Equal(t, "accountName=my-account-name, resourceGroupName=my-resource-group-name, expand=",
keys[0].Value)
output = ListStorageAccountKeysOutput(ctx, ListStorageAccountKeysOutputArgs{
AccountName: pulumi.String("my-account-name"),
ResourceGroupName: pulumi.String("my-resource-group-name"),
Expand: pulumi.String("my-expand"),
})
keys = waitOut(t, output.Keys()).([]StorageAccountKeyResponse)
assert.Equal(t, 1, len(keys))
assert.Equal(t, "key", keys[0].KeyName)
assert.Equal(t, "permissions", keys[0].Permissions)
assert.Equal(t, "accountName=my-account-name, resourceGroupName=my-resource-group-name, expand=my-expand",
keys[0].Value)
return nil
})
}
// TODO[pulumi/pulumi#7811]: it seems that default values are not
// supported by Go codegen yet, hence we do not observe "B" populated
// to default at all here.
func TestFuncWithDefaultValueOutput(t *testing.T) {
pulumiTest(t, func(ctx *pulumi.Context) error {
output := FuncWithDefaultValueOutput(ctx, FuncWithDefaultValueOutputArgs{
A: pulumi.String("my-a"),
})
r := waitOut(t, output.R())
assert.Equal(t, "map[a:{my-a}]", r)
return nil
})
}
func TestFuncWithAllOptionalInputsOutput(t *testing.T) {
pulumiTest(t, func(ctx *pulumi.Context) error {
output := FuncWithAllOptionalInputsOutput(ctx, FuncWithAllOptionalInputsOutputArgs{
A: pulumi.String("my-a"),
})
r := waitOut(t, output.R())
assert.Equal(t, "map[a:{my-a}]", r)
return nil
})
}
func TestFuncWithListParamOutput(t *testing.T) {
pulumiTest(t, func(ctx *pulumi.Context) error {
output := FuncWithListParamOutput(ctx, FuncWithListParamOutputArgs{
A: pulumi.StringArray{
pulumi.String("my-a1"),
pulumi.String("my-a2"),
pulumi.String("my-a3"),
},
})
r := waitOut(t, output.R())
assert.Equal(t, "map[a:{[{my-a1} {my-a2} {my-a3}]}]", r)
return nil
})
}
func TestFuncWithDictParamOutput(t *testing.T) {
pulumiTest(t, func(ctx *pulumi.Context) error {
output := FuncWithDictParamOutput(ctx, FuncWithDictParamOutputArgs{
A: pulumi.StringMap{
"one": pulumi.String("1"),
"two": pulumi.String("2"),
},
})
r := waitOut(t, output.R())
assert.Equal(t, "map[a:{map[one:{1} two:{2}]}]", r)
return nil
})
}
func TestGetIntegrationRuntimeObjectMetadatumOutput(t *testing.T) {
pulumiTest(t, func(ctx *pulumi.Context) error {
output := GetIntegrationRuntimeObjectMetadatumOutput(ctx, GetIntegrationRuntimeObjectMetadatumOutputArgs{
FactoryName: pulumi.String("my-factory-name"),
IntegrationRuntimeName: pulumi.String("my-integration-runtime-name"),
MetadataPath: pulumi.String("my-metadata-path"),
ResourceGroupName: pulumi.String("my-resource-group-name"),
})
nextLink := waitOut(t, output.NextLink())
assert.Equal(t, "my-next-link", *(nextLink.(*string)))
value := waitOut(t, output.Value())
assert.Equal(t, []interface{}{"factoryName=my-factory-name"}, value)
return nil
})
}
func pulumiTest(t *testing.T, testBody func(ctx *pulumi.Context) error) {
err := pulumi.RunErr(testBody, pulumi.WithMocks("project", "stack", mocks(0)))
assert.NoError(t, err)
}
func waitOut(t *testing.T, output pulumi.Output) interface{} {
result, err := waitOutput(output, 1*time.Second)
if err != nil {
t.Error(err)
return nil
}
return result
}
func waitOutput(output pulumi.Output, timeout time.Duration) (interface{}, error) {
c := make(chan interface{}, 2)
output.ApplyT(func(v interface{}) interface{} {
c <- v
return v
})
var timeoutMarker *int = new(int)
go func() {
time.Sleep(timeout)
c <- timeoutMarker
}()
result := <-c
if result == timeoutMarker {
return nil, fmt.Errorf("Timed out waiting for pulumi.Output after %v", timeout)
} else {
return result, nil
}
}

View file

@ -0,0 +1,74 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// Check codegen of functions with all optional inputs.
func FuncWithAllOptionalInputs(ctx *pulumi.Context, args *FuncWithAllOptionalInputsArgs, opts ...pulumi.InvokeOption) (*FuncWithAllOptionalInputsResult, error) {
var rv FuncWithAllOptionalInputsResult
err := ctx.Invoke("madeup-package:codegentest:funcWithAllOptionalInputs", args, &rv, opts...)
if err != nil {
return nil, err
}
return &rv, nil
}
type FuncWithAllOptionalInputsArgs struct {
A *string `pulumi:"a"`
B *string `pulumi:"b"`
}
type FuncWithAllOptionalInputsResult struct {
R string `pulumi:"r"`
}
func FuncWithAllOptionalInputsOutput(ctx *pulumi.Context, args FuncWithAllOptionalInputsOutputArgs, opts ...pulumi.InvokeOption) FuncWithAllOptionalInputsResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (FuncWithAllOptionalInputsResult, error) {
args := v.(FuncWithAllOptionalInputsArgs)
r, err := FuncWithAllOptionalInputs(ctx, &args, opts...)
return *r, err
}).(FuncWithAllOptionalInputsResultOutput)
}
type FuncWithAllOptionalInputsOutputArgs struct {
A pulumi.StringPtrInput `pulumi:"a"`
B pulumi.StringPtrInput `pulumi:"b"`
}
func (FuncWithAllOptionalInputsOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithAllOptionalInputsArgs)(nil)).Elem()
}
type FuncWithAllOptionalInputsResultOutput struct { *pulumi.OutputState }
func (FuncWithAllOptionalInputsResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithAllOptionalInputsResult)(nil)).Elem()
}
func (o FuncWithAllOptionalInputsResultOutput) ToFuncWithAllOptionalInputsResultOutput() FuncWithAllOptionalInputsResultOutput {
return o
}
func (o FuncWithAllOptionalInputsResultOutput) ToFuncWithAllOptionalInputsResultOutputWithContext(ctx context.Context) FuncWithAllOptionalInputsResultOutput {
return o
}
func (o FuncWithAllOptionalInputsResultOutput) R() pulumi.StringOutput {
return o.ApplyT(func (v FuncWithAllOptionalInputsResult) string { return v.R }).(pulumi.StringOutput)
}
func init() {
pulumi.RegisterOutputType(FuncWithAllOptionalInputsResultOutput{})
}

View file

@ -0,0 +1,20 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// Codegen demo with const inputs
func FuncWithConstInput(ctx *pulumi.Context, args *FuncWithConstInputArgs, opts ...pulumi.InvokeOption) error {
var rv struct{}
err := ctx.Invoke("madeup-package:codegentest:funcWithConstInput", args, &rv, opts...)
return err
}
type FuncWithConstInputArgs struct {
PlainInput *string `pulumi:"plainInput"`
}

View file

@ -0,0 +1,74 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// Check codegen of functions with default values.
func FuncWithDefaultValue(ctx *pulumi.Context, args *FuncWithDefaultValueArgs, opts ...pulumi.InvokeOption) (*FuncWithDefaultValueResult, error) {
var rv FuncWithDefaultValueResult
err := ctx.Invoke("madeup-package:codegentest:funcWithDefaultValue", args, &rv, opts...)
if err != nil {
return nil, err
}
return &rv, nil
}
type FuncWithDefaultValueArgs struct {
A string `pulumi:"a"`
B *string `pulumi:"b"`
}
type FuncWithDefaultValueResult struct {
R string `pulumi:"r"`
}
func FuncWithDefaultValueOutput(ctx *pulumi.Context, args FuncWithDefaultValueOutputArgs, opts ...pulumi.InvokeOption) FuncWithDefaultValueResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (FuncWithDefaultValueResult, error) {
args := v.(FuncWithDefaultValueArgs)
r, err := FuncWithDefaultValue(ctx, &args, opts...)
return *r, err
}).(FuncWithDefaultValueResultOutput)
}
type FuncWithDefaultValueOutputArgs struct {
A pulumi.StringInput `pulumi:"a"`
B pulumi.StringPtrInput `pulumi:"b"`
}
func (FuncWithDefaultValueOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithDefaultValueArgs)(nil)).Elem()
}
type FuncWithDefaultValueResultOutput struct { *pulumi.OutputState }
func (FuncWithDefaultValueResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithDefaultValueResult)(nil)).Elem()
}
func (o FuncWithDefaultValueResultOutput) ToFuncWithDefaultValueResultOutput() FuncWithDefaultValueResultOutput {
return o
}
func (o FuncWithDefaultValueResultOutput) ToFuncWithDefaultValueResultOutputWithContext(ctx context.Context) FuncWithDefaultValueResultOutput {
return o
}
func (o FuncWithDefaultValueResultOutput) R() pulumi.StringOutput {
return o.ApplyT(func (v FuncWithDefaultValueResult) string { return v.R }).(pulumi.StringOutput)
}
func init() {
pulumi.RegisterOutputType(FuncWithDefaultValueResultOutput{})
}

View file

@ -0,0 +1,74 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// Check codegen of functions with a Dict<str,str> parameter.
func FuncWithDictParam(ctx *pulumi.Context, args *FuncWithDictParamArgs, opts ...pulumi.InvokeOption) (*FuncWithDictParamResult, error) {
var rv FuncWithDictParamResult
err := ctx.Invoke("madeup-package:codegentest:funcWithDictParam", args, &rv, opts...)
if err != nil {
return nil, err
}
return &rv, nil
}
type FuncWithDictParamArgs struct {
A map[string]string `pulumi:"a"`
B *string `pulumi:"b"`
}
type FuncWithDictParamResult struct {
R string `pulumi:"r"`
}
func FuncWithDictParamOutput(ctx *pulumi.Context, args FuncWithDictParamOutputArgs, opts ...pulumi.InvokeOption) FuncWithDictParamResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (FuncWithDictParamResult, error) {
args := v.(FuncWithDictParamArgs)
r, err := FuncWithDictParam(ctx, &args, opts...)
return *r, err
}).(FuncWithDictParamResultOutput)
}
type FuncWithDictParamOutputArgs struct {
A pulumi.StringMapInput `pulumi:"a"`
B pulumi.StringPtrInput `pulumi:"b"`
}
func (FuncWithDictParamOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithDictParamArgs)(nil)).Elem()
}
type FuncWithDictParamResultOutput struct { *pulumi.OutputState }
func (FuncWithDictParamResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithDictParamResult)(nil)).Elem()
}
func (o FuncWithDictParamResultOutput) ToFuncWithDictParamResultOutput() FuncWithDictParamResultOutput {
return o
}
func (o FuncWithDictParamResultOutput) ToFuncWithDictParamResultOutputWithContext(ctx context.Context) FuncWithDictParamResultOutput {
return o
}
func (o FuncWithDictParamResultOutput) R() pulumi.StringOutput {
return o.ApplyT(func (v FuncWithDictParamResult) string { return v.R }).(pulumi.StringOutput)
}
func init() {
pulumi.RegisterOutputType(FuncWithDictParamResultOutput{})
}

View file

@ -0,0 +1,74 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// Check codegen of functions with a List parameter.
func FuncWithListParam(ctx *pulumi.Context, args *FuncWithListParamArgs, opts ...pulumi.InvokeOption) (*FuncWithListParamResult, error) {
var rv FuncWithListParamResult
err := ctx.Invoke("madeup-package:codegentest:funcWithListParam", args, &rv, opts...)
if err != nil {
return nil, err
}
return &rv, nil
}
type FuncWithListParamArgs struct {
A []string `pulumi:"a"`
B *string `pulumi:"b"`
}
type FuncWithListParamResult struct {
R string `pulumi:"r"`
}
func FuncWithListParamOutput(ctx *pulumi.Context, args FuncWithListParamOutputArgs, opts ...pulumi.InvokeOption) FuncWithListParamResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (FuncWithListParamResult, error) {
args := v.(FuncWithListParamArgs)
r, err := FuncWithListParam(ctx, &args, opts...)
return *r, err
}).(FuncWithListParamResultOutput)
}
type FuncWithListParamOutputArgs struct {
A pulumi.StringArrayInput `pulumi:"a"`
B pulumi.StringPtrInput `pulumi:"b"`
}
func (FuncWithListParamOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithListParamArgs)(nil)).Elem()
}
type FuncWithListParamResultOutput struct { *pulumi.OutputState }
func (FuncWithListParamResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*FuncWithListParamResult)(nil)).Elem()
}
func (o FuncWithListParamResultOutput) ToFuncWithListParamResultOutput() FuncWithListParamResultOutput {
return o
}
func (o FuncWithListParamResultOutput) ToFuncWithListParamResultOutputWithContext(ctx context.Context) FuncWithListParamResultOutput {
return o
}
func (o FuncWithListParamResultOutput) R() pulumi.StringOutput {
return o.ApplyT(func (v FuncWithListParamResult) string { return v.R }).(pulumi.StringOutput)
}
func init() {
pulumi.RegisterOutputType(FuncWithListParamResultOutput{})
}

View file

@ -0,0 +1,31 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// Use this function to access the current configuration of the native Azure provider.
func GetClientConfig(ctx *pulumi.Context, opts ...pulumi.InvokeOption) (*GetClientConfigResult, error) {
var rv GetClientConfigResult
err := ctx.Invoke("azure-native:codegentest:getClientConfig", nil, &rv, opts...)
if err != nil {
return nil, err
}
return &rv, nil
}
// Configuration values returned by getClientConfig.
type GetClientConfigResult struct {
// Azure Client ID (Application Object ID).
ClientId string `pulumi:"clientId"`
// Azure Object ID of the current user or service principal.
ObjectId string `pulumi:"objectId"`
// Azure Subscription ID
SubscriptionId string `pulumi:"subscriptionId"`
// Azure Tenant ID
TenantId string `pulumi:"tenantId"`
}

View file

@ -0,0 +1,98 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// A list of SSIS object metadata.
// API Version: 2018-06-01.
func GetIntegrationRuntimeObjectMetadatum(ctx *pulumi.Context, args *GetIntegrationRuntimeObjectMetadatumArgs, opts ...pulumi.InvokeOption) (*GetIntegrationRuntimeObjectMetadatumResult, error) {
var rv GetIntegrationRuntimeObjectMetadatumResult
err := ctx.Invoke("azure-native:codegentest:getIntegrationRuntimeObjectMetadatum", args, &rv, opts...)
if err != nil {
return nil, err
}
return &rv, nil
}
type GetIntegrationRuntimeObjectMetadatumArgs struct {
// The factory name.
FactoryName string `pulumi:"factoryName"`
// The integration runtime name.
IntegrationRuntimeName string `pulumi:"integrationRuntimeName"`
// Metadata path.
MetadataPath *string `pulumi:"metadataPath"`
// The resource group name.
ResourceGroupName string `pulumi:"resourceGroupName"`
}
// A list of SSIS object metadata.
type GetIntegrationRuntimeObjectMetadatumResult struct {
// The link to the next page of results, if any remaining results exist.
NextLink *string `pulumi:"nextLink"`
// List of SSIS object metadata.
Value []interface{} `pulumi:"value"`
}
func GetIntegrationRuntimeObjectMetadatumOutput(ctx *pulumi.Context, args GetIntegrationRuntimeObjectMetadatumOutputArgs, opts ...pulumi.InvokeOption) GetIntegrationRuntimeObjectMetadatumResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (GetIntegrationRuntimeObjectMetadatumResult, error) {
args := v.(GetIntegrationRuntimeObjectMetadatumArgs)
r, err := GetIntegrationRuntimeObjectMetadatum(ctx, &args, opts...)
return *r, err
}).(GetIntegrationRuntimeObjectMetadatumResultOutput)
}
type GetIntegrationRuntimeObjectMetadatumOutputArgs struct {
// The factory name.
FactoryName pulumi.StringInput `pulumi:"factoryName"`
// The integration runtime name.
IntegrationRuntimeName pulumi.StringInput `pulumi:"integrationRuntimeName"`
// Metadata path.
MetadataPath pulumi.StringPtrInput `pulumi:"metadataPath"`
// The resource group name.
ResourceGroupName pulumi.StringInput `pulumi:"resourceGroupName"`
}
func (GetIntegrationRuntimeObjectMetadatumOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*GetIntegrationRuntimeObjectMetadatumArgs)(nil)).Elem()
}
// A list of SSIS object metadata.
type GetIntegrationRuntimeObjectMetadatumResultOutput struct { *pulumi.OutputState }
func (GetIntegrationRuntimeObjectMetadatumResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*GetIntegrationRuntimeObjectMetadatumResult)(nil)).Elem()
}
func (o GetIntegrationRuntimeObjectMetadatumResultOutput) ToGetIntegrationRuntimeObjectMetadatumResultOutput() GetIntegrationRuntimeObjectMetadatumResultOutput {
return o
}
func (o GetIntegrationRuntimeObjectMetadatumResultOutput) ToGetIntegrationRuntimeObjectMetadatumResultOutputWithContext(ctx context.Context) GetIntegrationRuntimeObjectMetadatumResultOutput {
return o
}
// The link to the next page of results, if any remaining results exist.
func (o GetIntegrationRuntimeObjectMetadatumResultOutput) NextLink() pulumi.StringPtrOutput {
return o.ApplyT(func (v GetIntegrationRuntimeObjectMetadatumResult) *string { return v.NextLink }).(pulumi.StringPtrOutput)
}
// List of SSIS object metadata.
func (o GetIntegrationRuntimeObjectMetadatumResultOutput) Value() pulumi.ArrayOutput {
return o.ApplyT(func (v GetIntegrationRuntimeObjectMetadatumResult) []interface{} { return v.Value }).(pulumi.ArrayOutput)
}
func init() {
pulumi.RegisterOutputType(GetIntegrationRuntimeObjectMetadatumResultOutput{})
}

View file

@ -0,0 +1,10 @@
module codegentest
go 1.16
require (
github.com/pulumi/pulumi/sdk/v3 v3.2.1
github.com/stretchr/testify v1.6.1
)
replace github.com/pulumi/pulumi/sdk/v3 => ../../../../../../../sdk

View file

@ -0,0 +1,342 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cheggaaa/pb v1.0.18 h1:G/DgkKaBP0V5lnBg/vx61nVxxAU+VqU5yMzSc0f2PPE=
github.com/cheggaaa/pb v1.0.18/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/djherbis/times v1.2.0 h1:xANXjsC/iBqbO00vkWlYwPWgBgEVU6m6AFYg0Pic+Mc=
github.com/djherbis/times v1.2.0/go.mod h1:CGMZlo255K5r4Yw0b9RRfFQpM2y7uOmxg4jm9HsaVf8=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0=
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6 h1:9VTskZOIRf2vKF3UL8TuWElry5pgUpV1tFSe/e/0m/E=
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 h1:X9dsIWPuuEJlPX//UmRKophhOKCGXc46RVIGuttks68=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7/go.mod h1:UxoP3EypF8JfGEjAII8jx1q8rQyDnX8qdTCs/UQBVIE=
github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM=
github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6 h1:TjszyFsQsyZNHwdVdZ5m7bjmreu0znc2kRYsEml9/Ww=
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509 h1:MI14dOfl3OG6Zd32w3ugsrvcUO810fDZdWakTq39dH4=
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8=
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0 h1:ucqkfpjg9WzSUubAO62csmucvxl4/JeW3F4I4909XkM=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View file

@ -0,0 +1,87 @@
// *** WARNING: this file was generated by tool. ***
// *** Do not edit by hand unless you're certain you know what you are doing! ***
package codegentest
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// The response from the ListKeys operation.
// API Version: 2021-02-01.
func ListStorageAccountKeys(ctx *pulumi.Context, args *ListStorageAccountKeysArgs, opts ...pulumi.InvokeOption) (*ListStorageAccountKeysResult, error) {
var rv ListStorageAccountKeysResult
err := ctx.Invoke("azure-native:codegentest:listStorageAccountKeys", args, &rv, opts...)
if err != nil {
return nil, err
}
return &rv, nil
}
type ListStorageAccountKeysArgs struct {
// The name of the storage account within the specified resource group. Storage account names must be between 3 and 24 characters in length and use numbers and lower-case letters only.
AccountName string `pulumi:"accountName"`
// Specifies type of the key to be listed. Possible value is kerb.
Expand *string `pulumi:"expand"`
// The name of the resource group within the user's subscription. The name is case insensitive.
ResourceGroupName string `pulumi:"resourceGroupName"`
}
// The response from the ListKeys operation.
type ListStorageAccountKeysResult struct {
// Gets the list of storage account keys and their properties for the specified storage account.
Keys []StorageAccountKeyResponse `pulumi:"keys"`
}
func ListStorageAccountKeysOutput(ctx *pulumi.Context, args ListStorageAccountKeysOutputArgs, opts ...pulumi.InvokeOption) ListStorageAccountKeysResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (ListStorageAccountKeysResult, error) {
args := v.(ListStorageAccountKeysArgs)
r, err := ListStorageAccountKeys(ctx, &args, opts...)
return *r, err
}).(ListStorageAccountKeysResultOutput)
}
type ListStorageAccountKeysOutputArgs struct {
// The name of the storage account within the specified resource group. Storage account names must be between 3 and 24 characters in length and use numbers and lower-case letters only.
AccountName pulumi.StringInput `pulumi:"accountName"`
// Specifies type of the key to be listed. Possible value is kerb.
Expand pulumi.StringPtrInput `pulumi:"expand"`
// The name of the resource group within the user's subscription. The name is case insensitive.
ResourceGroupName pulumi.StringInput `pulumi:"resourceGroupName"`
}
func (ListStorageAccountKeysOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*ListStorageAccountKeysArgs)(nil)).Elem()
}
// The response from the ListKeys operation.
type ListStorageAccountKeysResultOutput struct { *pulumi.OutputState }
func (ListStorageAccountKeysResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*ListStorageAccountKeysResult)(nil)).Elem()
}
func (o ListStorageAccountKeysResultOutput) ToListStorageAccountKeysResultOutput() ListStorageAccountKeysResultOutput {
return o
}
func (o ListStorageAccountKeysResultOutput) ToListStorageAccountKeysResultOutputWithContext(ctx context.Context) ListStorageAccountKeysResultOutput {
return o
}
// Gets the list of storage account keys and their properties for the specified storage account.
func (o ListStorageAccountKeysResultOutput) Keys() StorageAccountKeyResponseArrayOutput {
return o.ApplyT(func (v ListStorageAccountKeysResult) []StorageAccountKeyResponse { return v.Keys }).(StorageAccountKeyResponseArrayOutput)
}
func init() {
pulumi.RegisterOutputType(ListStorageAccountKeysResultOutput{})
}

View file

@ -0,0 +1,51 @@
// Copyright 2016-2021, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This code is hand-added to make generated code compile.
package codegentest
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
// An access key for the storage account.
type StorageAccountKeyResponse struct {
// Name of the key.
KeyName string `pulumi:"keyName"`
// Permissions for the key -- read-only or full permissions.
Permissions string `pulumi:"permissions"`
// Base 64-encoded value of the key.
Value string `pulumi:"value"`
}
type StorageAccountKeyResponseArrayOutput struct{ *pulumi.OutputState }
func (StorageAccountKeyResponseArrayOutput) ElementType() reflect.Type {
return reflect.TypeOf((*[]StorageAccountKeyResponse)(nil)).Elem()
}
func (o StorageAccountKeyResponseArrayOutput) ToStorageAccountKeyResponseArrayOutput() StorageAccountKeyResponseArrayOutput {
return o
}
func (o StorageAccountKeyResponseArrayOutput) ToStorageAccountKeyResponseArrayOutputWithContext(ctx context.Context) StorageAccountKeyResponseArrayOutput {
return o
}
func init() {
pulumi.RegisterOutputType(StorageAccountKeyResponseArrayOutput{})
}

View file

@ -0,0 +1,75 @@
{
"functions": {
"azure-native:codegentest:listStorageAccountKeys": {
"description": "The response from the ListKeys operation.\nAPI Version: 2021-02-01.",
"inputs": {
"properties": {
"accountName": {
"type": "string",
"description": "The name of the storage account within the specified resource group. Storage account names must be between 3 and 24 characters in length and use numbers and lower-case letters only."
},
"expand": {
"type": "string",
"description": "Specifies type of the key to be listed. Possible value is kerb."
},
"resourceGroupName": {
"type": "string",
"description": "The name of the resource group within the user's subscription. The name is case insensitive."
}
},
"type": "object",
"required": [
"accountName",
"resourceGroupName"
]
},
"outputs": {
"description": "The response from the ListKeys operation.",
"properties": {
"keys": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/types/azure-native:codegentest:StorageAccountKeyResponse"
},
"description": "Gets the list of storage account keys and their properties for the specified storage account."
}
},
"type": "object",
"required": [
"keys"
]
}
}
},
"types": {
"azure-native:codegentest:StorageAccountKeyResponse": {
"description": "An access key for the storage account.",
"properties": {
"creationTime": {
"type": "string",
"description": "Creation time of the key, in round trip date format."
},
"keyName": {
"type": "string",
"description": "Name of the key."
},
"permissions": {
"type": "string",
"description": "Permissions for the key -- read-only or full permissions."
},
"value": {
"type": "string",
"description": "Base 64-encoded value of the key."
}
},
"type": "object",
"required": [
"creationTime",
"keyName",
"permissions",
"value"
]
}
}
}

View file

@ -43,6 +43,47 @@ func (i BazArgs) ToBazOutputWithContext(ctx context.Context) BazOutput {
return pulumi.ToOutputWithContext(ctx, i).(BazOutput)
}
func (i BazArgs) ToBazPtrOutput() BazPtrOutput {
return i.ToBazPtrOutputWithContext(context.Background())
}
func (i BazArgs) ToBazPtrOutputWithContext(ctx context.Context) BazPtrOutput {
return pulumi.ToOutputWithContext(ctx, i).(BazOutput).ToBazPtrOutputWithContext(ctx)
}
// BazPtrInput is an input type that accepts BazArgs, BazPtr and BazPtrOutput values.
// You can construct a concrete instance of `BazPtrInput` via:
//
// BazArgs{...}
//
// or:
//
// nil
type BazPtrInput interface {
pulumi.Input
ToBazPtrOutput() BazPtrOutput
ToBazPtrOutputWithContext(context.Context) BazPtrOutput
}
type bazPtrType BazArgs
func BazPtr(v *BazArgs) BazPtrInput {
return (*bazPtrType)(v)
}
func (*bazPtrType) ElementType() reflect.Type {
return reflect.TypeOf((**Baz)(nil)).Elem()
}
func (i *bazPtrType) ToBazPtrOutput() BazPtrOutput {
return i.ToBazPtrOutputWithContext(context.Background())
}
func (i *bazPtrType) ToBazPtrOutputWithContext(ctx context.Context) BazPtrOutput {
return pulumi.ToOutputWithContext(ctx, i).(BazPtrOutput)
}
type BazOutput struct{ *pulumi.OutputState }
func (BazOutput) ElementType() reflect.Type {
@ -57,6 +98,16 @@ func (o BazOutput) ToBazOutputWithContext(ctx context.Context) BazOutput {
return o
}
func (o BazOutput) ToBazPtrOutput() BazPtrOutput {
return o.ToBazPtrOutputWithContext(context.Background())
}
func (o BazOutput) ToBazPtrOutputWithContext(ctx context.Context) BazPtrOutput {
return o.ApplyTWithContext(ctx, func(_ context.Context, v Baz) *Baz {
return &v
}).(BazPtrOutput)
}
func (o BazOutput) Hello() pulumi.StringPtrOutput {
return o.ApplyT(func(v Baz) *string { return v.Hello }).(pulumi.StringPtrOutput)
}
@ -65,6 +116,49 @@ func (o BazOutput) World() pulumi.StringPtrOutput {
return o.ApplyT(func(v Baz) *string { return v.World }).(pulumi.StringPtrOutput)
}
type BazPtrOutput struct{ *pulumi.OutputState }
func (BazPtrOutput) ElementType() reflect.Type {
return reflect.TypeOf((**Baz)(nil)).Elem()
}
func (o BazPtrOutput) ToBazPtrOutput() BazPtrOutput {
return o
}
func (o BazPtrOutput) ToBazPtrOutputWithContext(ctx context.Context) BazPtrOutput {
return o
}
func (o BazPtrOutput) Elem() BazOutput {
return o.ApplyT(func(v *Baz) Baz {
if v != nil {
return *v
}
var ret Baz
return ret
}).(BazOutput)
}
func (o BazPtrOutput) Hello() pulumi.StringPtrOutput {
return o.ApplyT(func(v *Baz) *string {
if v == nil {
return nil
}
return v.Hello
}).(pulumi.StringPtrOutput)
}
func (o BazPtrOutput) World() pulumi.StringPtrOutput {
return o.ApplyT(func(v *Baz) *string {
if v == nil {
return nil
}
return v.World
}).(pulumi.StringPtrOutput)
}
func init() {
pulumi.RegisterOutputType(BazOutput{})
pulumi.RegisterOutputType(BazPtrOutput{})
}

View file

@ -4,6 +4,9 @@
package example
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
@ -23,3 +26,42 @@ type ArgFunctionArgs struct {
type ArgFunctionResult struct {
Result *Resource `pulumi:"result"`
}
func ArgFunctionOutput(ctx *pulumi.Context, args ArgFunctionOutputArgs, opts ...pulumi.InvokeOption) ArgFunctionResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (ArgFunctionResult, error) {
args := v.(ArgFunctionArgs)
r, err := ArgFunction(ctx, &args, opts...)
return *r, err
}).(ArgFunctionResultOutput)
}
type ArgFunctionOutputArgs struct {
Arg1 ResourceInput `pulumi:"arg1"`
}
func (ArgFunctionOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionArgs)(nil)).Elem()
}
type ArgFunctionResultOutput struct{ *pulumi.OutputState }
func (ArgFunctionResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionResult)(nil)).Elem()
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutput() ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutputWithContext(ctx context.Context) ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) Result() ResourceOutput {
return o.ApplyT(func(v ArgFunctionResult) *Resource { return v.Result }).(ResourceOutput)
}
func init() {
pulumi.RegisterOutputType(ArgFunctionResultOutput{})
}

View file

@ -4,6 +4,9 @@
package example
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
@ -23,3 +26,42 @@ type ArgFunctionArgs struct {
type ArgFunctionResult struct {
Result *Resource `pulumi:"result"`
}
func ArgFunctionOutput(ctx *pulumi.Context, args ArgFunctionOutputArgs, opts ...pulumi.InvokeOption) ArgFunctionResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (ArgFunctionResult, error) {
args := v.(ArgFunctionArgs)
r, err := ArgFunction(ctx, &args, opts...)
return *r, err
}).(ArgFunctionResultOutput)
}
type ArgFunctionOutputArgs struct {
Arg1 ResourceInput `pulumi:"arg1"`
}
func (ArgFunctionOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionArgs)(nil)).Elem()
}
type ArgFunctionResultOutput struct{ *pulumi.OutputState }
func (ArgFunctionResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionResult)(nil)).Elem()
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutput() ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutputWithContext(ctx context.Context) ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) Result() ResourceOutput {
return o.ApplyT(func(v ArgFunctionResult) *Resource { return v.Result }).(ResourceOutput)
}
func init() {
pulumi.RegisterOutputType(ArgFunctionResultOutput{})
}

View file

@ -4,6 +4,9 @@
package example
import (
"context"
"reflect"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
@ -23,3 +26,42 @@ type ArgFunctionArgs struct {
type ArgFunctionResult struct {
Result *Resource `pulumi:"result"`
}
func ArgFunctionOutput(ctx *pulumi.Context, args ArgFunctionOutputArgs, opts ...pulumi.InvokeOption) ArgFunctionResultOutput {
return pulumi.ToOutputWithContext(context.Background(), args).
ApplyT(func(v interface{}) (ArgFunctionResult, error) {
args := v.(ArgFunctionArgs)
r, err := ArgFunction(ctx, &args, opts...)
return *r, err
}).(ArgFunctionResultOutput)
}
type ArgFunctionOutputArgs struct {
Arg1 ResourceInput `pulumi:"arg1"`
}
func (ArgFunctionOutputArgs) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionArgs)(nil)).Elem()
}
type ArgFunctionResultOutput struct{ *pulumi.OutputState }
func (ArgFunctionResultOutput) ElementType() reflect.Type {
return reflect.TypeOf((*ArgFunctionResult)(nil)).Elem()
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutput() ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) ToArgFunctionResultOutputWithContext(ctx context.Context) ArgFunctionResultOutput {
return o
}
func (o ArgFunctionResultOutput) Result() ResourceOutput {
return o.ApplyT(func(v ArgFunctionResult) *Resource { return v.Result }).(ResourceOutput)
}
func init() {
pulumi.RegisterOutputType(ArgFunctionResultOutput{})
}

View file

@ -1541,7 +1541,7 @@ const (
)
// Regex used to parse external schema paths. This is declared at the package scope to avoid repeated recompilation.
var refPathRegex = regexp.MustCompile(`^/?(?P<package>\w+)/(?P<version>v[^/]*)/schema\.json$`)
var refPathRegex = regexp.MustCompile(`^/?(?P<package>[-\w]+)/(?P<version>v[^/]*)/schema\.json$`)
func (t *types) parseTypeSpecRef(ref string) (typeSpecRef, error) {
parsedURL, err := url.Parse(ref)
@ -2439,3 +2439,29 @@ func jsonMarshal(v interface{}) ([]byte, error) {
}
return b.Bytes(), nil
}
// Determines if codegen should emit a ${fn}Output version that
// automatically accepts Inputs and returns Outputs.
func (fun *Function) NeedsOutputVersion() bool {
// Skip functions that return no value. Arguably we could
// support them and return `Task`, but there are no such
// functions in `pulumi-azure-native` or `pulumi-aws` so we
// omit to simplify.
if fun.Outputs == nil {
return false
}
// Skip functions that have no inputs. The user can simply
// lift the `Task` to `Output` manually.
if fun.Inputs == nil {
return false
}
// No properties is kind of like no inputs.
if len(fun.Inputs.Properties) == 0 {
return false
}
return true
}

View file

@ -310,6 +310,17 @@ func Test_parseTypeSpecRef(t *testing.T) {
Token: "pulumi:providers:kubernetes",
},
},
{
name: "hyphenatedUrlPath",
ref: "/azure-native/v1.22.0/schema.json#/resources/azure-native:web:WebApp",
want: typeSpecRef{
URL: toURL("/azure-native/v1.22.0/schema.json#/resources/azure-native:web:WebApp"),
Package: "azure-native",
Version: toVersionPtr("1.22.0"),
Kind: "resources",
Token: "azure-native:web:WebApp",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View file

@ -624,8 +624,31 @@ namespace Pulumi.Automation
}
/// <inheritdoc/>
public override Task InstallPluginAsync(string name, string version, PluginKind kind = PluginKind.Resource, CancellationToken cancellationToken = default)
=> this.RunCommandAsync(new[] { "plugin", "install", kind.ToString().ToLower(), name, version }, cancellationToken);
public override Task InstallPluginAsync(string name, string version, PluginKind kind = PluginKind.Resource, PluginInstallOptions? options = null, CancellationToken cancellationToken = default)
{
var args = new List<string>
{
"plugin",
"install",
kind.ToString().ToLowerInvariant(),
name,
version
};
if (options != null)
{
if (options.ExactVersion)
args.Add("--exact");
if (!string.IsNullOrWhiteSpace(options.ServerUrl))
{
args.Add("--server");
args.Add(options.ServerUrl);
}
}
return this.RunCommandAsync(args, cancellationToken);
}
/// <inheritdoc/>
public override Task RemovePluginAsync(string? name = null, string? versionRange = null, PluginKind kind = PluginKind.Resource, CancellationToken cancellationToken = default)

View file

@ -0,0 +1,17 @@
namespace Pulumi.Automation
{
public class PluginInstallOptions
{
/// <summary>
/// If <c>true</c>, force installation of an exact version match (usually >= is accepted).
/// <para/>
/// Defaults to <c>false</c>.
/// </summary>
public bool ExactVersion { get; set; }
/// <summary>
/// A URL to download plugins from.
/// </summary>
public string? ServerUrl { get; set; }
}
}

View file

@ -158,6 +158,12 @@ Pulumi.Automation.PluginInfo.Path.get -> string
Pulumi.Automation.PluginInfo.ServerUrl.get -> string
Pulumi.Automation.PluginInfo.Size.get -> long
Pulumi.Automation.PluginInfo.Version.get -> string
Pulumi.Automation.PluginInstallOptions
Pulumi.Automation.PluginInstallOptions.ExactVersion.get -> bool
Pulumi.Automation.PluginInstallOptions.ExactVersion.set -> void
Pulumi.Automation.PluginInstallOptions.PluginInstallOptions() -> void
Pulumi.Automation.PluginInstallOptions.ServerUrl.get -> string
Pulumi.Automation.PluginInstallOptions.ServerUrl.set -> void
Pulumi.Automation.PluginKind
Pulumi.Automation.PluginKind.Analyzer = 0 -> Pulumi.Automation.PluginKind
Pulumi.Automation.PluginKind.Language = 1 -> Pulumi.Automation.PluginKind
@ -332,6 +338,7 @@ Pulumi.Automation.WhoAmIResult.User.get -> string
Pulumi.Automation.WhoAmIResult.WhoAmIResult(string user) -> void
Pulumi.Automation.Workspace
Pulumi.Automation.Workspace.CreateStackAsync(string stackName) -> System.Threading.Tasks.Task
Pulumi.Automation.Workspace.InstallPluginAsync(string name, string version, Pulumi.Automation.PluginKind kind, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task
Pulumi.Automation.Workspace.SelectStackAsync(string stackName) -> System.Threading.Tasks.Task
Pulumi.Automation.WorkspaceStack
Pulumi.Automation.WorkspaceStack.DestroyAsync(Pulumi.Automation.DestroyOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Pulumi.Automation.UpdateResult>
@ -359,7 +366,7 @@ abstract Pulumi.Automation.Workspace.GetConfigAsync(string stackName, string key
abstract Pulumi.Automation.Workspace.GetProjectSettingsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Pulumi.Automation.ProjectSettings>
abstract Pulumi.Automation.Workspace.GetStackOutputsAsync(string stackName, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Immutable.ImmutableDictionary<string, Pulumi.Automation.OutputValue>>
abstract Pulumi.Automation.Workspace.GetStackSettingsAsync(string stackName, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Pulumi.Automation.StackSettings>
abstract Pulumi.Automation.Workspace.InstallPluginAsync(string name, string version, Pulumi.Automation.PluginKind kind = Pulumi.Automation.PluginKind.Resource, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task
abstract Pulumi.Automation.Workspace.InstallPluginAsync(string name, string version, Pulumi.Automation.PluginKind kind = Pulumi.Automation.PluginKind.Resource, Pulumi.Automation.PluginInstallOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task
abstract Pulumi.Automation.Workspace.ListPluginsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Immutable.ImmutableList<Pulumi.Automation.PluginInfo>>
abstract Pulumi.Automation.Workspace.ListStacksAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Immutable.ImmutableList<Pulumi.Automation.StackSummary>>
abstract Pulumi.Automation.Workspace.Logger.get -> Microsoft.Extensions.Logging.ILogger
@ -392,7 +399,7 @@ override Pulumi.Automation.LocalWorkspace.GetConfigAsync(string stackName, strin
override Pulumi.Automation.LocalWorkspace.GetProjectSettingsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Pulumi.Automation.ProjectSettings>
override Pulumi.Automation.LocalWorkspace.GetStackOutputsAsync(string stackName, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Immutable.ImmutableDictionary<string, Pulumi.Automation.OutputValue>>
override Pulumi.Automation.LocalWorkspace.GetStackSettingsAsync(string stackName, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<Pulumi.Automation.StackSettings>
override Pulumi.Automation.LocalWorkspace.InstallPluginAsync(string name, string version, Pulumi.Automation.PluginKind kind = Pulumi.Automation.PluginKind.Resource, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task
override Pulumi.Automation.LocalWorkspace.InstallPluginAsync(string name, string version, Pulumi.Automation.PluginKind kind = Pulumi.Automation.PluginKind.Resource, Pulumi.Automation.PluginInstallOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task
override Pulumi.Automation.LocalWorkspace.ListPluginsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Immutable.ImmutableList<Pulumi.Automation.PluginInfo>>
override Pulumi.Automation.LocalWorkspace.ListStacksAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task<System.Collections.Immutable.ImmutableList<Pulumi.Automation.StackSummary>>
override Pulumi.Automation.LocalWorkspace.Logger.get -> Microsoft.Extensions.Logging.ILogger

View file

@ -593,7 +593,7 @@
<member name="M:Pulumi.Automation.LocalWorkspace.ImportStackAsync(System.String,Pulumi.Automation.StackDeployment,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Pulumi.Automation.LocalWorkspace.InstallPluginAsync(System.String,System.String,Pulumi.Automation.PluginKind,System.Threading.CancellationToken)">
<member name="M:Pulumi.Automation.LocalWorkspace.InstallPluginAsync(System.String,System.String,Pulumi.Automation.PluginKind,Pulumi.Automation.PluginInstallOptions,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Pulumi.Automation.LocalWorkspace.RemovePluginAsync(System.String,System.String,Pulumi.Automation.PluginKind,System.Threading.CancellationToken)">
@ -665,6 +665,18 @@
<see cref="M:Pulumi.Automation.LocalWorkspace.SaveStackSettingsAsync(System.String,Pulumi.Automation.StackSettings,System.Threading.CancellationToken)"/>.
</summary>
</member>
<member name="P:Pulumi.Automation.PluginInstallOptions.ExactVersion">
<summary>
If <c>true</c>, force installation of an exact version match (usually >= is accepted).
<para/>
Defaults to <c>false</c>.
</summary>
</member>
<member name="P:Pulumi.Automation.PluginInstallOptions.ServerUrl">
<summary>
A URL to download plugins from.
</summary>
</member>
<member name="T:Pulumi.Automation.PreviewOptions">
<summary>
Options controlling the behavior of an <see cref="M:Pulumi.Automation.WorkspaceStack.PreviewAsync(Pulumi.Automation.PreviewOptions,System.Threading.CancellationToken)"/> operation.
@ -1123,13 +1135,14 @@
stack's state (such as recovery from failed deployments).
</summary>
</member>
<member name="M:Pulumi.Automation.Workspace.InstallPluginAsync(System.String,System.String,Pulumi.Automation.PluginKind,System.Threading.CancellationToken)">
<member name="M:Pulumi.Automation.Workspace.InstallPluginAsync(System.String,System.String,Pulumi.Automation.PluginKind,Pulumi.Automation.PluginInstallOptions,System.Threading.CancellationToken)">
<summary>
Installs a plugin in the Workspace, for example to use cloud providers like AWS or GCP.
</summary>
<param name="name">The name of the plugin.</param>
<param name="version">The version of the plugin e.g. "v1.0.0".</param>
<param name="kind">The kind of plugin e.g. "resource".</param>
<param name="options">Any additional plugin installation options.</param>
<param name="cancellationToken">A cancellation token.</param>
</member>
<member name="M:Pulumi.Automation.Workspace.RemovePluginAsync(System.String,System.String,Pulumi.Automation.PluginKind,System.Threading.CancellationToken)">

View file

@ -260,7 +260,18 @@ namespace Pulumi.Automation
/// <param name="version">The version of the plugin e.g. "v1.0.0".</param>
/// <param name="kind">The kind of plugin e.g. "resource".</param>
/// <param name="cancellationToken">A cancellation token.</param>
public abstract Task InstallPluginAsync(string name, string version, PluginKind kind = PluginKind.Resource, CancellationToken cancellationToken = default);
public Task InstallPluginAsync(string name, string version, PluginKind kind, CancellationToken cancellationToken)
=> this.InstallPluginAsync(name, version, kind: kind, options: null, cancellationToken: cancellationToken);
/// <summary>
/// Installs a plugin in the Workspace, for example to use cloud providers like AWS or GCP.
/// </summary>
/// <param name="name">The name of the plugin.</param>
/// <param name="version">The version of the plugin e.g. "v1.0.0".</param>
/// <param name="kind">The kind of plugin e.g. "resource".</param>
/// <param name="options">Any additional plugin installation options.</param>
/// <param name="cancellationToken">A cancellation token.</param>
public abstract Task InstallPluginAsync(string name, string version, PluginKind kind = PluginKind.Resource, PluginInstallOptions? options = null, CancellationToken cancellationToken = default);
/// <summary>
/// Removes a plugin from the Workspace matching the specified name and version.

View file

@ -0,0 +1,28 @@
// Copyright 2016-2021, Pulumi Corporation
namespace Pulumi
{
/// <summary>
/// Options to help control the behavior of <see cref="Deployment.Call{T}"/>.
/// </summary>
public class CallOptions
{
/// <summary>
/// An optional parent to use for default options for this call (e.g. the default provider
/// to use).
/// </summary>
public Resource? Parent { get; set; }
/// <summary>
/// An optional provider to use for this call. If no provider is supplied, the default
/// provider for the called function's package will be used.
/// </summary>
public ProviderResource? Provider { get; set; }
/// <summary>
/// An optional version, corresponding to the version of the provider plugin that should be
/// used when performing this call.
/// </summary>
public string? Version { get; set; }
}
}

View file

@ -8,7 +8,7 @@ namespace Pulumi
public sealed class DeploymentInstance : IDeployment
{
private readonly IDeployment _deployment;
internal DeploymentInstance(IDeployment deployment)
{
_deployment = deployment;
@ -49,6 +49,25 @@ namespace Pulumi
public Task InvokeAsync(string token, InvokeArgs args, InvokeOptions? options = null)
=> _deployment.InvokeAsync(token, args, options);
/// <summary>
/// Dynamically calls the function '<paramref name="token"/>', which is offered by a
/// provider plugin.
/// <para/>
/// The result of <see cref="Call{T}"/> will be a <see cref="Output{T}"/> resolved to the
/// result value of the provider plugin.
/// <para/>
/// The <paramref name="args"/> inputs can be a bag of computed values(including, `T`s,
/// <see cref="Task{TResult}"/>s, <see cref="Output{T}"/>s etc.).
/// </summary>
public Output<T> Call<T>(string token, CallArgs args, Resource? self = null, CallOptions? options = null)
=> _deployment.Call<T>(token, args, self, options);
/// <summary>
/// Same as <see cref="Call{T}"/>, however the return value is ignored.
/// </summary>
public void Call(string token, CallArgs args, Resource? self = null, CallOptions? options = null)
=> _deployment.Call(token, args, self, options);
internal IDeploymentInternal Internal => (IDeploymentInternal)_deployment;
}
}

View file

@ -0,0 +1,138 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes;
using Pulumi.Serialization;
using Pulumirpc;
namespace Pulumi
{
public sealed partial class Deployment
{
void IDeployment.Call(string token, CallArgs args, Resource? self, CallOptions? options)
=> Call<object>(token, args, self, options, convertResult: false);
Output<T> IDeployment.Call<T>(string token, CallArgs args, Resource? self, CallOptions? options)
=> Call<T>(token, args, self, options, convertResult: true);
private Output<T> Call<T>(string token, CallArgs args, Resource? self, CallOptions? options, bool convertResult)
=> new Output<T>(CallAsync<T>(token, args, self, options, convertResult));
private async Task<OutputData<T>> CallAsync<T>(
string token, CallArgs args, Resource? self, CallOptions? options, bool convertResult)
{
var (result, deps) = await CallRawAsync(token, args, self, options).ConfigureAwait(false);
if (convertResult)
{
var converted = Converter.ConvertValue<T>($"{token} result", new Value { StructValue = result });
return new OutputData<T>(deps, converted.Value, converted.IsKnown, converted.IsSecret);
}
return new OutputData<T>(ImmutableHashSet<Resource>.Empty, default!, isKnown: true, isSecret: false);
}
private async Task<(Struct Return, ImmutableHashSet<Resource> Dependencies)> CallRawAsync(
string token, CallArgs args, Resource? self, CallOptions? options)
{
var label = $"Calling function: token={token} asynchronously";
Log.Debug(label);
// Be resilient to misbehaving callers.
// ReSharper disable once ConstantNullCoalescingCondition
args ??= CallArgs.Empty;
// Wait for all values to be available, and then perform the RPC.
var argsDict = await args.ToDictionaryAsync().ConfigureAwait(false);
// If we have a self arg, include it in the args.
if (self != null)
{
argsDict = argsDict.SetItem("__self__", self);
}
var (serialized, argDependencies) = await SerializeFilteredPropertiesAsync(
$"call:{token}",
argsDict, _ => true, keepResources: true).ConfigureAwait(false);
Log.Debug($"Call RPC prepared: token={token}" +
(_excessiveDebugOutput ? $", obj={serialized}" : ""));
// Determine the provider and version to use.
ProviderResource? provider;
string? version;
if (self != null)
{
provider = self._provider;
version = self._version;
}
else
{
provider = GetProvider(token, options);
version = options?.Version;
}
var providerReference = await ProviderResource.RegisterAsync(provider).ConfigureAwait(false);
// Create the request.
var request = new CallRequest
{
Tok = token,
Provider = providerReference ?? "",
Version = version ?? "",
Args = serialized,
};
// Add arg dependencies to the request.
foreach (var (argName, directDependencies) in argDependencies)
{
var urns = await GetAllTransitivelyReferencedResourceUrnsAsync(directDependencies).ConfigureAwait(false);
var deps = new CallRequest.Types.ArgumentDependencies();
deps.Urns.AddRange(urns);
request.ArgDependencies.Add(argName, deps);
}
// Kick off the call.
var result = await Monitor.CallAsync(request).ConfigureAwait(false);
// Handle failures.
if (result.Failures.Count > 0)
{
var reasons = "";
foreach (var reason in result.Failures)
{
if (reasons != "")
{
reasons += "; ";
}
reasons += $"{reason.Reason} ({reason.Property})";
}
throw new CallException($"Call of '{token}' failed: {reasons}");
}
// Unmarshal return dependencies.
var dependencies = ImmutableHashSet.CreateBuilder<Resource>();
foreach (var (_, returnDependencies) in result.ReturnDependencies)
{
foreach (var urn in returnDependencies.Urns)
{
dependencies.Add(new DependencyResource(urn));
}
}
return (result.Return, dependencies.ToImmutable());
}
private static ProviderResource? GetProvider(string token, CallOptions? options)
=> options?.Provider ?? options?.Parent?.GetProvider(token);
private sealed class CallException : Exception
{
public CallException(string error)
: base(error)
{
}
}
}
}

View file

@ -24,6 +24,9 @@ namespace Pulumi
public async Task<InvokeResponse> InvokeAsync(InvokeRequest request)
=> await this._client.InvokeAsync(request);
public async Task<CallResponse> CallAsync(CallRequest request)
=> await this._client.CallAsync(request);
public async Task<ReadResourceResponse> ReadResourceAsync(Resource resource, ReadResourceRequest request)
=> await this._client.ReadResourceAsync(request);

View file

@ -38,5 +38,23 @@ namespace Pulumi
/// return value is ignored.
/// </summary>
Task InvokeAsync(string token, InvokeArgs args, InvokeOptions? options = null);
/// <summary>
/// Dynamically calls the function '<paramref name="token"/>', which is offered by a
/// provider plugin. <see cref="Call{T}"/> returns immediately while the operation takes
/// place asynchronously in the background, similar to Resource constructors.
/// <para/>
/// The result of <see cref="Call{T}"/> will be a <see cref="Output{T}"/> resolved to the
/// result value of the provider plugin.
/// <para/>
/// The <paramref name="args"/> inputs can be a bag of computed values(including, `T`s,
/// <see cref="Task{TResult}"/>s, <see cref="Output{T}"/>s etc.).
/// </summary>
Output<T> Call<T>(string token, CallArgs args, Resource? self = null, CallOptions? options = null);
/// <summary>
/// Same as <see cref="Call{T}"/>, however the return value is ignored.
/// </summary>
void Call(string token, CallArgs args, Resource? self = null, CallOptions? options = null);
}
}

View file

@ -10,6 +10,8 @@ namespace Pulumi
Task<SupportsFeatureResponse> SupportsFeatureAsync(SupportsFeatureRequest request);
Task<InvokeResponse> InvokeAsync(InvokeRequest request);
Task<CallResponse> CallAsync(CallRequest request);
Task<ReadResourceResponse> ReadResourceAsync(Resource resource, ReadResourceRequest request);

View file

@ -21,6 +21,16 @@ Pulumi.Asset
Pulumi.AssetArchive
Pulumi.AssetArchive.AssetArchive(System.Collections.Generic.IDictionary<string, Pulumi.AssetOrArchive> assets) -> void
Pulumi.AssetOrArchive
Pulumi.CallArgs
Pulumi.CallArgs.CallArgs() -> void
Pulumi.CallOptions
Pulumi.CallOptions.CallOptions() -> void
Pulumi.CallOptions.Parent.get -> Pulumi.Resource
Pulumi.CallOptions.Parent.set -> void
Pulumi.CallOptions.Provider.get -> Pulumi.ProviderResource
Pulumi.CallOptions.Provider.set -> void
Pulumi.CallOptions.Version.get -> string
Pulumi.CallOptions.Version.set -> void
Pulumi.ComponentResource
Pulumi.ComponentResource.ComponentResource(string type, string name, Pulumi.ComponentResourceOptions options = null) -> void
Pulumi.ComponentResource.ComponentResource(string type, string name, Pulumi.ResourceArgs args, Pulumi.ComponentResourceOptions options = null, bool remote = false) -> void
@ -73,6 +83,8 @@ Pulumi.DictionaryResourceArgs
Pulumi.DictionaryResourceArgs.DictionaryResourceArgs(System.Collections.Immutable.ImmutableDictionary<string, object> dictionary) -> void
Pulumi.Deployment
Pulumi.DeploymentInstance
Pulumi.DeploymentInstance.Call(string token, Pulumi.CallArgs args, Pulumi.Resource self = null, Pulumi.CallOptions options = null) -> void
Pulumi.DeploymentInstance.Call<T>(string token, Pulumi.CallArgs args, Pulumi.Resource self = null, Pulumi.CallOptions options = null) -> Pulumi.Output<T>
Pulumi.DeploymentInstance.InvokeAsync(string token, Pulumi.InvokeArgs args, Pulumi.InvokeOptions options = null) -> System.Threading.Tasks.Task
Pulumi.DeploymentInstance.InvokeAsync<T>(string token, Pulumi.InvokeArgs args, Pulumi.InvokeOptions options = null) -> System.Threading.Tasks.Task<T>
Pulumi.DeploymentInstance.IsDryRun.get -> bool
@ -357,5 +369,6 @@ static Pulumi.Union<T0, T1>.FromT1(T1 input) -> Pulumi.Union<T0, T1>
static Pulumi.Union<T0, T1>.implicit operator Pulumi.Union<T0, T1>(T0 t) -> Pulumi.Union<T0, T1>
static Pulumi.Union<T0, T1>.implicit operator Pulumi.Union<T0, T1>(T1 t) -> Pulumi.Union<T0, T1>
static Pulumi.Urn.Create(Pulumi.Input<string> name, Pulumi.Input<string> type, Pulumi.Resource parent = null, Pulumi.Input<string> parentUrn = null, Pulumi.Input<string> project = null, Pulumi.Input<string> stack = null) -> Pulumi.Output<string>
static readonly Pulumi.CallArgs.Empty -> Pulumi.CallArgs
static readonly Pulumi.InvokeArgs.Empty -> Pulumi.InvokeArgs
static readonly Pulumi.ResourceArgs.Empty -> Pulumi.ResourceArgs

View file

@ -0,0 +1,23 @@
// Copyright 2016-2021, Pulumi Corporation
using System;
namespace Pulumi
{
/// <summary>
/// Base type for all call argument classes.
/// </summary>
public abstract class CallArgs : InputArgs
{
public static readonly CallArgs Empty = new EmptyCallArgs();
private protected override void ValidateMember(Type memberType, string fullName)
{
// No validation. A member may or may not be IInput.
}
private sealed class EmptyCallArgs : CallArgs
{
}
}
}

View file

@ -93,6 +93,16 @@ namespace Pulumi
/// </summary>
private readonly ImmutableDictionary<string, ProviderResource> _providers;
/// <summary>
/// The specified provider or provider determined from the parent for custom resources.
/// </summary>
internal readonly ProviderResource? _provider;
/// <summary>
/// The specified provider version.
/// </summary>
internal readonly string? _version;
/// <summary>
/// Creates and registers a new resource object. <paramref name="type"/> is the fully
/// qualified type token and <paramref name="name"/> is the "name" part to use in creating a
@ -241,6 +251,8 @@ namespace Pulumi
}
this._protect = options.Protect == true;
this._provider = custom ? options.Provider : null;
this._version = options.Version;
// Collapse any 'Alias'es down to URNs. We have to wait until this point to do so
// because we do not know the default 'name' and 'type' to apply until we are inside the

View file

@ -58,6 +58,21 @@ namespace Pulumi.Testing
return new InvokeResponse { Return = await SerializeAsync(result).ConfigureAwait(false) };
}
public async Task<CallResponse> CallAsync(CallRequest request)
{
// For now, we'll route both Invoke and Call through IMocks.CallAsync.
var args = ToDictionary(request.Args);
var result = await _mocks.CallAsync(new MockCallArgs
{
Token = request.Tok,
Args = args,
Provider = request.Provider,
})
.ConfigureAwait(false);
return new CallResponse { Return = await SerializeAsync(result).ConfigureAwait(false) };
}
public async Task<ReadResourceResponse> ReadResourceAsync(Resource resource, ReadResourceRequest request)
{
var (id, state) = await _mocks.NewResourceAsync(new MockResourceArgs

View file

@ -23,6 +23,7 @@ import (
"time"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/pulumi/pulumi/sdk/v3/python"
"github.com/stretchr/testify/assert"
)
@ -369,13 +370,30 @@ func TestRuntimeErrorPython(t *testing.T) {
stackName := FullyQualifiedStackName(pulumiOrg, runtimeErrProj, sName)
// initialize
pDir := filepath.Join(".", "test", "errors", "runtime_error", "python")
cmd := exec.Command("python3", "-m", "venv", "venv")
cmd.Dir = pDir
err := cmd.Run()
pDir, err := filepath.Abs(filepath.Join(".", "test", "errors", "runtime_error", "python"))
if err != nil {
t.Errorf("failed to install project dependencies")
t.Error(err)
t.FailNow()
}
err = python.InstallDependencies(pDir, "venv", true /*showOutput*/)
if err != nil {
t.Errorf("failed to create a venv and install project dependencies: %v", err)
t.FailNow()
}
pySDK, err := filepath.Abs(filepath.Join("..", "..", "..", "sdk", "python", "env", "src"))
if err != nil {
t.Error(err)
t.FailNow()
}
// install Pulumi Python SDK from the current source tree, -e means no-copy, ref directly
pyCmd := python.VirtualEnvCommand(filepath.Join(pDir, "venv"), "python", "-m", "pip", "install", "-e", pySDK)
pyCmd.Dir = pDir
err = pyCmd.Run()
if err != nil {
t.Errorf("failed to link venv against in-source pulumi: %v", err)
t.FailNow()
}
@ -394,6 +412,7 @@ func TestRuntimeErrorPython(t *testing.T) {
_, err = s.Up(ctx)
assert.NotNil(t, err)
assert.True(t, IsRuntimeError(err), "%+v", err)
assert.Contains(t, fmt.Sprintf("%v", err), "IndexError: list index out of range")
// -- pulumi destroy --

View file

@ -1 +1 @@
pulumi>=2.0.0,<3.0.0

View file

@ -1,47 +0,0 @@
%% regenerate using https://github.com/mermaid-js/mermaid-cli
flowchart TD
start("Resource registration")
read_read("Read(reg.URN, reg.ID, reg.State)")
import_read("Read(reg.URN, reg.ID)")
import_check("Check(reg.URN, reg.Inputs, read.Inputs)")
import_diff("Diff(reg.URN, check.Inputs, read.State)")
manage_check("Check(reg.URN, reg.Inputs, last?.Inputs)")
manage_create("Create(reg.URN, check.Inputs)")
manage_diff("Diff(reg.URN, check.Inputs, last.ID, last.State)")
manage_update("Update(reg.URN, last.ID, last.State)")
manage_replace_check("Check(reg.URN, reg.Inputs)")
manage_replace_create_before_delete("Create(reg.URN, reg.Inputs)")
manage_replace_delete_after_create("Delete(reg.URN, last.ID, last.State)")
manage_replace_delete_dependents("Delete dependents")
manage_replace_delete_before_create("Delete(reg.URN, last.ID, last.State)")
manage_replace_create_after_delete("Create(reg.URN, check.Inputs)")
done("Return new inputs and state")
start-- read -->read_read
start-- import -->import_read
start-- manage -->manage_check
read_read-->done
import_read-->import_check
import_check-->import_diff
import_diff-->done
manage_check-- no last state -->manage_create
manage_check-- has last state -->manage_diff
manage_diff-- can be updated -->manage_update
manage_diff-- must be replaced -->manage_replace_check
manage_replace_check-- create before delete -->manage_replace_create_before_delete
manage_replace_check-- delete after craete -->manage_replace_delete_dependents
manage_replace_create_before_delete-->manage_replace_delete_after_create
manage_replace_delete_dependents-->manage_replace_delete_before_create
manage_replace_delete_before_create-->manage_replace_create_after_delete
manage_create-->done
manage_update-->done
manage_replace_delete_after_create-->done
manage_replace_create_after_delete-->done

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 29 KiB

View file

@ -24,6 +24,7 @@
package main
import (
"bytes"
"context"
"encoding/json"
"flag"
@ -188,8 +189,7 @@ func (host *pythonLanguageHost) GetRequiredPlugins(ctx context.Context,
plugins := []*pulumirpc.PluginDependency{}
for _, pkg := range pulumiPackages {
plugin, err := determinePluginDependency(host.virtualenvPath, host.cwd, pkg.Name, pkg.Version)
plugin, err := determinePluginDependency(host.virtualenvPath, host.cwd, pkg)
if err != nil {
return nil, err
}
@ -318,23 +318,27 @@ var packagesWithoutPlugins = map[string]struct{}{
}
type pythonPackage struct {
Name string `json:"name"`
Version string `json:"version"`
Name string `json:"name"`
Version string `json:"version"`
Location string `json:"location"`
}
func determinePulumiPackages(virtualenv, cwd string) ([]pythonPackage, error) {
logging.V(5).Infof("GetRequiredPlugins: Determining pulumi packages")
// Run the `python -m pip list --format json` command.
args := []string{"-m", "pip", "list", "--format", "json"}
// Run the `python -m pip list -v --format json` command.
args := []string{"-m", "pip", "list", "-v", "--format", "json"}
output, err := runPythonCommand(virtualenv, cwd, args...)
if err != nil {
return nil, err
}
// Parse the JSON output.
// Parse the JSON output; on some systems pip -v verbose mode
// follows JSON with non-JSON trailer, so we need to be
// careful when parsing and ignore the trailer.
var packages []pythonPackage
if err := json.Unmarshal(output, &packages); err != nil {
jsonDecoder := json.NewDecoder(bytes.NewBuffer(output))
if err := jsonDecoder.Decode(&packages); err != nil {
return nil, errors.Wrapf(err, "parsing `python %s` output", strings.Join(args, " "))
}
@ -365,23 +369,17 @@ func determinePulumiPackages(virtualenv, cwd string) ([]pythonPackage, error) {
// are derived from the package name and version. If the plugin version cannot be determined from the package version,
// nil is returned.
func determinePluginDependency(
virtualenv, cwd, packageName, packageVersion string) (*pulumirpc.PluginDependency, error) {
virtualenv, cwd string, pkg pythonPackage) (*pulumirpc.PluginDependency, error) {
logging.V(5).Infof("GetRequiredPlugins: Determining plugin dependency: %v, %v", packageName, packageVersion)
// Determine the location of the installed package.
packageLocation, err := determinePackageLocation(virtualenv, cwd, packageName)
if err != nil {
return nil, err
}
logging.V(5).Infof("GetRequiredPlugins: Determining plugin dependency: %v, %v", pkg.Name, pkg.Version)
// The name of the module inside the package can be different from the package name.
// However, our convention is to always use the same name, e.g. a package name of
// "pulumi-aws" will have a module named "pulumi_aws", so we can determine the module
// by replacing hyphens with underscores.
packageModuleName := strings.ReplaceAll(packageName, "-", "_")
packageModuleName := strings.ReplaceAll(pkg.Name, "-", "_")
pulumiPluginFilePath := filepath.Join(packageLocation, packageModuleName, "pulumiplugin.json")
pulumiPluginFilePath := filepath.Join(pkg.Location, packageModuleName, "pulumiplugin.json")
logging.V(5).Infof("GetRequiredPlugins: pulumiplugin.json file path: %s", pulumiPluginFilePath)
var name, version, server string
@ -390,7 +388,7 @@ func determinePluginDependency(
// If `resource` is set to false, the Pulumi package has indicated that there is no associated plugin.
// Ignore it.
if !plugin.Resource {
logging.V(5).Infof("GetRequiredPlugins: Ignoring package %s with resource set to false", packageName)
logging.V(5).Infof("GetRequiredPlugins: Ignoring package %s with resource set to false", pkg.Name)
return nil, nil
}
@ -403,7 +401,7 @@ func determinePluginDependency(
}
if name == "" {
name = strings.TrimPrefix(packageName, "pulumi-")
name = strings.TrimPrefix(pkg.Name, "pulumi-")
}
if version == "" {
@ -413,11 +411,11 @@ func determinePluginDependency(
// "3.31.0a1605189729" will have an associated plugin with a version of "3.31.0-alpha.1605189729+42435656".
// The "+42435656" suffix cannot be determined so the plugin version cannot be determined. In such cases,
// log the issue and skip the package.
version, err = determinePluginVersion(packageVersion)
version, err = determinePluginVersion(pkg.Version)
if err != nil {
logging.V(5).Infof(
"GetRequiredPlugins: Could not determine plugin version for package %s with version %s",
packageName, packageVersion)
pkg.Name, pkg.Version)
return nil, nil
}
}
@ -437,16 +435,6 @@ func determinePluginDependency(
return &result, nil
}
// determinePackageLocation determines the location on disk of the package by running `python -m pip show <package>`
// and parsing the output.
func determinePackageLocation(virtualenv, cwd, packageName string) (string, error) {
b, err := runPythonCommand(virtualenv, cwd, "-m", "pip", "show", packageName)
if err != nil {
return "", err
}
return parseLocation(packageName, string(b))
}
func parseLocation(packageName, pipShowOutput string) (string, error) {
// We want the value of Location from the following output of `python -m pip show <packageName>`:
// $ python -m pip show pulumi-aws

View file

@ -142,3 +142,28 @@ func TestDeterminePluginVersion(t *testing.T) {
})
}
}
func TestDeterminePulumiPackages(t *testing.T) {
t.Run("empty", func(t *testing.T) {
cwd := t.TempDir()
_, err := runPythonCommand("", cwd, "-m", "venv", "venv")
assert.NoError(t, err)
packages, err := determinePulumiPackages("venv", cwd)
assert.NoError(t, err)
assert.Empty(t, packages)
})
t.Run("non-empty", func(t *testing.T) {
cwd := t.TempDir()
_, err := runPythonCommand("", cwd, "-m", "venv", "venv")
assert.NoError(t, err)
_, err = runPythonCommand("venv", cwd, "-m", "pip", "install", "pulumi-random")
assert.NoError(t, err)
packages, err := determinePulumiPackages("venv", cwd)
assert.NoError(t, err)
assert.NotEmpty(t, packages)
assert.Equal(t, 1, len(packages))
random := packages[0]
assert.Equal(t, "pulumi-random", random.Name)
assert.NotEmpty(t, random.Location)
})
}

View file

@ -117,7 +117,7 @@ class LocalWorkspace(Workspace):
break
path = os.path.join(self.work_dir, f"Pulumi{found_ext}")
writable_settings = {key: settings.__dict__[key] for key in settings.__dict__ if settings.__dict__[key] is not None}
with open(path, "w") as file:
with open(path, "w", encoding="utf-8") as file:
if found_ext == ".json":
json.dump(writable_settings, file, indent=4)
else:
@ -129,7 +129,7 @@ class LocalWorkspace(Workspace):
path = os.path.join(self.work_dir, f"Pulumi.{stack_settings_name}{ext}")
if not os.path.exists(path):
continue
with open(path, "r") as file:
with open(path, "r", encoding="utf-8") as file:
settings = json.load(file) if ext == ".json" else yaml.safe_load(file)
return StackSettings._deserialize(settings)
raise FileNotFoundError(f"failed to find stack settings file in workdir: {self.work_dir}")
@ -143,7 +143,7 @@ class LocalWorkspace(Workspace):
found_ext = ext
break
path = os.path.join(self.work_dir, f"Pulumi.{stack_settings_name}{found_ext}")
with open(path, "w") as file:
with open(path, "w", encoding="utf-8") as file:
if found_ext == ".json":
json.dump(settings._serialize(), file, indent=4)
else:
@ -490,7 +490,7 @@ def _load_project_settings(work_dir: str) -> ProjectSettings:
project_path = os.path.join(work_dir, f"Pulumi{ext}")
if not os.path.exists(project_path):
continue
with open(project_path, "r") as file:
with open(project_path, "r", encoding="utf-8") as file:
settings = json.load(file) if ext == ".json" else yaml.safe_load(file)
return ProjectSettings(**settings)
raise FileNotFoundError(f"failed to find project settings file in workdir: {work_dir}")

View file

@ -0,0 +1,23 @@
# Copyright 2016-2021, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class _Representable:
"""This mix-in improves the default `__repr__` to be more readable."""
def __repr__(self):
inputs = self.__dict__
fields = [f"{key}={inputs[key]!r}" for key in inputs] # pylint: disable=consider-using-dict-items
fields = ", ".join(fields)
return f"{self.__class__.__name__}({fields})"

View file

@ -32,6 +32,7 @@ from ._server import LanguageServer
from ._workspace import Workspace, PulumiFn, Deployment
from ..runtime.settings import _GRPC_CHANNEL_OPTIONS
from ..runtime.proto import language_pb2_grpc
from ._representable import _Representable
_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
@ -84,17 +85,11 @@ class UpdateSummary:
f"resource_changes={self.resource_changes!r}, config={self.config!r}, Deployment={self.Deployment!r})"
class BaseResult:
class BaseResult(_Representable):
def __init__(self, stdout: str, stderr: str):
self.stdout = stdout
self.stderr = stderr
def __repr__(self):
inputs = self.__dict__
fields = [f"{key}={inputs[key]!r}" for key in inputs] # pylint: disable=consider-using-dict-items
fields = ", ".join(fields)
return f"{self.__class__.__name__}({fields})"
class PreviewResult(BaseResult):
def __init__(self, stdout: str, stderr: str, change_summary: OpMap):
@ -647,13 +642,13 @@ def _create_log_file(command: str) -> Tuple[str, tempfile.TemporaryDirectory]:
filepath = os.path.join(log_dir.name, "eventlog.txt")
# Open and close the file to ensure it exists before we start polling for logs
with open(filepath, "w+"):
with open(filepath, "w+", encoding="utf-8"):
pass
return filepath, log_dir
def _watch_logs(filename: str, callback: OnEvent):
with open(filename) as f:
with open(filename, encoding="utf-8") as f:
while True:
line = f.readline()

View file

@ -17,6 +17,7 @@
from enum import Enum
from typing import Optional, List, Mapping, Any, MutableMapping
from ._representable import _Representable
class OpType(str, Enum):
@ -43,13 +44,8 @@ class OpType(str, Enum):
OpMap = MutableMapping[OpType, int]
class BaseEvent:
def __repr__(self):
# pylint: disable=duplicate-code
inputs = self.__dict__
fields = [f"{key}={inputs[key]!r}" for key in inputs] # pylint: disable=consider-using-dict-items
fields = ", ".join(fields)
return f"{self.__class__.__name__}({fields})"
class BaseEvent(_Representable):
pass
class CancelEvent(BaseEvent):

View file

@ -337,15 +337,10 @@ def _create_provider_resource(ref: str) -> ProviderResource:
otherwise return an instance of DependencyProviderResource.
"""
urn, _ = _parse_resource_reference(ref)
urn_parts = urn.split("::")
urn_name = urn_parts[3]
qualified_type = urn_parts[2]
typ = qualified_type.split("$")[-1]
typ_parts = typ.split(":")
typ_name = typ_parts[2] if len(typ_parts) > 2 else ""
resource_package = rpc.get_resource_package(typ_name, version="")
urn_parts = pulumi.urn._parse_urn(urn)
resource_package = rpc.get_resource_package(urn_parts.typ_name, version="")
if resource_package is not None:
return cast(ProviderResource, resource_package.construct_provider(urn_name, typ, urn))
return cast(ProviderResource, resource_package.construct_provider(
urn_parts.urn_name, urn_parts.typ, urn))
return DependencyProviderResource(ref)

View file

@ -24,6 +24,7 @@ from .runtime.resource import get_resource, register_resource, register_resource
convert_providers
from .runtime.settings import get_root_resource
from .output import _is_prompt, _map_input, _map2_input, T, Output
from . import urn as urn_util
if TYPE_CHECKING:
from .output import Input, Inputs
@ -985,12 +986,11 @@ class DependencyProviderResource(ProviderResource):
def __init__(self, ref: str) -> None:
ref_urn, ref_id = _parse_resource_reference(ref)
urn_parts = ref_urn.split("::")
qualified_type = urn_parts[2]
typ = qualified_type.split("$")[-1]
typ_parts = typ.split(":")
# typ will be "pulumi:providers:<package>" and we want the last part.
pkg = typ_parts[2] if len(typ_parts) > 2 else ""
urn_parts = urn_util._parse_urn(ref_urn)
# `typ` will be `pulumi:providers:<package>` and we want the
# last part, which normally parses as `typ_name`.
pkg = urn_parts.typ_name
super().__init__(pkg=pkg, name="", props={}, opts=None, dependency=True)

View file

@ -21,7 +21,7 @@ import json
import os
# default to an empty map for config.
CONFIG: Dict[str, Any] = dict()
CONFIG: Dict[str, Any] = {}
# default to an empty set for config secret keys.
_SECRET_KEYS: Set[str] = set()
@ -56,7 +56,7 @@ def get_config_env() -> Dict[str, Any]:
if 'PULUMI_CONFIG' in os.environ:
env_config = os.environ['PULUMI_CONFIG']
return json.loads(env_config)
return dict()
return {}
def get_config_env_key(k: str) -> str:

View file

@ -139,7 +139,7 @@ class MockMonitor:
def __init__(self, mocks: Mocks):
self.mocks = mocks
self.resources = dict()
self.resources = {}
def make_urn(self, parent: str, type_: str, name: str) -> str:
if parent != "":

View file

@ -26,6 +26,7 @@ from .rpc_manager import RPC_MANAGER
from .settings import handle_grpc_error
from ..output import Output
from .. import _types
from .. import urn as urn_util
if TYPE_CHECKING:
@ -194,9 +195,8 @@ def get_resource(res: 'Resource',
transform_using_type_metadata = typ is not None
# Extract the resource type from the URN.
urn_parts = urn.split("::")
qualified_type = urn_parts[2]
ty = qualified_type.split("$")[-1]
urn_parts = urn_util._parse_urn(urn)
ty = urn_parts.typ
# Initialize the URN property on the resource.
(resolve_urn, res.__dict__["urn"]) = resource_output(res)

View file

@ -29,6 +29,7 @@ import six
from . import known_types, settings
from .. import log
from .. import _types
from .. import urn as urn_util
if TYPE_CHECKING:
from ..output import Inputs, Input, Output
@ -399,15 +400,12 @@ def deserialize_resource(ref_struct: struct_pb2.Struct, keep_unknowns: Optional[
urn = ref_struct["urn"]
version = ref_struct["packageVersion"] if "packageVersion" in ref_struct else ""
urn_parts = urn.split("::")
urn_name = urn_parts[3]
qualified_type = urn_parts[2]
typ = qualified_type.split("$")[-1]
typ_parts = typ.split(":")
pkg_name = typ_parts[0]
mod_name = typ_parts[1] if len(typ_parts) > 1 else ""
typ_name = typ_parts[2] if len(typ_parts) > 2 else ""
urn_parts = urn_util._parse_urn(urn)
urn_name = urn_parts.urn_name
typ = urn_parts.typ
pkg_name = urn_parts.pkg_name
mod_name = urn_parts.mod_name
typ_name = urn_parts.typ_name
is_provider = pkg_name == "pulumi" and mod_name == "providers"
if is_provider:
@ -881,7 +879,7 @@ class ResourcePackage(ABC):
pass
_RESOURCE_PACKAGES: Dict[str, List[ResourcePackage]] = dict()
_RESOURCE_PACKAGES: Dict[str, List[ResourcePackage]] = {}
def register_resource_package(pkg: str, package: ResourcePackage):
@ -922,7 +920,7 @@ class ResourceModule(ABC):
pass
_RESOURCE_MODULES: Dict[str, List[ResourceModule]] = dict()
_RESOURCE_MODULES: Dict[str, List[ResourceModule]] = {}
def _module_key(pkg: str, mod: str) -> str:

View file

@ -127,7 +127,7 @@ class Stack(ComponentResource):
super().__init__('pulumi:pulumi:Stack', name, None, None)
# Invoke the function while this stack is active and then register its outputs.
self.outputs = dict()
self.outputs = {}
set_root_resource(self)
try:
func()

View file

@ -0,0 +1,41 @@
# Copyright 2016-2021, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections import namedtuple
_UrnParts = namedtuple('_UrnParts', ['urn_name',
'typ',
'pkg_name',
'mod_name',
'typ_name'])
def _parse_urn(urn: str) -> _UrnParts:
try:
urn_parts = urn.split('::')
urn_name = urn_parts[3] if len(urn_parts) >= 4 else ""
qualified_type = urn_parts[2]
typ = qualified_type.split("$")[-1]
typ_parts = typ.split(":")
pkg_name = typ_parts[0]
mod_name = typ_parts[1] if len(typ_parts) > 1 else ""
typ_name = typ_parts[2] if len(typ_parts) > 2 else ""
return _UrnParts(urn_name=urn_name,
typ=typ,
pkg_name=pkg_name,
mod_name=mod_name,
typ_name=typ_name)
except Exception as e:
raise ValueError(f'Cannot parse URN: {urn}') from e

View file

@ -0,0 +1,34 @@
# Copyright 2016-2021, Pulumi Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from pulumi import urn as urn_util
def test_parse_urn_with_name():
res = urn_util._parse_urn('urn:pulumi:stack::project::pulumi:providers:aws::default_4_13_0')
assert res.urn_name == 'default_4_13_0'
assert res.typ == 'pulumi:providers:aws'
assert res.pkg_name == 'pulumi'
assert res.mod_name == 'providers'
assert res.typ_name == 'aws'
def test_parse_urn_without_name():
res = urn_util._parse_urn('urn:pulumi:stack::project::pulumi:providers:aws')
assert res.urn_name == ''
assert res.typ == 'pulumi:providers:aws'
assert res.pkg_name == 'pulumi'
assert res.mod_name == 'providers'
assert res.typ_name == 'aws'

View file

@ -0,0 +1,353 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

View file

@ -0,0 +1,41 @@
// Copyright 2016-2021, Pulumi Corporation. All rights reserved.
using Pulumi;
class ComponentArgs : ResourceArgs
{
[Input("first")]
public Input<string> First { get; set; } = null!;
[Input("second")]
public Input<string> Second { get; set; } = null!;
}
class Component : ComponentResource
{
public Component(string name, ComponentArgs args, ComponentResourceOptions? opts = null)
: base("testcomponent:index:Component", name, args, opts, remote: true)
{
}
public Output<GetMessageResult> GetMessage(GetMessageArgs args)
=> Deployment.Instance.Call<GetMessageResult>("testcomponent:index:Component/getMessage", args, this);
}
public class GetMessageArgs : CallArgs
{
[Input("name")]
public Input<string> Name { get; set; } = null!;
}
[OutputType]
public sealed class GetMessageResult
{
public readonly string Message;
[OutputConstructor]
private GetMessageResult(string message)
{
Message = message;
}
}

View file

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,16 @@
// Copyright 2016-2021, Pulumi Corporation. All rights reserved.
using Pulumi;
class MyStack : Stack
{
[Output("message")]
public Output<string> Message { get; set; }
public MyStack()
{
var component = new Component("component", new ComponentArgs { First = "Hello", Second = "World" });
var result = component.GetMessage(new GetMessageArgs { Name = "Alice" });
Message = result.Apply(v => v.Message);
}
}

View file

@ -0,0 +1,9 @@
// Copyright 2016-2021, Pulumi Corporation. All rights reserved.
using System.Threading.Tasks;
using Pulumi;
class Program
{
static Task<int> Main() => Deployment.RunAsync<MyStack>();
}

Some files were not shown because too many files have changed in this diff Show more