provider-upgrade

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Upgrading 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:
  1. User intent - what the user wants in the cloud (unchanged during an upgrade)
  2. Code - how the program expresses that intent using the provider API (may need updating)
  3. Pulumi state - Pulumi's stored representation of what exists (may need reconciliation)
  4. 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认为代码定义的状态与已存在的状态完全一致。
需要牢记四个层级:
  1. 用户意图 - 用户希望在云环境中实现的目标(升级期间保持不变)
  2. 代码 - 程序使用Provider API表达意图的方式(可能需要更新)
  3. Pulumi状态 - Pulumi存储的现有基础设施表示(可能需要协调)
  4. 实际云环境 - 真实存在的基础设施(升级期间不应改变)
升级过程中,层级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
  1. Bump the provider dependency
  2. Preview with required CLI flags
  3. Diff Checkpoint - categorize every non-
    same
    resource (see next section)
  4. Fix Category A - code changes that didn't produce
    same
  5. Investigate Category B - diffs on resources you didn't change
  6. Repeat until clean or remaining diffs are fully investigated
  7. 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
  1. 升级 Provider依赖版本
  2. 预览 使用所需的CLI标志
  3. 差异检查点 - 对每个非
    same
    状态的资源进行分类(见下一章节)
  4. 修复A类问题 - 未产生
    same
    状态的代码变更
  5. 调查B类问题 - 未修改代码的资源出现的差异
  6. 重复 直到预览无差异或剩余差异已完全调查清楚
  7. 创建PR 附带升级总结

The Diff Checkpoint

差异检查点

This is the most important section. Run this after EVERY preview.
For each non-
same
resource, answer one question: "Did any of my code changes affect this resource - directly or indirectly?"
"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
same
, 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.
I modified an existing resource and it shows
update
:
Your rename, restructure, or value adjustment changed the meaning, not just the syntax. The resource would show
same
if the old and new code compiled to the same goal state. The
update
means they don't.
Ask yourself: "If this rename were truly equivalent, the resource would show
same
. It doesn't. What is semantically different between my old code and my new code?"
Common 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,
pulumi up
WILL send those values to the cloud API. Don't assume they're no-ops. Investigate each changed property.
I added a new resource block and it shows
create
:
During 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
import
, not
create
. Tell Pulumi to adopt the existing cloud resource.
Ask 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
delete
:
A
delete
in the preview means
pulumi up
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.
This is different from
pulumi state delete
, 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:
  1. pulumi state delete '<urn>'
    - manual step, removes from tracking only
  2. Add replacement resources (if any) with imports - adopts the cloud state under new types
  3. Verify with preview
Do NOT leave a
delete
in the preview and proceed to PR creation. A delete that runs via
pulumi up
will destroy real infrastructure. If the resource must be removed from state, document it as a manual step for the user.
Ask yourself: "What cloud infrastructure does this resource manage? If
pulumi up
runs this delete, what gets destroyed or unconfigured?"
你的代码变更本应将相同的意图转换为新API。如果资源显示
same
,说明转换正确。如果显示其他状态,说明转换有误。不要认为“因为我修改了代码,所以差异是预期的”——如果变更在语义上等价,就不会产生差异。
我修改了现有资源,它显示
update
你的重命名、重构或值调整改变了语义,而非仅语法。如果新旧代码编译后的目标状态一致,资源会显示
same
update
说明两者不一致。
自问:“如果这次重命名真的等价,资源会显示
same
。但它没有。我的旧代码和新代码在语义上有什么不同?”
常见原因:新属性名称对应不同的底层字段;值的结构发生变化,转换过程中丢失或添加了信息;新版本的默认值已更改,你需要显式设置旧值;新Provider版本开始追踪之前未追踪的字段(这些字段需要显式设置以匹配当前状态)。
如果更新包含你未修改的属性——新字段出现、类型标准化(字符串→数字)、新增默认值——这是Provider追踪字段的变化。但只要存在差异,
pulumi up
就会将这些值发送到云API。不要假设它们是无操作。请调查每个变更的属性。
我添加了新的资源块,它显示
create
在升级过程中,新资源块几乎总是代表云环境中已存在的基础设施。旧Provider会隐式管理它(作为另一个资源的一部分);新Provider需要显式的资源定义。但云对象已经存在。Pulumi想要创建新的基础设施——这不是你想要的结果。
正确的修复方式是
import
,而非
create
。告诉Pulumi采用现有的云资源。
自问:“这个新资源代表哪个云对象?它是否已经存在?升级前它是如何被管理的?”
typescript
// 错误 - 创建重复基础设施
const stage = new aws.apigateway.Stage("prodStage", { ... });

