cloudformation-to-pulumi

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

IMPORTANT: PLAN ADJUSTMENT REQUIRED

重要提示:需调整现有计划

If you have already generated a migration plan before loading this skill, you MUST:
  1. Review your existing plan against the workflows and requirements in this skill
  2. Identify any gaps, missing steps, or incorrect assumptions
  3. Update and revise your plan to align with this skill's guidance
  4. Communicate the adjusted plan to the user before proceeding
如果您在加载此技能前已生成迁移计划,必须执行以下操作:
  1. 对照本技能中的工作流和要求,审核您现有的计划
  2. 找出所有缺口、缺失步骤或错误假设
  3. 更新并修订您的计划,使其与本技能的指导方针保持一致
  4. 在继续操作前,将调整后的计划告知用户

CRITICAL SUCCESS REQUIREMENTS

核心成功要求

The migration output MUST meet all of the following:
  1. Complete Resource Coverage
    • Every CloudFormation resource MUST be represented in the Pulumi program OR explicitly justified in the final report.
  2. CloudFormation Logical ID as Resource Name
    • CRITICAL: Every Pulumi resource MUST use the CloudFormation Logical ID as its resource name.
    • This enables the
      cdk-importer
      tool to automatically find import IDs.
    • DO NOT rename resources. Automated import will FAIL if you change the logical IDs.
  3. Successful Deployment
    • The produced Pulumi program must be structurally valid and capable of a successful
      pulumi preview
      (assuming proper config).
  4. Zero-Diff Import Validation (if importing existing resources)
    • After import,
      pulumi preview
      must show NO updates, replaces, creates, or deletes.
  5. Final Migration Report
    • Always output a formal migration report suitable for a Pull Request.
迁移输出必须满足以下所有条件:
  1. 完整资源覆盖
    • 每个CloudFormation资源都必须在Pulumi程序中有所体现,或在最终报告中给出明确的理由说明未包含的原因。
  2. 以CloudFormation逻辑ID作为资源名称
    • 核心要求:每个Pulumi资源必须使用CloudFormation逻辑ID作为其资源名称。
    • 这能让
      cdk-importer
      工具自动查找导入ID。
    • 请勿重命名资源。如果修改逻辑ID,自动导入将会失败。
  3. 部署成功
    • 生成的Pulumi程序必须结构合法,且在配置正确的情况下能够成功执行
      pulumi preview
  4. 零差异导入验证(若导入现有资源)
    • 导入完成后,
      pulumi preview
      必须显示无更新、无替换、无创建、无删除操作。
  5. 最终迁移报告
    • 始终输出一份适用于Pull Request的正式迁移报告。

WHEN INFORMATION IS MISSING

信息缺失时的处理

If the user has not provided a CloudFormation template, you MUST fetch it from AWS using the stack name.
如果用户未提供CloudFormation模板,您必须通过堆栈名称从AWS获取该模板。

MIGRATION WORKFLOW

迁移工作流

Follow this workflow exactly and in this order:
严格按照以下顺序执行此工作流:

1. INFORMATION GATHERING

1. 信息收集

1.1 Verify AWS Credentials (ESC)

1.1 验证AWS凭证(ESC)

Running AWS commands requires credentials loaded via Pulumi ESC.
  • If the user has already provided an ESC environment, use it.
  • If no ESC environment is specified, ask the user which ESC environment to use before proceeding.
For detailed ESC information: Use skill
pulumi-esc
.
You MUST confirm the AWS region with the user.
执行AWS命令需要通过Pulumi ESC加载凭证。
  • 如果用户已提供ESC环境,请直接使用。
  • 如果未指定ESC环境,请先询问用户要使用哪个ESC环境,再继续操作。
如需详细的ESC信息:请使用技能
pulumi-esc
您必须与用户确认AWS区域。

1.2 Get the CloudFormation Template

1.2 获取CloudFormation模板

If user provided a template file: Read the template directly.
If user only provided a stack name: Fetch the template from AWS:
bash
aws cloudformation get-template \
  --region <region> \
  --stack-name <stack-name> \
  --query 'TemplateBody' \
  --output json > template.json
如果用户提供了模板文件:直接读取该模板。
如果用户仅提供了堆栈名称:从AWS获取模板:
bash
aws cloudformation get-template \
  --region <region> \
  --stack-name <stack-name> \
  --query 'TemplateBody' \
  --output json > template.json

1.3 Build Resource Inventory

1.3 构建资源清单

List all resources in the stack:
bash
aws cloudformation list-stack-resources \
  --region <region> \
  --stack-name <stack-name> \
  --output json
