provider-upgrade
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUpgrading Pulumi Providers
升级Pulumi Provider
The Principle
核心原则
A provider upgrade is a translation, not a change request.
The user's infrastructure intent hasn't changed - they still want the same bucket, the
same function, the same cluster. What changed is how the provider's API expresses that
intent. Your job is to translate their existing code into the new API so that Pulumi sees
no difference between what the code says and what already exists.
There are four layers to keep in mind:
- User intent - what the user wants in the cloud (unchanged during an upgrade)
- Code - how the program expresses that intent using the provider API (may need updating)
- Pulumi state - Pulumi's stored representation of what exists (may need reconciliation)
- Real cloud - the actual infrastructure (should not change during an upgrade)
During an upgrade, layers 2 and 3 may need to change so that they continue to correctly
represent the unchanged layers 1 and 4.
A correct translation produces zero diff. The Pulumi engine doesn't have a concept of
"upgrade" - it just compares goal state (your code) against actual state (the state file)
and reconciles. If the translation is correct, those two states match and nothing happens.
If you see a diff, either your translation is wrong, or something beyond a code change is
needed (import, alias, manual step). In all cases, the diff is a problem to solve, not a
consequence to accept.
Provider升级是一次翻译,而非变更请求。
用户的基础设施意图并未改变——他们仍然需要相同的存储桶、相同的函数、相同的集群。变化的是Provider的API如何表达该意图。你的工作是将现有代码转换为新API,使Pulumi认为代码定义的状态与已存在的状态完全一致。
需要牢记四个层级:
- 用户意图 - 用户希望在云环境中实现的目标(升级期间保持不变)
- 代码 - 程序使用Provider API表达意图的方式(可能需要更新)
- Pulumi状态 - Pulumi存储的现有基础设施表示(可能需要协调)
- 实际云环境 - 真实存在的基础设施(升级期间不应改变)
升级过程中,层级2和3可能需要调整,以继续正确表示保持不变的层级1和4。
正确的转换应产生零差异。Pulumi引擎没有“升级”的概念——它只是比较目标状态(你的代码)与实际状态(状态文件)并进行协调。如果转换正确,这两个状态将匹配,不会产生任何操作。如果出现差异,要么是转换有误,要么是需要代码变更之外的操作(导入、别名、手动步骤)。无论哪种情况,差异都是需要解决的问题,而非必须接受的结果。
The Core Loop
核心流程
mermaid
flowchart TD
A[Bump version] --> B[Run preview with env vars]
B --> C{Clean?}
C -->|Yes| D[Create PR]
C -->|No| E[Diff Checkpoint: categorize every diff]
E --> F{Any Category A?}
F -->|Yes| G[Fix wrong translations]
G --> B
F -->|No| H{Any Category B?}
H -->|Yes| I[Investigate with toolbox]
I --> J[Fix or document]
J --> B
H -->|No| D- Bump the provider dependency
- Preview with required CLI flags
- Diff Checkpoint - categorize every non-resource (see next section)
same - Fix Category A - code changes that didn't produce
same - Investigate Category B - diffs on resources you didn't change
- Repeat until clean or remaining diffs are fully investigated
- Create PR with upgrade summary
mermaid
flowchart TD
A[Bump version] --> B[Run preview with env vars]
B --> C{Clean?}
C -->|Yes| D[Create PR]
C -->|No| E[Diff Checkpoint: categorize every diff]
E --> F{Any Category A?}
F -->|Yes| G[Fix wrong translations]
G --> B
F -->|No| H{Any Category B?}
H -->|Yes| I[Investigate with toolbox]
I --> J[Fix or document]
J --> B
H -->|No| D- 升级 Provider依赖版本
- 预览 使用所需的CLI标志
- 差异检查点 - 对每个非状态的资源进行分类(见下一章节)
same - 修复A类问题 - 未产生状态的代码变更
same - 调查B类问题 - 未修改代码的资源出现的差异
- 重复 直到预览无差异或剩余差异已完全调查清楚
- 创建PR 附带升级总结
The Diff Checkpoint
差异检查点
This is the most important section. Run this after EVERY preview.
For each non- resource, answer one question:
"Did any of my code changes affect this resource - directly or indirectly?"
same"Directly" means you edited the resource block itself. "Indirectly" means you changed
something that feeds into this resource - a shared variable, an output from another
resource, a helper function, a default value, or a resource that this one depends on.
If your changes could have altered what Pulumi computes for this resource, it's Category A.
Then follow the category that applies.
这是最重要的章节。每次预览后都要执行此步骤。
对于每个非状态的资源,回答一个问题:
“我的代码变更是否直接或间接影响了该资源?”
same“直接”指你编辑了资源块本身。“间接”指你修改了影响该资源的内容——共享变量、其他资源的输出、辅助函数、默认值,或该资源依赖的其他资源。如果你的变更可能改变Pulumi为该资源计算的结果,则属于A类。
然后遵循对应类别的处理方式。
Category A: I changed code for this resource
A类:我修改了该资源的代码
Your code change was supposed to translate the same intent into the new API. If the
resource shows , your translation is correct. If it shows anything else, your
translation is wrong. Not "the diff is expected because I changed the code" - if the
change were semantically equivalent, there would be no diff.
sameI modified an existing resource and it shows :
updateYour rename, restructure, or value adjustment changed the meaning, not just the syntax.
The resource would show if the old and new code compiled to the same goal state.
The means they don't.
sameupdateAsk yourself: "If this rename were truly equivalent, the resource would show .
It doesn't. What is semantically different between my old code and my new code?"
sameCommon causes: the new property name maps to a different underlying field; the value
shape changed and your conversion lost or added information; a default value changed
in the new version and you need to explicitly set the old value; additional properties
now appear in the diff because the new provider version tracks fields it didn't before
(these need to be set explicitly to match the current state).
If the update includes properties you didn't change - new fields appearing, type
normalizations (string->number), additional defaults - that's the provider changing what
it tracks. But if the diff is there, WILL send those values to the cloud API.
Don't assume they're no-ops. Investigate each changed property.
pulumi upI added a new resource block and it shows :
createDuring an upgrade, a new resource block almost always represents infrastructure that
already exists in the cloud. The old provider managed it implicitly (as part of another
resource); the new provider needs an explicit resource. But the cloud object is already
there. Pulumi wants to create NEW infrastructure - that's not what you want.
The fix is , not . Tell Pulumi to adopt the existing cloud resource.
importcreateAsk yourself: "What cloud object does this new resource represent? Does it already
exist? How was it managed before the upgrade?"
typescript
// Wrong - creates duplicate infrastructure
const stage = new aws.apigateway.Stage("prodStage", { ... });
// Right - adopts the existing resource
const stage = new aws.apigateway.Stage("prodStage", { ... }, {
import: "<rest-api-id>/prod", // import ID format varies by resource type
});I removed a resource block and it shows :
deleteA in the preview means will call the provider's Delete API to
destroy or unconfigure this cloud resource. This is real destruction - not just state
cleanup. The cloud infrastructure still exists and is almost certainly still needed.
deletepulumi upThis is different from , which removes the resource from Pulumi's
tracking WITHOUT calling the provider's API. When a resource type is removed in a new
provider version, the correct approach is:
pulumi state delete- - manual step, removes from tracking only
pulumi state delete '<urn>' - Add replacement resources (if any) with imports - adopts the cloud state under new types
- Verify with preview
Do NOT leave a in the preview and proceed to PR creation. A delete that runs
via will destroy real infrastructure. If the resource must be removed from
state, document it as a manual step for the user.
deletepulumi upAsk yourself: "What cloud infrastructure does this resource manage? If runs
this delete, what gets destroyed or unconfigured?"
pulumi up你的代码变更本应将相同的意图转换为新API。如果资源显示,说明转换正确。如果显示其他状态,说明转换有误。不要认为“因为我修改了代码,所以差异是预期的”——如果变更在语义上等价,就不会产生差异。
same我修改了现有资源,它显示:
update你的重命名、重构或值调整改变了语义,而非仅语法。如果新旧代码编译后的目标状态一致,资源会显示。说明两者不一致。
sameupdate自问:“如果这次重命名真的等价,资源会显示。但它没有。我的旧代码和新代码在语义上有什么不同?”
same常见原因:新属性名称对应不同的底层字段;值的结构发生变化,转换过程中丢失或添加了信息;新版本的默认值已更改,你需要显式设置旧值;新Provider版本开始追踪之前未追踪的字段(这些字段需要显式设置以匹配当前状态)。
如果更新包含你未修改的属性——新字段出现、类型标准化(字符串→数字)、新增默认值——这是Provider追踪字段的变化。但只要存在差异,就会将这些值发送到云API。不要假设它们是无操作。请调查每个变更的属性。
pulumi up我添加了新的资源块,它显示:
create在升级过程中,新资源块几乎总是代表云环境中已存在的基础设施。旧Provider会隐式管理它(作为另一个资源的一部分);新Provider需要显式的资源定义。但云对象已经存在。Pulumi想要创建新的基础设施——这不是你想要的结果。
正确的修复方式是,而非。告诉Pulumi采用现有的云资源。
importcreate自问:“这个新资源代表哪个云对象?它是否已经存在?升级前它是如何被管理的?”
typescript
// 错误 - 创建重复基础设施
const stage = new aws.apigateway.Stage("prodStage", { ... });
// 正确 - 采用现有资源
const stage = new aws.apigateway.Stage("prodStage", { ... }, {
import: "<rest-api-id>/prod", // 导入ID格式因资源类型而异
});我删除了资源块,它显示:
delete预览中的意味着将调用Provider的Delete API来销毁或取消配置该云资源。这是真实的销毁操作——而非仅清理状态。云基础设施仍然存在,并且几乎可以肯定仍被需要。
deletepulumi up这与不同,后者仅将资源从Pulumi的追踪中移除,而不会调用Provider的API。当新Provider版本移除了某个资源类型时,正确的做法是:
pulumi state delete- - 手动步骤,仅从追踪中移除
pulumi state delete '<urn>' - 添加带导入配置的替代资源(如有)——采用云状态并使用新类型
- 通过预览验证
不要在预览中保留并继续创建PR。通过执行的删除操作会销毁真实的基础设施。如果必须从状态中移除资源,请将其记录为用户需要执行的手动步骤。
deletepulumi up自问:“该资源管理的是哪些云基础设施?如果执行此删除操作,会销毁或取消配置什么?”
pulumi upCategory B: I didn't change code for this resource
B类:我未修改该资源的代码
This diff was not caused by your code changes. It comes from the provider version change
itself - a different default, a changed state representation, or a behavioral difference.
Read and investigate.
references/diagnostic-toolbox.mdThese diffs might be:
- Fixable with code - set an explicit value for a changed default, add an alias
- A documented no-op - the upgrade guide says it resolves on without affecting real infrastructure. This classification REQUIRES a citation from the upgrade guide or provider documentation. Your own judgment that "this looks like a no-op" is not sufficient - the user is trusting you to distinguish real infrastructure changes from artifacts, and getting it wrong means unexpected changes to their cloud.
pulumi up - Requiring manual steps - state removal + reimport, documented for the user
- Unknown - present what you've found to the user and ask for guidance
此差异并非由你的代码变更引起,而是来自Provider版本变更本身——默认值变化、状态表示变更或行为差异。请阅读并进行调查。
references/diagnostic-toolbox.md这些差异可能是:
- 可通过代码修复 - 为变更的默认值设置显式值、添加别名
- 有文档记录的无操作 - 升级指南说明在后会自动解决,不会影响真实基础设施。此分类必须引用升级指南或Provider文档中的内容。仅靠你判断“这看起来是无操作”是不够的——用户信任你区分真实基础设施变更和伪差异,判断错误会导致云环境出现意外变更。
pulumi up - 需要手动步骤 - 状态移除+重新导入,为用户记录步骤
- 未知 - 将你的发现告知用户并寻求指导
Category C: Provider version bump
C类:Provider版本升级
An on showing only a version change is the one
expected diff. Verify no other properties changed on the provider resource.
updatepulumi:providers:{name}pulumi:providers:{name}updateAfter categorizing
分类完成后
Completeness check: Every resource in the preview that shows any non- state
must appear in your checkpoint - including resources with annotations,
even if they don't have an explicit create/update/delete marker. If you didn't list it,
your checkpoint is incomplete. Go back and categorize the missing resources.
same[diff: ...]Evidence requirement for accepted diffs: If you want to accept any diff as "OK"
(not fix it), you need evidence - whether it's Category A or Category B. "I believe the
API treats these equivalently" or "this looks like state reconciliation" is not evidence.
Acceptable evidence: the upgrade guide documents it, a GitHub issue confirms it, or the
provider documentation explains the behavior. If you can't find evidence, either fix the
diff or flag it to the user.
Ordering: Fix all Category A issues before investigating Category B. Your code
corrections will change the preview output, so investigating Category B diffs first wastes
effort. Fix your own mistakes first, re-preview, then look at what remains.
No or in the final preview. If a delete or replace remains when
you're ready to create a PR, stop. A delete means will destroy cloud
infrastructure. A replace means it will destroy and recreate. These are never acceptable
as "remaining diffs" - they must be resolved (via code fix, alias, or documented manual
steps) before proceeding.
deletereplacepulumi up完整性检查: 预览中所有显示非状态的资源都必须出现在你的检查点中——包括带有注释的资源,即使它们没有显式的create/update/delete标记。如果有遗漏,你的检查点不完整。请返回并对缺失的资源进行分类。
same[diff: ...]接受差异的证据要求: 如果你想接受任何差异为“可忽略”(不修复),需要提供证据——无论属于A类还是B类。“我认为API会将这些视为等价”或“这看起来是状态协调”不属于有效证据。可接受的证据包括:升级指南中有记录、GitHub问题已确认,或Provider文档解释了该行为。如果找不到证据,请修复差异或向用户标记该问题。
优先级: 在调查B类差异之前,先修复所有A类问题。你的代码修正会改变预览输出,因此先调查B类差异会浪费精力。先修复自己的错误,重新预览,再查看剩余的差异。
最终预览中不得存在或。 当你准备创建PR时,如果仍有delete或replace操作,请停止。Delete意味着会销毁云基础设施。Replace意味着会销毁并重新创建。这些绝不能作为“剩余差异”被接受——在继续之前必须解决(通过代码修复、别名或记录的手动步骤)。
deletereplacepulumi upHard Rules
硬性规则
Required CLI flags
必需的CLI标志
Use these flags when running preview. A preview without them can show false diffs
(phantom tag removals, region additions) that aren't real. Don't interpret a preview
that was run without them.
shell
pulumi preview --refresh --run-program- refreshes actual cloud state before diffing.
--refresh - runs the Pulumi program during refresh.
--run-program
运行预览时请使用这些标志。不使用这些标志的预览可能会显示虚假差异(如 phantom tag removals、region additions),并非真实存在的问题。请勿解读未使用这些标志生成的预览结果。
shell
pulumi preview --refresh --run-program- 在比较差异前刷新实际云状态。
--refresh - 在刷新期间运行Pulumi程序。
--run-program
Don't chase deprecations
不要主动处理废弃项
If something is deprecated but still works, leave it alone. Migrating to the replacement
introduces risk for no benefit. A deprecation warning is acceptable - a diff is not.
typescript
// BAD: migrating deprecated-but-working properties introduces risk
new aws.s3.Bucket('bucket');
new aws.s3.BucketLogging('bucketLogging', {...}); // unnecessary migration
// GOOD: fix only the actual error, leave working code alone
new aws.s3.Bucket('bucket', {
logging: {...}, // "loggings" renamed to "logging" - real breaking change
website: {...}, // deprecated but works - don't touch
});如果某项功能已废弃但仍能正常工作,请保持原样。迁移到替代方案会引入风险但无收益。废弃警告是可接受的——但差异不可接受。
typescript
// 错误:迁移已废弃但仍可用的属性会引入风险
new aws.s3.Bucket('bucket');
new aws.s3.BucketLogging('bucketLogging', {...}); // 不必要的迁移
// 正确:仅修复实际错误,保留可用代码
new aws.s3.Bucket('bucket', {
logging: {...}, // "loggings"重命名为"logging" - 真实的破坏性变更
website: {...}, // 已废弃但仍可用 - 请勿修改
});Be minimally invasive
最小侵入性
Every line changed could introduce a regression. Prefer the smallest change that works.
每一行变更都可能引入回归。优先选择能解决问题的最小变更。
Do not run pulumi up
不要运行pulumi up
Provider upgrades modify source code and need code review before deployment.
PR -> review -> merge -> deploy via CI/CD.
Provider升级会修改源代码,需要经过代码审查后再部署。流程应为:PR -> 审查 -> 合并 -> 通过CI/CD部署。
Getting Started
入门指南
1. Get version information
1. 获取版本信息
Determine the target version from the user's request, the Pulumi Registry, package
manager metadata, or the repository's existing dependency constraints.
Default to the latest stable version if the user hasn't specified a target version.
If the user asks which stacks or projects are affected, use skill or
the best available package inventory tooling before making changes.
package-usage根据用户请求、Pulumi Registry、包管理器元数据或仓库现有的依赖约束确定目标版本。
如果用户未指定目标版本,默认使用最新稳定版本。如果用户询问哪些栈或项目会受到影响,请在进行变更前使用skill 或最佳可用的包清单工具。
package-usage2. Update the dependency
2. 更新依赖
- TypeScript/JavaScript: or
npm install @pulumi/{provider}@^{version}yarn add @pulumi/{provider}@^{version} - Python: Update or
pyproject.tomlwithrequirements.txt(underscore, not hyphen), then installpulumi_{provider}>={version} - Go: , update all import paths (e.g.,
go get github.com/pulumi/pulumi-{provider}/sdk/v{major}@latest->v6), runv7go mod tidy - .NET:
dotnet add package Pulumi.{Provider} --version {version} - Java: Update or
pom.xmldependency versionbuild.gradle - YAML: Update provider version in resource options or provider configuration. See https://www.pulumi.com/docs/iac/languages-sdks/yaml/yaml-language-reference/#providers-and-provider-versions for examples.
After installing, check the actual installed version from the lockfile (package-lock.json,
go.sum, etc.) - use these exact versions for schema-tools comparisons.
- TypeScript/JavaScript:或
npm install @pulumi/{provider}@^{version}yarn add @pulumi/{provider}@^{version} - Python:在或
pyproject.toml中更新为requirements.txt(使用下划线,而非连字符),然后安装pulumi_{provider}>={version} - Go:,更新所有导入路径(如
go get github.com/pulumi/pulumi-{provider}/sdk/v{major}@latest->v6),运行v7go mod tidy - .NET:
dotnet add package Pulumi.{Provider} --version {version} - Java:更新或
pom.xml中的依赖版本build.gradle - YAML:在资源选项或Provider配置中更新版本。示例请参考https://www.pulumi.com/docs/iac/languages-sdks/yaml/yaml-language-reference/#providers-and-provider-versions
安装后,从锁文件(package-lock.json、go.sum等)中检查实际安装的版本——在schema-tools比较中使用这些精确版本。
3. Run preview
3. 运行预览
Run immediately after updating the dependency.
Do not research breaking changes first - many upgrades just work, especially minor
versions.
pulumi preview --refresh --run-programIf the preview is clean (only the provider version bump), create a PR.
更新依赖后立即运行。不要先研究破坏性变更——许多升级可以直接生效,尤其是小版本升级。
pulumi preview --refresh --run-program如果预览无差异(仅Provider版本升级),请创建PR。
Preview Progress
预览进展
Preview can fail on the first error and hide others. Fixing one error often reveals new
errors. This is normal progress, not a sign that fixes are making things worse.
- New or different errors -> progress, continue
- Error set shrank -> progress, continue
- Same error persists -> your fix didn't work, try a different approach
- No errors but diffs -> run the diff checkpoint
预览可能会在第一个错误处失败并隐藏其他错误。修复一个错误通常会暴露新的错误。这是正常进展,并非修复使情况恶化的迹象。
- 出现新的或不同的错误 -> 进展中,继续
- 错误数量减少 -> 进展中,继续
- 相同错误持续存在 -> 你的修复无效,请尝试其他方法
- 无错误但存在差异 -> 执行差异检查点
Upgrade Summary
升级总结
Once the preview is clean (or as clean as possible), present the summary:
undefined一旦预览无差异(或尽可能接近无差异),请提交总结:
undefinedUpgrade Summary: {provider} v{current} -> v{target}
升级总结:{provider} v{current} -> v{target}
Code Changes
代码变更
| File | Change | Why it preserves intent |
|---|---|---|
| package.json | Version bump | - |
| index.ts:15 | loggings -> logging | Property renamed, same underlying field |
| 文件 | 变更内容 | 为何能保留意图 |
|---|---|---|
| package.json | 版本升级 | - |
| index.ts:15 | loggings -> logging | 属性重命名,对应相同的底层字段 |
Preview Result
预览结果
All resources show except provider version bump.
{Or: N resources show diffs - see below}
same除Provider版本升级外,所有资源均显示。
{或:N个资源存在差异 - 详见下文}
sameRemaining Diffs (if any)
剩余差异(如有)
| Resource | Operation | What happens on | Risk | Source |
|---|---|---|---|---|
| aws:s3:Bucket (myBucket) | update (-tags) | No-op, state reconciles | None | AWS v7 guide section 3.2 |
Every remaining diff MUST cite an authoritative source (upgrade guide, provider docs,
upstream GitHub issue). "I believe this is expected" is not a source.
| 资源 | 操作 | | 风险 | 来源 |
|---|---|---|---|---|
| aws:s3:Bucket (myBucket) | update (-tags) | 无操作,状态将自动协调 | 无 | AWS v7指南第3.2节 |
所有剩余差异必须引用权威来源(升级指南、Provider文档、上游GitHub问题)。“我认为这是预期的”不属于有效来源。
Manual Steps Required (if any)
所需手动步骤(如有)
- - remove old type binding
pulumi state delete '<urn>' - - adopt under new type
pulumi import <type> <name> <id> - - verify clean
pulumi preview --refresh --run-program
- - 移除旧类型绑定
pulumi state delete '<urn>' - - 使用新类型采用现有资源
pulumi import <type> <name> <id> - - 验证无差异
pulumi preview --refresh --run-program
Deprecation Warnings (no action taken)
废弃警告(未执行操作)
- List deprecated-but-working code left intentionally
If the preview is clean (or all remaining diffs are documented no-ops with cited sources),
create a pull request. If unresolved diffs remain, present the summary as an exception
report and ask the user how they'd like to proceed before creating a PR.
---- 列出有意保留的已废弃但仍可用的代码
如果预览无差异(或所有剩余差异均为有文档记录的无操作并已引用来源),请创建拉取请求。如果仍有未解决的差异,请将总结作为异常报告提交给用户,并在创建PR前询问用户希望如何处理。
---References
参考资料
- - upgrade guides, schema-tools (install, run, interpret output), stack state inspection, SDK types, GitHub issues. Read when investigating Category B diffs.
references/diagnostic-toolbox.md
- - 升级指南、schema-tools(安装、运行、解读输出)、栈状态检查、SDK类型、GitHub问题。调查B类差异时请阅读。
references/diagnostic-toolbox.md