mcpField
P
provider-upgrade

provider-upgrade

github.com/pulumi云与 DevOps78857 次安装3 周前更新
代码仓库

关于 provider-upgrade

provider-upgrade 是用于更新 Pulumi Provider 依赖的技能,重点是在升级时保持基础设施意图和云端资源不变。它指导开发者分类预览差异、协调状态,并在部署前进行审查。

主要功能

  1. 01更新依赖版本
  2. 02基于预览分类差异
  3. 03导入与状态协调指导
  4. 04避免意外删除或替换

适用场景

  1. 01升级项目中的 Pulumi Provider
  2. 02排查版本升级后的差异
  3. 03准备升级 PR 而不部署

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/pulumi/agent-skills --skill provider-upgrade

安装后在 Claude Code 中输入/provider-upgrade确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

use_cases.yaml
agents/
openai.yaml
references/
diagnostic-toolbox.md
gcp-v10.md

详细介绍

升级 Pulumi Provider

原则

Provider 升级是一次转换,而不是一项变更请求。

用户的基础设施意图并没有改变——他们仍然想要同一个存储桶、同一个函数、同一个集群。改变的是 Provider API 表达这一意图的方式。你的工作是将现有代码转换为新的 API,让 Pulumi 看到的代码与现有资源之间没有差异。

需要牢记四个层面:

  1. 用户意图 - 用户希望在云端实现什么(升级期间保持不变)
  2. 代码 - 程序如何使用 Provider API 表达该意图(可能需要更新)
  3. Pulumi 状态 - Pulumi 对现有资源的存储表示(可能需要协调)
  4. 实际云端资源 - 实际的基础设施(升级期间不应改变)

升级期间,第 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
  1. 升级 Provider 依赖项
  2. 使用所需的 CLI 标志进行预览
  3. 差异检查点 - 对每个非 same 资源进行分类(见下一节)
  4. 修复 A 类 - 未产生 same 的代码变更
  5. 调查 B 类 - 对未修改资源产生的差异
  6. 重复以上步骤,直到预览干净,或剩余差异均已彻底调查
  7. 创建 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 移除资源类型时,正确的做法是:

  1. pulumi state delete '<urn>' - 手动步骤,仅从跟踪中移除
  2. 添加替代资源(如有),并使用导入功能——在新类型下接管云状态
  3. 通过预览进行验证

不要在预览中仍有 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)。

评论

支持 Markdown