关于 provider-upgrade
provider-upgrade 是用于更新 Pulumi Provider 依赖的技能,重点是在升级时保持基础设施意图和云端资源不变。它指导开发者分类预览差异、协调状态,并在部署前进行审查。
主要功能
- 01更新依赖版本
- 02基于预览分类差异
- 03导入与状态协调指导
- 04避免意外删除或替换
适用场景
- 01升级项目中的 Pulumi Provider
- 02排查版本升级后的差异
- 03准备升级 PR 而不部署
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pulumi/ agent-skills --skill provider-upgrade安装后在 Claude Code 中输入/provider-upgrade确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
use_cases.yamlagents/openai.yamlreferences/diagnostic-toolbox.mdgcp-v10.md详细介绍
升级 Pulumi Provider
原则
Provider 升级是一次转换,而不是一项变更请求。
用户的基础设施意图并没有改变——他们仍然想要同一个存储桶、同一个函数、同一个集群。改变的是 Provider API 表达这一意图的方式。你的工作是将现有代码转换为新的 API,让 Pulumi 看到的代码与现有资源之间没有差异。
需要牢记四个层面:
- 用户意图 - 用户希望在云端实现什么(升级期间保持不变)
- 代码 - 程序如何使用 Provider API 表达该意图(可能需要更新)
- Pulumi 状态 - Pulumi 对现有资源的存储表示(可能需要协调)
- 实际云端资源 - 实际的基础设施(升级期间不应改变)
升级期间,第 2 层和第 3 层可能需要变更,以便继续正确表示保持不变的第 1 层和第 4 层。
正确的转换会产生零差异。Pulumi 引擎没有“升级”的概念——它只会比较目标状态(你的代码)与实际状态(状态文件),并进行协调。如果转换正确,这两种状态就会匹配,不会发生任何变化。如果看到差异,要么是转换有误,要么是还需要进行代码变更以外的操作(导入、别名或手动步骤)。无论是哪种情况,差异都是需要解决的问题,而不是可以接受的结果。
核心循环
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 并附上升级摘要
差异检查点
这是最重要的一节。每次预览后都要执行此步骤。
对于每个非 same 资源,回答一个问题:
“我的任何代码变更是否直接或间接影响了此资源?”
“直接”是指你编辑了资源块本身。“间接”是指你修改了影响此资源的内容——共享变量、另一个资源的输出、辅助函数、默认值,或此资源所依赖的资源。如果你的变更可能改变 Pulumi 对此资源的计算结果,它就属于 A 类。
然后按照适用的类别处理。
类别 A:我更改了此资源的代码
你的代码更改本应将相同意图转换为新的 API。如果资源显示 same,说明你的转换正确。如果显示其他内容,则说明你的转换有误。不要说“差异是预期的,因为我更改了代码”——如果更改在语义上等效,就不会出现差异。
我修改了现有资源,它显示 update:
你的重命名、重构或值调整改变了含义,而不只是语法。如果新旧代码编译后得到相同的目标状态,资源就会显示 same。显示 update 意味着它们并不相同。
问问自己:“如果这次重命名确实等效,资源就会显示 same。但它没有。我的新旧代码在语义上有什么不同?”
常见原因:新的属性名称映射到了不同的底层字段;值的结构发生变化,而转换过程中丢失或增加了信息;新版本中的默认值发生了变化,你需要显式设置旧值;差异中出现了额外属性,因为新版本的 provider 会跟踪以前未跟踪的字段(需要显式设置这些字段以匹配当前状态)。
如果更新中包含你未更改的属性——例如出现新字段、类型规范化(string->number)或额外默认值——这说明 provider 改变了跟踪的内容。但只要差异存在,pulumi up 就会将这些值发送到云 API。不要以为它们不会产生影响。请逐一调查每个变更的属性。
我添加了新的资源代码块,它显示 create:
升级期间,新的资源代码块几乎总是对应于云中已经存在的基础设施。旧 provider 会隐式管理它(作为另一个资源的一部分);新 provider 则需要显式资源。但云对象已经存在。Pulumi 想要创建新的基础设施——这不是你想要的结果。
解决方法是使用 import,而不是 create。告诉 Pulumi 接管现有云资源。
问问自己:“这个新资源代表什么云对象?它是否已经存在?升级前是如何管理它的?”
// 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
});
我删除了资源代码块,它显示 delete:
预览中出现 delete,意味着 pulumi up 会调用 provider 的 Delete API 来销毁或取消配置此云资源。这是真正的销毁,而不只是清理状态。云基础设施仍然存在,而且几乎肯定仍有用途。
这与 pulumi state delete 不同:后者会在不调用 provider API 的情况下,从 Pulumi 跟踪中移除此资源。新版本的 provider 移除资源类型时,正确的做法是:
pulumi state delete '<urn>'- 手动步骤,仅从跟踪中移除- 添加替代资源(如有),并使用导入功能——在新类型下接管云状态
- 通过预览进行验证
不要在预览中仍有 delete 时继续创建 PR。通过 pulumi up 执行删除会摧毁真实基础设施。如果必须从状态中移除该资源,请将其记录为用户需要手动执行的步骤。
问问自己:“此资源管理着什么云基础设施?如果运行 pulumi up 执行此删除,会摧毁或取消配置什么?”
类别 B:我没有为此资源更改代码
此差异并非由你的代码更改导致,而是由提供程序版本本身的变化引起的——默认值不同、状态表示方式改变,或行为差异。
阅读 references/diagnostic-toolbox.md 并进行调查。
这些差异可能是:
- 可通过代码修复——为发生变化的默认值设置显式值、添加别名
- 有文档说明的无操作——升级指南指出,此差异会在
pulumi up时消除,且不会影响实际基础设施。此分类必须引用升级指南或提供程序文档。仅凭你自己判断“这看起来是无操作”并不足够——用户信任你能区分实际基础设施变更和工件,判断错误会导致云环境发生意外变更。 - 需要手动步骤——删除状态并重新导入,并向用户说明操作步骤
- 未知——向用户展示你找到的信息并征求指引
分类之后
**完整性检查:**预览中显示任何非 same 状态的每个资源都必须出现在你的检查点中——包括带有 [diff: ...] 注释的资源,即使它们没有明确的创建/更新/删除标记。如果你没有列出某个资源,你的检查点就不完整。返回并对遗漏的资源进行分类。
**接受差异的证据要求:**如果你想将任何差异视为“可以接受”(而不修复),就必须提供证据——无论它属于类别 A 还是类别 B。“我认为 API 会将它们视为等效”或“这看起来像是状态协调”都不是证据。可接受的证据包括:升级指南对此有说明、GitHub issue 确认了这一点,或提供程序文档解释了这种行为。如果找不到证据,就修复该差异或将其标记出来并告知用户。
**顺序:**先修复所有类别 A 问题,再调查类别 B。你的代码修正会改变预览输出,因此先调查类别 B 差异会浪费精力。先修复自己的错误,重新运行预览,然后再检查剩余差异。
**最终预览中不得有 delete 或 replace。**如果准备创建 PR 时仍存在删除或替换,请停止。删除意味着 pulumi up 会销毁云基础设施。替换意味着它会先销毁再重新创建。这些绝不能作为“剩余差异”接受——必须在继续之前解决(通过代码修复、别名或有文档说明的手动步骤)。
硬性规则
必需的 CLI 标志
运行预览时使用这些标志。没有它们的预览可能会显示虚假差异(虚假的标签移除、区域新增),这些差异并非真实情况。不要解读未使用这些标志运行的预览。
pulumi preview --refresh --run-program
--refresh会在执行差异比较前刷新实际云状态。--run-program会在刷新期间运行 Pulumi 程序。
不要追着弃用项做迁移
如果某项功能已弃用但仍能正常工作,就保持原样。迁移到替代方案会带来风险,却没有任何好处。弃用警告可以接受,差异则不行。
// 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
});
尽量减少改动
每一行更改都可能引入回归。优先选择能奏效的最小改动。
不要运行 pulumi up
提供程序升级会修改源代码,部署前需要代码审查。 PR → 审查 → 合并 → 通过 CI/CD 部署。
开始使用
1. 获取版本信息
根据用户的请求、Pulumi Registry、包管理器元数据或仓库中现有的依赖约束,确定目标版本。
如果用户未指定目标版本,则默认使用最新稳定版本。
如果用户询问受影响的 stack 或项目,请在进行更改前使用 skill package-usage 或最合适的包清单工具。
1a. 检查是否有针对特定提供程序的参考文档
某些主版本包含重大变更,如果修复顺序不当,可能会破坏正在运行的资源,而仅靠预览无法发现这一点。如果 references/ 中有适用于此提供程序和目标主版本的文件(例如,将 pulumi-gcp 升级到 10.x 时的 gcp-v10.md),请现在阅读该文件,并在执行步骤 2 之前遵循其中的“升级前”部分。对于此次升级,该部分优先于步骤 3 中的“不要先研究重大变更”规则。
2. 更新依赖项
- 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:在资源选项或提供程序配置中更新提供程序版本。示例请参阅 https://www.pulumi.com/docs/iac/languages-sdks/yaml/yaml-language-reference/#providers-and-provider-versions。
安装后,请从锁文件(package-lock.json、go.sum 等)检查实际安装的版本,并在 schema-tools 比较中使用这些确切版本。
3. 运行预览
更新依赖项后立即运行 pulumi preview --refresh --run-program。
不要先研究重大变更——许多升级都能直接成功,尤其是次要版本升级。
如果预览干净(只有提供程序版本升级),请创建 PR。
预览进度
预览可能在遇到第一个错误时失败,从而隐藏其他错误。修复一个错误后,通常会显现新的错误。这是正常进展,并不意味着修复让情况变得更糟。
- 出现新的或不同的错误 -> 取得进展,继续
- 错误数量减少 -> 取得进展,继续
- 相同错误仍然存在 -> 修复未奏效,请尝试其他方法
- 没有错误,但存在差异 -> 运行差异检查点
升级摘要
预览干净(或尽可能干净)后,请提供摘要:
## Upgrade Summary: {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 |
### Preview Result
All resources show `same` except provider version bump.
{Or: N resources show diffs - see below}
### Remaining Diffs (if any)
| Resource | Operation | What happens on `pulumi up` | 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.
### 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
### Deprecation Warnings (no action taken)
- List deprecated-but-working code left intentionally
如果预览干净(或所有剩余差异均已记录为无操作项,并附有引用来源),请创建拉取请求。如果仍有未解决的差异,请将摘要作为例外报告提供,并在创建 PR 之前询问用户希望如何继续。
参考文档
references/diagnostic-toolbox.md- 升级指南、schema-tools(安装、运行、解读输出)、堆栈状态检查、SDK 类型、GitHub 问题。调查 B 类差异时阅读。references/gcp-v10.md- pulumi-gcp v10 中的所有重大变更,包括状态扫描、grep 模式、修复顺序和风险。将 pulumi-gcp 升级到 10.x 之前阅读(见步骤 1a)。