[developer-docs] Add links + a broad arch diagram (#7856)

- Add links within the resource registration docs
- Add a broad-strokes architectural diagram to the overview
- Add a `clean` target to the Makefile
- Expand the "Building" docs a bit
This commit is contained in:
Pat Gavlin 2021-08-27 10:55:06 -07:00 committed by GitHub
parent 96e6eb2592
commit a5a818b802
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 176 additions and 27 deletions

View file

@ -9,7 +9,7 @@ html: Makefile graphics
pdf: Makefile graphics
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: graphics Makefile
.PHONY: graphics clean Makefile
SVG_FILES = \
providers/resource-lifecycle.svg \
@ -26,3 +26,6 @@ SVG_FILES = \
plantuml -tsvg $<
graphics: Makefile $(SVG_FILES)
clean:
rm -rf $(BUILDDIR)/*

View file

@ -2,11 +2,22 @@
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
1. [The deployment engine](#the-deployment-engine)
2. [State storage backends](#state-storage-backends)
3. [Language SDKs](#language-sdks)
4. [Resource providers](#resource-providers)
5. [Package schemas and code generators](#package-schemas-and-code-generators)
These components interact to provide the feature set exposed by the Pulumi CLI and SDKs, including desired-state
deployments using standard programming languages, remote state storage and secret encryption, and the ability to bridge
the gap between existing and Pulumi-managed infrastructure.
These components are composed like so:
![Pulumi CLI](./pulumi-cli.svg)
In most cases, the language plugin, CLI, and resource providers will all live in separate processes, and each instance
of a resource provider will live in its own process.
## The Deployment Engine

View file

@ -0,0 +1,68 @@
<?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="379px" preserveAspectRatio="none" style="width:837px;height:379px;background:#FFFFFF;" version="1.1" viewBox="0 0 837 379" width="837px" zoomAndPan="magnify"><defs><filter height="300%" id="f19xh40rheasqw" 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=[6ad7c0b688d9e902153dd4de2b6da276]
cluster plugin--><polygon fill="#FFFFFF" filter="url(#f19xh40rheasqw)" points="274,16,284,6,533,6,533,110,523,120,274,120,274,16" style="stroke:#000000;stroke-width:1.5;"/><line style="stroke:#000000;stroke-width:1.5;" x1="523" x2="533" y1="16" y2="6"/><line style="stroke:#000000;stroke-width:1.5;" x1="274" x2="523" y1="16" y2="16"/><line style="stroke:#000000;stroke-width:1.5;" x1="523" x2="523" y1="16" y2="120"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="119" x="340" y="32.5352">Language Plugin</text><!--MD5=[e3a89b72019d8d69b73b0a9ebb84eda6]
cluster cli--><polygon fill="#FFFFFF" filter="url(#f19xh40rheasqw)" points="143,154,153,144,820,144,820,236,810,246,143,246,143,154" style="stroke:#000000;stroke-width:1.5;"/><line style="stroke:#000000;stroke-width:1.5;" x1="810" x2="820" y1="154" y2="144"/><line style="stroke:#000000;stroke-width:1.5;" x1="143" x2="810" y1="154" y2="154"/><line style="stroke:#000000;stroke-width:1.5;" x1="810" x2="810" y1="154" y2="246"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="79" x="438" y="170.5352">Pulumi CLI</text><!--MD5=[37555286e97c6ca40d22b1bfaf1e2f78]
cluster providers--><polygon fill="#FFFFFF" filter="url(#f19xh40rheasqw)" points="16,280,26,270,718,270,718,362,708,372,16,372,16,280" style="stroke:#000000;stroke-width:1.5;"/><line style="stroke:#000000;stroke-width:1.5;" x1="708" x2="718" y1="280" y2="270"/><line style="stroke:#000000;stroke-width:1.5;" x1="16" x2="708" y1="280" y2="280"/><line style="stroke:#000000;stroke-width:1.5;" x1="708" x2="708" y1="280" y2="372"/><text fill="#000000" font-family="sans-serif" font-size="14" font-weight="bold" lengthAdjust="spacing" textLength="138" x="294" y="296.5352">Resource Providers</text><!--MD5=[bd28a176169e8702965fc6459f094f8d]
entity langhost--><ellipse cx="490" cy="75" fill="#FEFECE" filter="url(#f19xh40rheasqw)" rx="8" ry="8" style="stroke:#A80036;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="36" x="472" y="105.5352">gRPC</text><!--MD5=[1344c822e198f17c7a138ae37b519ce9]
entity sdk--><rect fill="#FEFECE" filter="url(#f19xh40rheasqw)" height="46.4883" style="stroke:#A80036;stroke-width:1.5;" width="138" x="290" y="52"/><rect fill="#FEFECE" height="10" style="stroke:#A80036;stroke-width:1.5;" width="15" x="408" y="57"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="406" y="59"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="406" y="63"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="98" x="305" y="85.5352">Language SDK</text><!--MD5=[f50d41480d2572d7a33322ea46f73a65]
entity resmon--><ellipse cx="359" cy="207" fill="#FEFECE" filter="url(#f19xh40rheasqw)" rx="8" ry="8" style="stroke:#A80036;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="36" x="341" y="237.5352">gRPC</text><!--MD5=[cb028c5091c687ec367cd0cbfd70389f]
entity engine--><rect fill="#FEFECE" filter="url(#f19xh40rheasqw)" height="46.4883" style="stroke:#A80036;stroke-width:1.5;" width="173" x="403.5" y="184"/><rect fill="#FEFECE" height="10" style="stroke:#A80036;stroke-width:1.5;" width="15" x="556.5" y="189"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="554.5" y="191"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="554.5" y="195"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="133" x="418.5" y="217.5352">Deployment engine</text><!--MD5=[4e8ecd94af36cce41665c9f079adf9fd]
entity backend--><rect fill="#FEFECE" filter="url(#f19xh40rheasqw)" height="46.4883" style="stroke:#A80036;stroke-width:1.5;" width="192" x="612" y="184"/><rect fill="#FEFECE" height="10" style="stroke:#A80036;stroke-width:1.5;" width="15" x="784" y="189"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="782" y="191"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="782" y="195"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="152" x="627" y="217.5352">State storage backend</text><!--MD5=[97c4ad735e832b0a87d5a2aef4ec1b90]
entity codegen--><rect fill="#FEFECE" filter="url(#f19xh40rheasqw)" height="46.4883" style="stroke:#A80036;stroke-width:1.5;" width="155" x="159.5" y="184"/><rect fill="#FEFECE" height="10" style="stroke:#A80036;stroke-width:1.5;" width="15" x="294.5" y="189"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="292.5" y="191"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="292.5" y="195"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="115" x="174.5" y="217.5352">Code generators</text><!--MD5=[62cc4166db310ca44a141886713fd6cd]
entity provider--><ellipse cx="506" cy="333" fill="#FEFECE" filter="url(#f19xh40rheasqw)" rx="8" ry="8" style="stroke:#A80036;stroke-width:1.5;"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="36" x="488" y="363.5352">gRPC</text><!--MD5=[f50278905982483810086d91fb8fa489]
entity schemas--><rect fill="#FEFECE" filter="url(#f19xh40rheasqw)" height="46.4883" style="stroke:#A80036;stroke-width:1.5;" width="159" x="32.5" y="310"/><rect fill="#FEFECE" height="10" style="stroke:#A80036;stroke-width:1.5;" width="15" x="171.5" y="315"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="169.5" y="317"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="169.5" y="321"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="119" x="47.5" y="343.5352">Package schemas</text><!--MD5=[af3cd302a2b94eb7b444b626445d5884]
entity mlcs--><rect fill="#FEFECE" filter="url(#f19xh40rheasqw)" height="46.4883" style="stroke:#A80036;stroke-width:1.5;" width="235" x="226.5" y="310"/><rect fill="#FEFECE" height="10" style="stroke:#A80036;stroke-width:1.5;" width="15" x="441.5" y="315"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="439.5" y="317"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="439.5" y="321"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="195" x="241.5" y="343.5352">Multi-language components</text><!--MD5=[20621550007b0095ffa57af918ba4be8]
entity resources--><rect fill="#FEFECE" filter="url(#f19xh40rheasqw)" height="46.4883" style="stroke:#A80036;stroke-width:1.5;" width="152" x="550" y="310"/><rect fill="#FEFECE" height="10" style="stroke:#A80036;stroke-width:1.5;" width="15" x="682" y="315"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="680" y="317"/><rect fill="#FEFECE" height="2" style="stroke:#A80036;stroke-width:1.5;" width="4" x="680" y="321"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="112" x="565" y="343.5352">Cloud resources</text><!--MD5=[c83b99234783bf3a067a09561fd85385]
link resmon to engine--><path d="M368.21,207 C379.95,207 391.68,207 403.42,207 " fill="none" id="resmon-engine" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[98cdd689628792af5a8a660ccc4dffbf]
link sdk to resmon--><path d="M359,98.05 C359,125.17 359,170.32 359,192.66 " fill="none" id="sdk-to-resmon" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="359,197.82,363,188.82,359,192.82,355,188.82,359,197.82" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[d52cf39a665d43a4a7d453d21ffdc651]
reverse link langhost to engine--><path d="M490,89.29 C490,111.61 490,156.83 490,183.97 " fill="none" id="langhost-backto-engine" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="490,84.13,486,93.13,490,89.13,494,93.13,490,84.13" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[e20dc6a04c5d42d30c66420d5b1444cb]
link engine to backend--><path d="M576.86,207 C586.82,207 596.78,207 606.74,207 " fill="none" id="engine-to-backend" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="611.95,207,602.95,203,606.95,207,602.95,211,611.95,207" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[042dc1ddbbd8cfb6e2feb7f3a04ccb5f]
link provider to mlcs--><path d="M496.66,333 C485.01,333 473.35,333 461.7,333 " fill="none" id="provider-mlcs" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[aebd7ec848a828c3343ccead83a346e8]
link provider to resources--><path d="M515.38,333 C526.9,333 538.42,333 549.95,333 " fill="none" id="provider-resources" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[3853d8b64fd7062d32cb72c7d7ab69e6]
link engine to provider--><path d="M492.86,230.17 C496.18,255.88 501.54,297.43 504.27,318.63 " fill="none" id="engine-to-provider" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="504.94,323.8,507.7493,314.3603,504.297,318.8415,499.8158,315.3892,504.94,323.8" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[dbb39786d704e74d101b7253a3f8c0d1]
reverse link resmon to mlcs--><path d="M357.39,221.29 C354.83,242.44 349.81,283.98 346.69,309.72 " fill="none" id="resmon-backto-mlcs" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="358.02,216.14,352.9675,224.5941,357.4192,221.1038,360.9096,225.5554,358.02,216.14" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[fb8092344ec2ce39b6aa9e0be2593080]
@startuml
node "Language Plugin" as plugin {
interface gRPC as langhost
component "Language SDK" as sdk
}
node "Pulumi CLI" as cli {
interface gRPC as resmon
component "Deployment engine" as engine
component "State storage backend" as backend
component "Code generators" as codegen
resmon - engine
sdk -down-> resmon
engine -up-> langhost
engine -right-> backend
}
node "Resource Providers" as providers {
interface gRPC as provider
component "Package schemas" as schemas
component "Multi-language components" as mlcs
component "Cloud resources" as resources
provider - mlcs
provider - resources
engine -down-> provider
mlcs -up-> resmon
}
@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: 11 KiB

View file

@ -0,0 +1,37 @@
@startuml
node "Language Plugin" as plugin {
interface gRPC as langhost
component "Language SDK" as sdk
}
node "Pulumi CLI" as cli {
interface gRPC as resmon
component "Deployment engine" as engine
component "State storage backend" as backend
component "Code generators" as codegen
resmon - engine
sdk -down-> resmon
engine -up-> langhost
engine -right-> backend
}
node "Resource Providers" as providers {
interface gRPC as provider
component "Package schemas" as schemas
component "Multi-language components" as mlcs
component "Cloud resources" as resources
provider - mlcs
provider - resources
engine -down-> provider
mlcs -up-> resmon
}
@enduml

View file

@ -13,12 +13,12 @@ methods to perform it. After the action completes, the engine returns the new st
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
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
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
@ -32,7 +32,7 @@ When the resource monitor receives a resource registration, it does the followin
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
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.
@ -98,7 +98,7 @@ 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
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
@ -116,32 +116,32 @@ When the step generator receives a `RegisterResourceEvent`, it does the followin
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.
4. If the event indicates that the resource should be imported, issue an `ImportStep` to the [step exectuor] 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.
7. If the resource has no existing state, it is being created. Issue a `CreateStep` to the [step exectuor] 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.
9. If the resource has no changes, issue a `SameStep` to the [step exectuor] and return.
10. If the resource is not being replaced, issue an `UpdateStep` to the [step exectuor] 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.
`CreateStep` and a `DeleteStep` to the [step exectuor] 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.
issue a sequence of `DeleteStep`s followed by a single `CreateStep` to the [step exectuor].
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.
generator moves on to process the next `RegisterResourceEvent`. It is the responsibility of the [step exectuor] 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
@ -149,7 +149,7 @@ for deletion by first sorting the list of resources to delete using the topologi
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
In lieu of tracking per-step dependencies and orienting the [step exectuor] 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"
@ -170,7 +170,7 @@ Translated to a resource dependency graph:
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.
generator reverses the list and then issues each sublist to the [step exectuor].
### Resource Diffing
@ -214,12 +214,12 @@ In these cases, neither B nor D would need to be deleted before A could be delet
## 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
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
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
@ -253,3 +253,7 @@ The diagram below illustrates the sequence of events that occurs when a multi-la
registration of the component's children is elided.
![Multi-language component construction](./construct.svg)
[resource monitor]: #the-resource-monitor
[step generator]: #the-step-generator
[step executor]: #the-step-executor

View file

@ -1,9 +1,13 @@
# Building the Docs
This documentation is generated using [Sphinx] and authored in Markdown. Markdown support for [Sphinx] is provided by
[MyST]. [MyST] provides a number of small syntax extensions to support declaring ReStructuredText directives; see
[the MyST syntax guide](https://myst-parser.readthedocs.io/en/latest/syntax/syntax.html) for details.
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:
1. Install [PlantUML]. On macOS, this can be done via `brew install plantuml`.
2. Install the requirements for [Sphinx]:
```bash
$ pip install requirements.txt
@ -17,3 +21,19 @@ In order to build the devloper documentation:
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`.
Note that Sphinx doesn't do a great job of rebuilding output files if only the table-of-contents has changed. If you
change the table of contents, you may need to clean the output directory in order to see the effects of your changes:
```bash
$ make clean
```
## Notes on Style
- Do use appropriate links wherever possible. Learn to use [header anchors](https://myst-parser.readthedocs.io/en/latest/syntax/optional.html#auto-generated-header-anchors).
- If a particular link destination is referenced multiple times, prefer [shortcut reference links](https://spec.commonmark.org/0.29/#shortcut-reference-link).
[Sphinx]: https://www.sphinx-doc.org/en/master/index.html
[MyST]: https://myst-parser.readthedocs.io/en/latest/index.html
[PlantUML]: https://plantuml.com

View file

@ -53,3 +53,9 @@ html_theme = 'sphinx_rtd_theme'
# 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']
# -- MyST configuration ------------------------------------------------------
# Enable auto-generated header anchors.
myst_heading_anchors = 5

View file

@ -102,7 +102,7 @@ contents).
#### Resource References
A `ResourceReference` represents a reference to a [Pulumi resource](#Resources). Although
A `ResourceReference` represents a reference to a [Pulumi resource](#resources). Although
all that is necessary to uniquely identify a resource is its URN, a `ResourceReference`
also carries the resource's ID (if it is a [custom resource](#custom-resources)) and the
version of the provider that manages the resource. If the contents of the referenced