This provides:
  • LogicalResourceId
    - Use this as the Pulumi resource name
  • PhysicalResourceId
    - The actual AWS resource ID
  • ResourceType
    - The CloudFormation resource type
列出堆栈中的所有资源:
bash
aws cloudformation list-stack-resources \
  --region <region> \
  --stack-name <stack-name> \
  --output json
该命令会返回以下信息:
  • LogicalResourceId
    - 请将其用作Pulumi资源名称
  • PhysicalResourceId
    - 实际的AWS资源ID
  • ResourceType
    - CloudFormation资源类型

1.4 Analyze Template Structure

1.4 分析模板结构

Extract from the template:
  • Parameters and their defaults
  • Mappings
  • Conditions
  • Outputs
  • Resource dependencies (Ref, GetAtt, DependsOn)
从模板中提取以下内容:
  • 参数及其默认值
  • 映射关系
  • 条件判断
  • 输出内容
  • 资源依赖(Ref、GetAtt、DependsOn)

2. CODE CONVERSION (CloudFormation → Pulumi)

2. 代码转换(CloudFormation → Pulumi)

IMPORTANT: There is NO automated conversion tool for CloudFormation. You MUST convert each resource manually.
重要提示:目前没有CloudFormation到Pulumi的自动转换工具。您必须手动转换每个资源。

2.1 Resource Name Convention (CRITICAL)

2.1 资源命名规范(核心要求)

Every Pulumi resource MUST use the CloudFormation Logical ID as its name.
typescript
// CloudFormation:
// "MyAppBucketABC123": { "Type": "AWS::S3::Bucket", ... }

// Pulumi - CORRECT:
const myAppBucket = new aws.s3.Bucket("MyAppBucketABC123", { ... });

// Pulumi - WRONG (DO NOT do this - import will fail):
const myAppBucket = new aws.s3.Bucket("my-app-bucket", { ... });
This naming convention is REQUIRED because the
cdk-importer
tool matches resources by name.
每个Pulumi资源必须使用CloudFormation逻辑ID作为其名称。
typescript
// CloudFormation:
// "MyAppBucketABC123": { "Type": "AWS::S3::Bucket", ... }

// Pulumi - 正确写法:
const myAppBucket = new aws.s3.Bucket("MyAppBucketABC123", { ... });

// Pulumi - 错误写法(请勿这样做,会导致导入失败):
const myAppBucket = new aws.s3.Bucket("my-app-bucket", { ... });
此命名规范是必须的,因为
cdk-importer
工具会通过名称匹配资源。

2.2 Provider Strategy

2.2 提供商策略

⚠️ CRITICAL: ALWAYS USE aws-native BY DEFAULT ⚠️
  • Use
    aws-native
    for all resources unless there's a specific reason to use
    aws
    .
  • CloudFormation types map directly to aws-native (e.g.,
    AWS::S3::Bucket
    aws-native.s3.Bucket
    ).
  • Only use
    aws
    (classic) when aws-native doesn't support a required feature.
This is MANDATORY for successful imports with cdk-importer. The cdk-importer works by matching CloudFormation resources to Pulumi resources, and CloudFormation maps 1:1 to aws-native. Using the classic
aws
provider will cause import failures.
⚠️ 核心要求:默认始终使用aws-native ⚠️
  • 除非有特定理由使用
    aws
    提供商,否则所有资源都必须使用
    aws-native
  • CloudFormation类型与aws-native直接对应(例如:
    AWS::S3::Bucket
    aws-native.s3.Bucket
    )。
  • 仅当aws-native不支持所需功能时,才使用
    aws
    (经典版)提供商。
这是使用cdk-importer成功导入的必要条件。cdk-importer通过将CloudFormation资源与Pulumi资源匹配来工作,而CloudFormation与aws-native是1:1对应的。使用经典版
aws
提供商会导致导入失败。

2.3 CloudFormation Intrinsic Functions

2.3 CloudFormation内置函数

