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.
22
.readthedocs.yaml
Normal 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
|
||||
|
||||
|
3
Makefile
|
@ -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
|
@ -0,0 +1 @@
|
|||
_build
|
28
developer-docs/Makefile
Normal 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)
|
23
developer-docs/architecture/construct.svg
Normal file
After Width: | Height: | Size: 6.5 KiB |
13
developer-docs/architecture/construct.uml
Normal 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
|
33
developer-docs/architecture/create.svg
Normal file
After Width: | Height: | Size: 11 KiB |
23
developer-docs/architecture/create.uml
Normal 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
|
35
developer-docs/architecture/delete-before-replace-graph.svg
Normal 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 |
14
developer-docs/architecture/delete-before-replace-graph.uml
Normal 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
|
37
developer-docs/architecture/delete-before-replace.svg
Normal file
After Width: | Height: | Size: 14 KiB |
27
developer-docs/architecture/delete-before-replace.uml
Normal 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
|
35
developer-docs/architecture/import.svg
Normal file
After Width: | Height: | Size: 12 KiB |
25
developer-docs/architecture/import.uml
Normal 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
|
19
developer-docs/architecture/overview.md
Normal 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
|
40
developer-docs/architecture/replace.svg
Normal file
After Width: | Height: | Size: 16 KiB |
30
developer-docs/architecture/replace.uml
Normal 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
|
255
developer-docs/architecture/resource-registration.md
Normal 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)
|
33
developer-docs/architecture/same.svg
Normal file
After Width: | Height: | Size: 11 KiB |
23
developer-docs/architecture/same.uml
Normal 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
|
35
developer-docs/architecture/update.svg
Normal file
After Width: | Height: | Size: 12 KiB |
25
developer-docs/architecture/update.uml
Normal 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
|
@ -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
|
@ -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
|
@ -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
|
||||
```
|
|
@ -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
|
||||
|
82
developer-docs/providers/resource-lifecycle.svg
Normal 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 |
52
developer-docs/providers/resource-lifecycle.uml
Normal 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
|
4
developer-docs/requirements.txt
Normal 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
|
|
@ -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
|
Before Width: | Height: | Size: 29 KiB |