Start in on developer documentation. (#7839)

Developer documentation is written in Markdown and can be built into
HTML, PDF, etc. using Sphinx. Diagrams are written in PlantUML and
rendered as SVGs. All developer docs live in the `developer-docs` folder
under the root of the repository.
This commit is contained in:
Pat Gavlin 2021-08-25 15:18:13 -07:00 committed by GitHub
parent 01f5289219
commit 98f73cf1ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1024 additions and 49 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.9"
install:
- requirements: developer-docs/requirements.txt

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 appropraite
`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 verison, 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::default_4_16_0::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,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