Map CloudFormation intrinsic functions to Pulumi equivalents:
CloudFormationPulumi Equivalent
!Ref
(resource)
Resource output (e.g.,
bucket.id
)
!Ref
(parameter)
Pulumi config
!GetAtt Resource.Attr
Resource property output
!Sub "..."
pulumi.interpolate
!Join [delim, [...]]
pulumi.interpolate
or
.apply()
!If [cond, true, false]
Ternary operator
!Equals [a, b]
===
comparison
!Select [idx, list]
Array indexing with
.apply()
!Split [delim, str]
.apply(v => v.split(...))
Fn::ImportValue
Stack references or config
将CloudFormation内置函数映射为Pulumi等效实现:
CloudFormation 函数Pulumi 等效实现
!Ref
(资源)
资源输出(例如:
bucket.id
!Ref
(参数)
Pulumi 配置
!GetAtt Resource.Attr
资源属性输出
!Sub "..."
pulumi.interpolate
!Join [delim, [...]]
pulumi.interpolate
.apply()
!If [cond, true, false]
三元运算符
!Equals [a, b]
===
比较
!Select [idx, list]
结合
.apply()
的数组索引
!Split [delim, str]
.apply(v => v.split(...))
Fn::ImportValue
堆栈引用或配置
Example: !Sub
示例:!Sub
typescript
// CloudFormation: !Sub "arn:aws:s3:::${MyBucket}/*"
// Pulumi:
const bucketArn = pulumi.interpolate`arn:aws:s3:::${myBucket.bucket}/*`;
typescript
// CloudFormation: !Sub "arn:aws:s3:::${MyBucket}/*"
// Pulumi:
const bucketArn = pulumi.interpolate`arn:aws:s3:::${myBucket.bucket}/*`;
Example: !GetAtt
示例:!GetAtt
typescript
// CloudFormation: !GetAtt MyFunction.Arn
// Pulumi:
const functionArn = myFunction.arn;
typescript
// CloudFormation: !GetAtt MyFunction.Arn
// Pulumi:
const functionArn = myFunction.arn;

2.4 CloudFormation Conditions

2.4 CloudFormation 条件判断

Convert CloudFormation conditions to TypeScript logic:
typescript
// CloudFormation:
// "Conditions": {
//   "CreateProdResources": { "Fn::Equals": [{ "Ref": "Environment" }, "prod"] }
// }

// Pulumi:
const config = new pulumi.Config();
const environment = config.require("environment");
const createProdResources = environment === "prod";

if (createProdResources) {
  // Create production-only resources
}
将CloudFormation条件转换为TypeScript逻辑:
typescript
// CloudFormation:
// "Conditions": {
//   "CreateProdResources": { "Fn::Equals": [{ "Ref": "Environment" }, "prod"] }
// }

// Pulumi:
const config = new pulumi.Config();
const environment = config.require("environment");
const createProdResources = environment === "prod";

if (createProdResources) {
  // 创建仅用于生产环境的资源
}

2.5 CloudFormation Parameters

2.5 CloudFormation 参数

Convert parameters to Pulumi config:
typescript
// CloudFormation:
// "Parameters": {
//   "InstanceType": { "Type": "String", "Default": "t3.micro" }
// }

// Pulumi:
const config = new pulumi.Config();
const instanceType = config.get("instanceType") || "t3.micro";
将参数转换为Pulumi配置:
typescript
// CloudFormation:
// "Parameters": {
//   "InstanceType": { "Type": "String", "Default": "t3.micro" }
// }

// Pulumi:
const config = new pulumi.Config();
const instanceType = config.get("instanceType") || "t3.micro";

2.6 CloudFormation Mappings

2.6 CloudFormation 映射

Convert mappings to TypeScript objects:
typescript
// CloudFormation:
// "Mappings": {
//   "RegionMap": {
//     "us-east-1": { "AMI": "ami-12345" },
//     "us-west-2": { "AMI": "ami-67890" }
//   }
// }

// Pulumi:
const regionMap: Record<string, { ami: string }> = {
  "us-east-1": { ami: "ami-12345" },
  "us-west-2": { ami: "ami-67890" },
};
const ami = regionMap[aws.config.region!].ami;
将映射转换为TypeScript对象:
typescript
// CloudFormation:
// "Mappings": {
//   "RegionMap": {
//     "us-east-1": { "AMI": "ami-12345" },
//     "us-west-2": { "AMI": "ami-67890" }
//   }
// }

// Pulumi:
const regionMap: Record<string, { ami: string }> = {
  "us-east-1": { ami: "ami-12345" },
  "us-west-2": { ami: "ami-67890" },
};
const ami = regionMap[aws.config.region!].ami;

2.7 Custom Resources

2.7 自定义资源

CloudFormation Custom Resources (
AWS::CloudFormation::CustomResource
or
Custom::*
) require special handling:
  1. Identify the purpose: Read the Lambda function code to understand what it does
  2. Find native replacement: Check if Pulumi has a native resource that provides the same functionality
  3. If no replacement: Document in the migration report that manual implementation is needed
CloudFormation自定义资源(
AWS::CloudFormation::CustomResource
Custom::*
)需要特殊处理:
  1. 明确用途:阅读Lambda函数代码,了解其功能
  2. 寻找原生替代方案:检查Pulumi是否有提供相同功能的原生资源
  3. 若无替代方案:在迁移报告中记录,说明需要手动实现

2.8 TypeScript Output Handling

2.8 TypeScript 输出处理

aws-native outputs often include undefined. Avoid
!
non-null assertions. Always safely unwrap with
.apply()
:
typescript
// WRONG
functionName: lambdaFunction.functionName!,

// CORRECT
functionName: lambdaFunction.functionName.apply(name => name || ""),
aws-native的输出通常包含undefined。避免使用
!
非空断言,始终通过
.apply()
安全解包:
typescript
// 错误写法
functionName: lambdaFunction.functionName!,

// 正确写法
functionName: lambdaFunction.functionName.apply(name => name || ""),

3. RESOURCE IMPORT

3. 资源导入

After conversion, import existing resources to be managed by Pulumi.
转换完成后,将现有资源导入Pulumi进行管理。

3.0 Pre-Import Validation (REQUIRED)

3.0 导入前验证(必须执行)

Before proceeding with import, verify your code:
  1. Check Provider Usage: Scan your code to ensure all resources use
    aws-native
  2. Document Exceptions: Any use of
    aws
    (classic) provider must be justified
  3. Verify Resource Names: Confirm all resources use CloudFormation Logical IDs as names
在开始导入前,请验证您的代码:
  1. 检查提供商使用情况:扫描代码,确保所有资源都使用
    aws-native
  2. 记录例外情况:任何使用
    aws
    (经典版)提供商的情况都必须给出理由
  3. 验证资源名称:确认所有资源都使用CloudFormation逻辑ID作为名称

3.1 Automated Import with cdk-importer

3.1 使用cdk-importer自动导入

Because you used CloudFormation Logical IDs as resource names, you can use the
cdk-importer
tool to automatically import resources.
Follow cfn-importer.md for detailed import procedures.
由于您使用了CloudFormation逻辑ID作为资源名称,您可以使用
cdk-importer
工具自动导入资源。
请参考cfn-importer.md获取详细的导入步骤。

3.2 Manual Import for Failed Resources

3.2 手动导入导入失败的资源

For resources that fail automatic import:
  1. Follow cloudformation-id-lookup.md to find the import ID format
  2. Use
    pulumi import
    :
bash
pulumi import <pulumi-resource-type> <logical-id> <import-id>
对于自动导入失败的资源:
  1. 参考cloudformation-id-lookup.md查找导入ID格式
  2. 使用
    pulumi import
    命令:
bash
pulumi import <pulumi-resource-type> <logical-id> <import-id>

3.3 Running Preview After Import

3.3 导入后执行预览

After import, run
pulumi preview
. There must be:
  • NO updates
  • NO replaces
  • NO creates
  • NO deletes
If there are changes, investigate and update the program until preview is clean.
导入完成后,执行
pulumi preview
。结果必须满足:
  • 无更新操作
  • 无替换操作
  • 无创建操作
  • 无删除操作
如果有变更,请排查问题并更新程序,直到预览结果无任何变更。

OUTPUT FORMAT (REQUIRED)

输出格式要求(必须遵守)

When performing a migration, always produce:
  1. Overview (high-level description)
  2. Migration Plan Summary
  3. Pulumi Code Outputs (TypeScript; organized by file)
  4. Resource Mapping Table:
CloudFormation Logical IDCFN TypePulumi TypeProvider
MyAppBucketABC123
AWS::S3::Bucket
aws-native.s3.Bucket
aws-native
MyLambdaFunction456
AWS::Lambda::Function
aws-native.lambda.Function
aws-native
  1. Custom Resources Summary (if any)
  2. Final Migration Report (PR-ready)
  3. Next Steps (import instructions)
执行迁移时,必须生成以下内容:
  1. 概述(高层级描述)
  2. 迁移计划摘要
  3. Pulumi代码输出(TypeScript;按文件组织)
  4. 资源映射表
CloudFormation 逻辑IDCFN 类型Pulumi 类型提供商
MyAppBucketABC123
AWS::S3::Bucket
aws-native.s3.Bucket
aws-native
MyLambdaFunction456
AWS::Lambda::Function
aws-native.lambda.Function
aws-native
  1. 自定义资源摘要(如有)
  2. 最终迁移报告(适用于Pull Request)
  3. 下一步操作(导入说明)

FOR DETAILED DOCUMENTATION

详细文档参考