// 正确 - 采用现有资源
const stage = new aws.apigateway.Stage("prodStage", { ... }, {
    import: "<rest-api-id>/prod",  // 导入ID格式因资源类型而异
});
我删除了资源块,它显示
delete
预览中的
delete
意味着
pulumi up
将调用Provider的Delete API来销毁或取消配置该云资源。这是真实的销毁操作——而非仅清理状态。云基础设施仍然存在,并且几乎可以肯定仍被需要。
这与
pulumi state delete
不同,后者仅将资源从Pulumi的追踪中移除,而不会调用Provider的API。当新Provider版本移除了某个资源类型时,正确的做法是:
  1. pulumi state delete '<urn>'
    - 手动步骤,仅从追踪中移除
  2. 添加带导入配置的替代资源(如有)——采用云状态并使用新类型
  3. 通过预览验证
不要在预览中保留
delete
并继续创建PR。通过
pulumi up
执行的删除操作会销毁真实的基础设施。如果必须从状态中移除资源,请将其记录为用户需要执行的手动步骤。
自问:“该资源管理的是哪些云基础设施?如果
pulumi up
执行此删除操作,会销毁或取消配置什么?”

Category 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
references/diagnostic-toolbox.md
and investigate.
These 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
    pulumi up
    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.
  • 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
并进行调查。
这些差异可能是:
  • 可通过代码修复 - 为变更的默认值设置显式值、添加别名
  • 有文档记录的无操作 - 升级指南说明在
    pulumi up
    后会自动解决,不会影响真实基础设施。此分类必须引用升级指南或Provider文档中的内容。仅靠你判断“这看起来是无操作”是不够的——用户信任你区分真实基础设施变更和伪差异,判断错误会导致云环境出现意外变更。
  • 需要手动步骤 - 状态移除+重新导入,为用户记录步骤
  • 未知 - 将你的发现告知用户并寻求指导

Category C: Provider version bump

C类:Provider版本升级

An
update
on
pulumi:providers:{name}
showing only a version change is the one expected diff. Verify no other properties changed on the provider resource.
pulumi:providers:{name}
显示仅版本变更的
update
是唯一预期的差异。请验证Provider资源的其他属性未发生变更。

After categorizing

分类完成后

Completeness check: Every resource in the preview that shows any non-
same
state must appear in your checkpoint - including resources with
[diff: ...]
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.
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
delete
or
replace
in the final preview.
If a delete or replace remains when you're ready to create a PR, stop. A delete means
pulumi up
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.

完整性检查: 预览中所有显示非
same
状态的资源都必须出现在你的检查点中——包括带有
[diff: ...]
注释的资源,即使它们没有显式的create/update/delete标记。如果有遗漏,你的检查点不完整。请返回并对缺失的资源进行分类。
接受差异的证据要求: 如果你想接受任何差异为“可忽略”(不修复),需要提供证据——无论属于A类还是B类。“我认为API会将这些视为等价”或“这看起来是状态协调”不属于有效证据。可接受的证据包括:升级指南中有记录、GitHub问题已确认,或Provider文档解释了该行为。如果找不到证据,请修复差异或向用户标记该问题。
优先级: 在调查B类差异之前,先修复所有A类问题。你的代码修正会改变预览输出,因此先调查B类差异会浪费精力。先修复自己的错误,重新预览,再查看剩余的差异。
最终预览中不得存在
delete
replace
当你准备创建PR时,如果仍有delete或replace操作,请停止。Delete意味着
pulumi up
会销毁云基础设施。Replace意味着会销毁并重新创建。这些绝不能作为“剩余差异”被接受——在继续之前必须解决(通过代码修复、别名或记录的手动步骤)。

