Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Release cdk-from-cfn version 0.183.0 #835

Merged
merged 2 commits into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions ARCHITECTURE.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# cdk-from-cfn Architecture Overview

This document provides a high level overview of the key components in the cdk-from-cfn project and their responsibilities

## Processing Flow

The easiest way to understand the purpose behind the core components of `cdk-from-cfj`, is to look at the high-level processing flow
of transforming a Cloudformation Template into a CDK Application:
```
CloudFormation Template
↓ (Parser)
Cloudformation Parse Tree
↓ (IR)
Cloudformation Program Ir
↓ (Synthesizer)
Generated CDK Code
```

Put simply, the idea behind the cdk-from-cfn processing flow is to transform a
CFN template into an IR, and then use that IR plus a language synthesizer to generate a CDK Application.

To do so, the parser reads the text from the provided Cloudformation template and generates a simple, un-validated, data structure
called the `CloudformationParseTree` which is essentially a 1:1 in memory representation of the provided template

However the `CloudformationParseTree` is not sufficient for application synthesis and needs to be enriched with additional
information and validated against the schema for correctness. This is the purpose of the `IR` which generates a `CloudformationProgramIr`.

A language specific synthesizer can then read the IR and use it to generate CDK stack code.

In rust code this flow would look like:
```rust
// 1. Parse CloudFormation template
let cfn_tree: CloudformationParseTree = serde_yaml::from_str(template)?;

// 2. Convert to IR
let ir = CloudformationProgramIr::from(cfn_tree, schema)?;

// 3. Synthesize to target language
let synthesizer = TypeScript {};
ir.synthesize(synthesizer, output, stack_name)?;
```

## Core Components Overview

### Parser

Responsible for de-serializing the Cloudformation template into a `CloudformationParseTree` data structure. The parser's sole responsibility is creating a 1:1 representation of the template structure, without performing any validation or enhancement.

Key responsibilities:
- Reads YAML/JSON Cloudformation templates
- Creates corresponding Rust data structures
- Parses all template sections (Resources, Parameters, Conditions, intrinsic functions, etc.)

```rust
// CloudFormation Template
{
"Resources": {
"MyBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": {
"Fn::Join": ["-", ["mybucket", {"Ref": "AWS::Region"}]]
}
}
}
}
}

// Parse Tree - Just maps the structure directly
CloudformationParseTree {
resources: {
"MyBucket" => ResourceAttributes {
resource_type: "AWS::S3::Bucket",
properties: {
"BucketName" => ResourceValue::IntrinsicFunction(
Fn::Join {
sep: "-",
list: ["mybucket", Ref("AWS::Region")]
}
)
}
}
}
}
```

### IR (Intermediate Representation)

Responsible for converting the raw ParseTree into a validated and enriched `CloudformationProgramIr`. The IR's main purpose is to validate the template against the schema, as well as add necessary CDK-specific information and validate resources against the CDK schema before code generation. Some of the key enrichments added by the IR from the parse tree are as follows:

1. Type Resolution
* Comparing the resource properties from the ParseTree against the schema, the IR will concretely type the resource properties so they can be concretely typed in the generated application
2. Dependency Graph and Reference Tracking
* Performs a topological sort to determine resource ordering for code synthesis
3. Import Instructions
* Generates all modules modules which will later need to be imported in the cdk app.
4. Conditional Normalization
* CFN allows multiple ways to define conditionals (short hands or intrinsic functions), so the IR normalizes these into `ConditionIr`s as these will be turned into language specific boolean expressions by the synthesizer.

Key responsibilities:
- Validates resources and properties against CDK schema
- Resolves references and tracks dependencies between resources
- Enhances references with type and origin information
- Orders resources based on dependencies
- Adds necessary CDK imports and type information
- Normalizes Conditionals

```rust
// IR - Validates against the schema and adds additional information for app generation
CloudformationProgramIr {
resources: [
ResourceInstruction {
name: "MyBucket",
resource_type: ResourceType::AWS {
service: "S3",
type_name: "Bucket"
},
properties: {
"bucketName": ResourceIr::Join(
"-",
[
ResourceIr::String("mybucket"),
ResourceIr::Ref(Reference {
origin: Origin::PseudoParameter(Region),
name: "AWS::Region"
})
]
)
},
// Additional validated information:
references: ["AWS::Region"], // Tracks dependencies
condition: None,
deletion_policy: None
}
]
}
```

### Synthesizer

Responsible for converting the validated IR into CDK code in a specific target language. The synthesizer's main purpose is to generate idiomatic code that properly represents the CloudFormation resources as CDK constructs. At a high level the synthesizer's job is quite simple. Every language is different however generally speaking a synthesizer will loop through the various properties of the IR and generate language specific code in the following order:

```
1. Import Generation
2. Stack Class/Props Generation
3. Resource Generation
4. Mappings Generation
5. Output Generation
```

However because every language is different that does not mean every synthesizer will generate code in the same way/order. For example a simple s3 bucket in Typescript may look like this

```typescript
// Stack properties defined as an interface
interface StackProps {
bucketName?: string;
}

// Resource creation
new s3.Bucket(this, 'MyBucket', {
bucketName: props.bucketName
});
```

where the same app in python may look like this
```python
# Stack properties defined as parameters since python does not have interfaces
def __init__(self, scope, id, *, bucket_name=None):

# Resource creation
s3.Bucket(self, 'MyBucket',
bucket_name=bucket_name
)
```


Key responsibilities:
- Converts IR constructs to language-specific CDK code
- Generates language specific imports
- Handles language-specific code patterns (builders, properties, etc.)
- Implements string interpolation and type conversion for each language
62 changes: 27 additions & 35 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,43 @@
# Contributing
# Contributing to cdk-from-cfn

This document describes how to set up a development environment and submit your changes.
We welcome contributions to the cdk-from-cfn project! This guide will help you get started with contributing.

## Getting Started
## Development Environment Setup

### Setup

#### Required

- [Rust](https://www.rust-lang.org/tools/install)
### Prerequisites
- [Rust](https://www.rust-lang.org/tools/install) (Latest stable version)
- [Wasm-Pack](https://github.com/rustwasm/wasm-pack?tab=readme-ov-file)
- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- [GitHub account](https://github.com/join)

#### Recommended
- [GitHub Account](https://github.com/join)

- [Brew](https://docs.brew.sh/Installation)
- IDE
- [VSCode](https://code.visualstudio.com/download)
- [IntelliJ](https://www.jetbrains.com/idea/download)
- [GitHub CLI](https://cli.github.com/)
### Getting the Project

```console
// Using github cli
```bash
# Clone your fork
gh repo fork cdklabs/cdk-from-cfn
# Or manually clone
git clone https://github.com/YOUR_USERNAME/cdk-from-cfn.git
cd cdk-from-cfn
cargo build
```

### Tests
## Building the Project
```bash
# build the debug target
cargo build

```console
cargo test
```
# build the release target
cargo build --release

```console
./tasks/coverage.sh
# build the wasm release
wasm-pack build --all-features --target=nodejs
```

### Making changes

Following guidance is for making changes in your fork and pushing changes to your fork's remote:
## Testing the Project

```console
git status
git add <file-name or .>
git commit -m "<commit message following https://www.conventionalcommits.org/en/v1.0.0/#summary>"
git push
```
```bash
# run all tests
cargo test

Once you have done the above, you can then [create a PR from your fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork).
# run clippy to lint
cargo clippy
```
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cdk-from-cfn"
version = "0.182.0"
version = "0.183.0"
edition = "2021"
rust-version = "1.84"
description = "Turn AWS CloudFormation templates into AWS CDK applications"
Expand Down
34 changes: 25 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,37 @@
# cdk-from-cfn

In a world where people want to use the full extent of the cdk, there **was** no product that would transform all your
JSON/YAML into beautiful typescript...until now.
`cdk-from-cfn` is a command-line tool that converts AWS CloudFormation templates into AWS CDK code. It supports multiple programming languages including TypeScript, Python, Java, Go, and C#.

`cdk-from-cfn` will take your JSON/YAML and output the equivalent typescript.
## Installation

## User Guide
```console
$ cargo install cdk-from-cfn
```

## Usage

```console
$ cargo build --release
$ ./target/release/cdk-from-cfn [INPUT] [OUTPUT]
$ cdk-from-cfn [INPUT] [OUTPUT] --language <LANGUAGE> --stack-name <STACK_NAME>
```

- `INPUT` is the input file path (STDIN by default).
- `OUTPUT` is the output file path; if not specified, output will be printed on your command line (STDOUT by default).

### Cargo Features
## Node.js Module Usage

cdk-from-cfn leverages WebAssembly (WASM) bindings to provide a cross-platform [npm](https://www.npmjs.com/package/cdk-from-cfn) module, which exposes apis to be used in Node.js projects. Simply take a dependency on `cdk-from-cfn` in your package.json and utilize it as you would a normal module. i.e.

```typescript
import * as cdk_from_cfn from 'cdk-from-cfn';

// get supported languages
cdk_from_cfn.supported_languages();

// transmute cfn template into cdk app
cdk_from_cfn.transmute(template, language, stackName)
```

## Language and Feature support

Name | Enabled by default | Description
-------------|:------------------:|---------------------------------------------
Expand All @@ -39,7 +55,7 @@ $ cargo build --release --no-default-features --features=golang
Finished release [optimized] target(s) in 0.17s
```

## Implemented
### Implemented

- [x] Fn::FindInMap
- [x] Fn::Join
Expand All @@ -63,7 +79,7 @@ Finished release [optimized] target(s) in 0.17s
- [x] Deletion policy
- [x] Fn::Cidr support

## Remaining
### Remaining

There are known unsupported features. Working on them in priority order:

Expand Down
2 changes: 1 addition & 1 deletion src/synthesizer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ their specific use-cases, reducing compilation time and binary size. Languages
considered "stable" are however enabled by default, while "experimental" targets
are opt-in.

The `Synthesizer` API is very simple, reciving a CloudFormation Template IR
The `Synthesizer` API is very simple, receiving a CloudFormation Template IR
object, and a `Writer` to which the generated code should be written. The
`cdk_from_cfn::code` module provides assistance for generating code, in
particular for maintaining correct indentation levels.