Hard 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
  • --refresh
    refreshes actual cloud state before diffing.
  • --run-program
    runs the Pulumi program during refresh.
运行预览时请使用这些标志。不使用这些标志的预览可能会显示虚假差异(如 phantom tag removals、region additions),并非真实存在的问题。请勿解读未使用这些标志生成的预览结果。
shell
pulumi preview --refresh --run-program
  • --refresh
    在比较差异前刷新实际云状态。
  • --run-program
    在刷新期间运行Pulumi程序。

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
package-usage
or the best available package inventory tooling before making changes.
根据用户请求、Pulumi Registry、包管理器元数据或仓库现有的依赖约束确定目标版本。
如果用户未指定目标版本,默认使用最新稳定版本。如果用户询问哪些栈或项目会受到影响,请在进行变更前使用skill
package-usage
或最佳可用的包清单工具。

2. Update the dependency

2. 更新依赖

  • TypeScript/JavaScript:
    npm install @pulumi/{provider}@^{version}
    or
    yarn add @pulumi/{provider}@^{version}
  • Python: Update
    pyproject.toml
    or
    requirements.txt
    with
    pulumi_{provider}>={version}
    (underscore, not hyphen), then install
  • Go:
    go get github.com/pulumi/pulumi-{provider}/sdk/v{major}@latest
    , update all import paths (e.g.,
    v6
    ->
    v7
    ), run
    go mod tidy
  • .NET:
    dotnet add package Pulumi.{Provider} --version {version}
  • Java: Update
    pom.xml
    or
    build.gradle
    dependency version
  • 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
    ->
    v7
    ),运行
    go 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
pulumi preview --refresh --run-program
immediately after updating the dependency. Do not research breaking changes first - many upgrades just work, especially minor versions.
If 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
一旦预览无差异(或尽可能接近无差异),请提交总结:
undefined

Upgrade Summary: {provider} v{current} -> v{target}

升级总结:{provider} v{current} -> v{target}

Code Changes

代码变更

FileChangeWhy it preserves intent
package.jsonVersion bump-
index.ts:15loggings -> loggingProperty renamed, same underlying field
文件变更内容为何能保留意图
package.json版本升级-
index.ts:15loggings -> logging属性重命名,对应相同的底层字段

Preview Result

预览结果

All resources show
same
except provider version bump. {Or: N resources show diffs - see below}
除Provider版本升级外,所有资源均显示
same
。 {或:N个资源存在差异 - 详见下文}

Remaining Diffs (if any)

剩余差异(如有)

ResourceOperationWhat happens on
pulumi up
RiskSource
aws:s3:Bucket (myBucket)update (-tags)No-op, state reconcilesNoneAWS 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.
资源操作
pulumi up
执行时的行为
风险来源
aws:s3:Bucket (myBucket)update (-tags)无操作,状态将自动协调AWS v7指南第3.2节
所有剩余差异必须引用权威来源(升级指南、Provider文档、上游GitHub问题)。“我认为这是预期的”不属于有效来源。

Manual Steps Required (if any)

所需手动步骤(如有)

  1. pulumi state delete '<urn>'
    - remove old type binding
  2. pulumi import <type> <name> <id>
    - adopt under new type
  3. pulumi preview --refresh --run-program
    - verify clean
  1. pulumi state delete '<urn>'
    - 移除旧类型绑定
  2. pulumi import <type> <name> <id>
    - 使用新类型采用现有资源
  3. 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

参考资料

  • references/diagnostic-toolbox.md
    - 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类差异时请阅读。