https://github.com/tjirsch/rs-cfg2hcl
A tool to transpile compact YAML infrastructure definitions into OpenTofu/Terraform HCL. Builtin functions to bootstrap a Google Cloud Organization and do state import, migration and discovery of an existing GCP Organization from state or live infrastructure.
https://github.com/tjirsch/rs-cfg2hcl
discovery gcp google hcl opentofu
Last synced: 4 months ago
JSON representation
A tool to transpile compact YAML infrastructure definitions into OpenTofu/Terraform HCL. Builtin functions to bootstrap a Google Cloud Organization and do state import, migration and discovery of an existing GCP Organization from state or live infrastructure.
- Host: GitHub
- URL: https://github.com/tjirsch/rs-cfg2hcl
- Owner: tjirsch
- License: mit
- Created: 2026-02-13T12:27:28.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-02-13T15:21:13.000Z (4 months ago)
- Last Synced: 2026-02-14T01:32:36.715Z (4 months ago)
- Topics: discovery, gcp, google, hcl, opentofu
- Language: Rust
- Homepage:
- Size: 147 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# cfg2hcl
A tool to transpile compact YAML infrastructure definitions into OpenTofu/Terraform HCL.
Builtin functions to bootstrap a Google Cloud Organization and do state import, migration and discovery of an existing GCP Organization from state or live infrastructure.
## Folder Structure
The project is structured such that `cfg2hcl` (the tool) is kept separate from customer-specific definitions. Each customer repository follows this layout:
```text
customer-repo/ (e.g. project-root/)
├── config.toml # Tool configuration for this customer
├── schemas/ # JSON schemas for used cloud providers
├── yaml/ # Infrastructure definitions
└── hcl/ # Generated .tf files
```
### Global Options
These options can be placed anywhere in the command (e.g., before or after subcommands):
- `-c, --config `: Path to tool config file. Mandatory for most commands if `config.toml` is not in the current directory.
- `-v, --validation `: Validation level for mandatory parameters (`warn`, `error`, `none`).
- `--verbose`: Enable verbose output. When invoked without a subcommand (e.g. `cfg2hcl --verbose`), prints full recursive help listing all subcommands and their options.
## Installation
### Using cargo-dist Installer (Recommended)
Install the latest release using the cargo-dist installer:
```bash
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/tjirsch/rs-cfg2hcl/releases/latest/download/cfg2hcl-installer.sh | sh
```
This will install `cfg2hcl` to `~/.local/bin` and automatically add it to your PATH if needed.
> **Note:** The installer will:
> - Install the binary to `~/.local/bin`
> - Check if this directory is on your PATH
> - If not, add it to your shell profile (e.g., `.bashrc`, `.zshrc`)
> - Provide instructions to refresh your shell
>
> If you prefer a different location, you can override it:
> ```bash
> curl --proto '=https' --tlsv1.2 -LsSf https://github.com/tjirsch/rs-cfg2hcl/releases/latest/download/cfg2hcl-installer.sh | CARGO_DIST_FORCE_INSTALL_DIR=/your/custom/path sh
> ```
> **Note:** The installer script is generated automatically when releases are created. If you get a 404 error, it means no releases have been published yet. Use the "From Source" method below instead.
### From Source
To install the binary to `/usr/local/bin` (requires sudo):
```bash
cargo xtask install
```
This command safely builds the release binary as your user and then uses `sudo` only for the copy step. It works from any subdirectory in the project.
Alternatively, install directly with cargo:
```bash
cargo install --path .
```
This installs to `~/.cargo/bin` (no sudo required).
## CLI Usage
### Initialize Project (`init`)
Bootstrap a new project directory with default folders, config, .gitignore, and schemas.
```bash
cfg2hcl init \
--customer-id C01234567 \
--customer-shortname example-org \
--billing-account-infra A12345-B67890-C12345 \
--customer-domain example.com \
--customer-organization-id "123456789012"
```
**Parameters:**
- `--defaults `: Default provider sets to include (e.g., `google`).
- `--providers `: Explicit providers to include (e.g., `aws`, `azure`, `google`).
- `--tf-tool `: Terraform binary to use (default: `tofu`).
- `--customer-id `: Workspace Organization ID (e.g., `C01234567`).
- `--customer-shortname `: Short slug for the customer.
- `--billing-account-infra `: Billing account ID.
- `--customer-organization-id `: GCP Organization ID.
- `--customer-domain `: Primary domain name.
- `--iac-user `: Initial Admin User (default: `first.admin@`).
- `--default-region `: Default GCP region (default: `europe-west3`).
- `--infra-project-name `: Override for the infrastructure project ID.
- `--infra-bucket-name `: Override for the state bucket name.
**Under the Hood:**
- Creates the standardized directory structure: `yaml/`, `hcl/`, `schemas/`.
- Generates a default `config.toml` and `.gitignore`.
- If customer details are provided, generates a template YAML file in `yaml/`.
- Fetches the latest provider schemas for the configured providers.
### Day 0 Bootstrap (`bootstrap`)
The `bootstrap` command automates the entire onboarding process for a new customer organization.
```bash
cfg2hcl bootstrap [options]
```
**Parameters:**
- ``: Path to the YAML config file (e.g., `yaml/C01234567.yaml`).
- `--dry-run`: Simulation mode; does not create resources.
**Tip:** Use `--dry-run` to see what resources would be created without making changes.
**Tip:** For a declarative approach, set `deployment-mode: boot` in your YAML and run `transpile`.
**Under the Hood:**
1. **Authentication**: Uses Application Default Credentials (ADC).
2. **Infrastructure Folder**: Checks availability or creates the top-level folder (requires `Folder Admin`).
3. **Project Shell**: Creates the management project (project-id defaults to `shortname-iac-infra`) inside the folder.
4. **Billing Link**: Links the project to the specified Billing Account.
5. **Enable APIs**: Enables critical foundation APIs (Service Usage, Cloud Resource Manager, IAM, Storage).
6. **State Bucket**: Creates the GCS bucket for Terraform state (with versioning, uniform access).
7. **Automated Setup**:
- **Transpile**: Converts the YAML to HCL.
- **Init**: Runs `tofu init` to download plugins.
- **Import**: Automatically imports the created Folder, Project, and Bucket into the local state.
### Transpile (`transpile`)
Convert your YAML configuration to production-ready HCL.
```bash
cfg2hcl transpile [options]
```
**Parameters:**
- ``: Name of the input YAML file. This is resolved relative to the `yaml_dir` defined in your config.
- `--output, -o `: Optional output subdirectory or absolute path. By default, output goes to `hcl_dir`.
- `--schema-dir, -s `: Override the schema directory.
**Running from subdirectories:**
You can run the transpile command from any directory (e.g., from within the `hcl/` folder) by specifying the config path. Both styles are supported:
```bash
# Global option before subcommand
cfg2hcl --config ../config.toml transpile my-infra.yaml
# Global option after subcommand (Recommended)
cfg2hcl transpile my-infra.yaml --config ../config.toml
```
This will correctly look for `../yaml/my-infra.yaml` and update the files in the current directory.
**Under the Hood:**
- Reads the YAML file and processes any `!include` tags.
- strict Validation: Checks the YAML against the loaded provider schemas `schemas/*.json` to ensure all required fields are present.
- Merges variables from the `variables` block into the configuration.
- Generates four files in the output directory:
- `main.tf`: Resources.
- `providers.tf`: Provider configurations and aliases.
- `variables.tf`: Variable declarations.
- `terraform.tfvars`: Variable values.
- `imports.tf`: (Optional) OpenTofu `import` blocks for existing resources.
### Resource Imports
`cfg2hcl` supports declarative resource imports using the OpenTofu/Terraform 1.5+ `import` block logic. This allows you to bring existing cloud resources under management without manually running CLI `import` commands.
#### Declarative Imports (via `import-id`)
To import an existing resource, add the `import-id` tag to its definition in your YAML:
```yaml
google_org_policy_policy:
iam.disableServiceAccountKeyCreation:
import-id: "organizations/12345/policies/iam.disableServiceAccountKeyCreation"
spec:
rules:
- enforce: "TRUE"
```
**How it works:**
- **`import-id: ""`**: Provide the full GCP resource ID.
- **`imports.tf` Generation**: The transpiler detects the `import-id` and generates a corresponding OpenTofu `import` block in `hcl/imports.tf`.
- **Automatic Lifecycle**: `imports.tf` is automatically deleted before each `transpile` run and only recreated if `import-id` tags are found.
- **Execution**: Running `tofu plan` (or `apply`) will show these resources as "to be imported".
#### Automatic Imports during Bootstrap
The `bootstrap` command automatically handles the import of core infrastructure resources (Folder, Project, and State Bucket) into your initial state so you don't have to manually link them.
> [!NOTE]
> Declarative imports require **OpenTofu** or **Terraform 1.5.0+**. For older versions, traditional CLI `tofu import` must be used.
### Mode Switching & State Migration (`migrate`)
Seamlessly move your project between development (`local`) and production (`cloud`) modes.
```bash
cfg2hcl migrate --mode
```
**Parameters:**
- ``: Name of the input YAML file.
- `--mode, -m `: Target mode (`local` or `cloud`).
**Under the Hood:**
- **Update YAML**: Modifies the `deployment-mode` anchor in the source YAML file.
- **Regenerate**: Runs `transpile` to update the backend configuration (Local vs GCS) and provider authentication (ADC vs Impersonation).
- **Migrate State**: Executes `tofu init -migrate-state` to safely move your terraform state to the new backend.
### Infrastructure Discovery
`cfg2hcl` provides two discovery commands to generate YAML configurations from existing infrastructure.
#### Discover from Terraform State (`discover-from-state`)
Read an existing Terraform/OpenTofu state and generate a corresponding YAML configuration.
```bash
cfg2hcl discover-from-state --output discovered.yaml
```
**Parameters:**
- `--state-json `: Path to Terraform state JSON file (optional). If omitted, runs `tofu show -json`.
- `--output, -o `: Path to output YAML file (default: `discovered.yaml`).
- `--add-import-id`: Add `import-id` tag to every resource for declarative imports.
- `--add-import-id-as-comment`: Add `import-id` as a comment to every resource.
- `--discovery-config `: Path to discovery configuration YAML file (default: `presets/discovery-config.yaml`).
**Under the Hood:**
- Reads the current state (either from a file or by running `tofu show -json`).
- Reverse-engineers the resources to match the `cfg2hcl` YAML structure.
- **Configurable Filtering**: respects `presets/discovery-config.yaml` to include/exclude specific resources and attributes.
- Resource types can be globally enabled/disabled (`import: true/false`).
- Specific attributes can be filtered via `exclude` and `include` lists per resource.
- **Schema Validation**: Automatically validates discovered data against the Terraform Provider Schema, dropping read-only or computed fields that would cause HCL generation errors.
- **IAM Heuristics**: Intelligently maps complex IAM resources (like `google_storage_bucket_iam_member`) to simplified, project-nested YAML structures.
#### Discover from GCP Organization (`discover-from-organization`)
Discover infrastructure directly from a GCP Organization using the Cloud Asset API and generate a YAML configuration.
```bash
cfg2hcl discover-from-organization --customer-organization-id "123456789012" --output discovered.yaml
```
**Parameters:**
- `--customer-organization-id `: Numeric GCP Organization ID (required).
- `--output, -o `: Path to output YAML file (default: `discovered.yaml`).
- `--add-import-id`: Add `import-id` tag to every resource for declarative imports.
- `--add-import-id-as-comment`: Add `import-id` as a comment to every resource.
- `--discovery-config `: Path to discovery configuration YAML file (default: `presets/discovery-config.yaml`).
**Under the Hood:**
- Uses Google Cloud Asset API to enumerate all resources in the organization.
- Requires appropriate IAM permissions (`cloudasset.assets.searchAllResources`).
- Applies the same filtering and validation as `discover-from-state`.
- Useful for discovering infrastructure that isn't managed by Terraform/OpenTofu yet.
### Update Schemas (`update-schema`)
Refresh local provider schemas to get the latest resource definitions.
```bash
cfg2hcl update-schema --providers google,google-beta
```
**Parameters:**
- `--providers, -p `: Comma-separated list of providers to update.
- `--version, -v `: Provider version to fetch (default: from config).
- `--tf-tool, -t `: Terraform/OpenTofu binary to use.
**Under the Hood:**
- runs `tofu init` in a temporary directory.
- runs `tofu providers schema -json` to export the latest definitions.
- Updates the JSON files in `schemas/`.
### Self-update (`self-update`)
Check for and install a new release from GitHub. After a successful install, the tool downloads the release README and prints its full path, then opens it unless you pass the options below.
```bash
cfg2hcl self-update [options]
```
**Parameters:**
- `--no-download-readme`: Do not download README.md after installing.
- `--no-open-readme`: Download README and print its path, but do not open it (only applies if download runs).
**Under the Hood:**
- Fetches the latest release from the GitHub API, compares versions, and runs the cargo-dist installer script when a newer version is available. On success, optionally downloads `README.md` from the repo and prints its path (e.g. `README: /Users/you/Downloads/cfg2hcl-0.4.9-README.md`).
## Day 0 Onboarding Playbook
This section outlines the step-by-step process for onboarding a new Google Cloud Organization.
### Phase 1: Preparation
#### Prerequisites
Ensure the executing user has:
- **Superadmin** access to the Google Workspace / Cloud Identity.
- **Organization Administrator** role on the GCP Organization.
- **Billing Account Administrator** on the target billing account (must be granted in the Reseller Console).
#### Workspace Setup
1. Authenticate with Google Cloud:
```bash
gcloud auth application-default login
```
2. Initialize the tool configuration and folder structure:
```bash
cfg2hcl init \
--customer-id "C01234567" \
--customer-shortname "example-org" \
--billing-account-infra "A12345-B67890-C12345" \
--customer-domain "example.com" \
--customer-organization-id "123456789012" \
--iac-user "admin@example.com"
```
### Phase 2: Fundamental Infrastructure
#### 1. Bootstrap Core Resources
The `bootstrap` command automates the entire process: creating the infrastructure folder, project, bucket, linking billing, enabling foundation APIs (fixing the "chicken-and-egg" problem), and initializing the state.
```bash
cfg2hcl bootstrap yaml/C01234567.yaml
```
**What this does:**
- Creates Folder, Project, Bucket, Service Account.
- Enables Service Usage, IAM, and other core APIs.
- Assigns `Folder Admin` to the user executing the bootstrap (if missing).
- Automatically runs `transpile`, `init`, and `import` to bring resources under Terraform management.
#### 2. (Optional) Customize & Transpile
*Only needed if you modify the generated YAML configuration after bootstrap.*
Modify `yaml/C01234567.yaml` as needed, then manually generate the HCL:
```bash
cfg2hcl transpile C01234567.yaml
```
#### 3. (Optional) Configure Identity
*Only needed if the default identity setup from bootstrap was insufficient.*
If customization was done, re-run initialization:
```bash
cd hcl
tofu init
tofu apply
```
### Phase 3: Identity & Access Rollout
#### 1. Apply Management Infrastructure
Run the first Tofu apply. This creates the **Identity Groups**, attaches the necessary **IAM roles** (including `Token Creator`), and finalizes the management project.
```bash
cd hcl/
tofu plan
tofu apply
```
### Phase 4: Cloud Migration
#### 1. Perform State Migration
Toggle to `cloud` mode and move state to the GCS bucket:
```bash
cfg2hcl migrate C01234567.yaml --mode cloud
```
The tool automatically updates the YAML, switches to **Service Account Impersonation**, and runs `tofu init -migrate-state`.
#### 2. Verification
In `cloud` mode, verify that you can plan/apply using the restricted service account identity:
```bash
tofu plan
```
#### Template Variables Reference
When you run `init`, the following variables are generated in the template:
| Variable | Default | Description |
|----------|---------|-------------|
| `infra-folder-name` | `Infrastructure` | Display name for the top-level folder. Leave `""` to create the project in the root. |
| `infra-project-name` | `""` | The unique ID for the management (IaC) project. |
| `infra-bucket-name` | `""` | The name of the GCS bucket for Terraform state. |
| `customer-id` | (from CLI) | The Workspace Organization ID (e.g., `C01234567...`). |
| `customer-organization-id` | `"123456789012"` | The numeric Google Cloud Organization ID. **Note:** Always use quotes, otherwise YAML interprets this as a number. |
| `customer-domain` | `""` | The customer's primary domain (e.g., `example.com`). |
| `customer-longname` | `""` | The full legal name of the customer entity. |
| `customer-shortname` | `""` | A unique slug or shortname for the customer. |
| `svc-iac-account` | `svc-iac-001` | The name/ID of the primary IaC Service Account. |
| `svc-iac-users-group` | `svc-iac-users` | The Cloud Identity group for IaC administrators. |
| `billing-account-infra` | `""` | The Billing Account ID (e.g., `A12345-B67890-C12345`). |
| `deployment-engine` | `tofu` | The IaC tool: `tofu` or `terraform`. |
| `deployment-mode` | `local` | `local` for Day 0 (User ADC); `cloud` for Day 1+ (Impersonation). |
| `default-region` | `europe-west3` | Default region for regional resources. |
| `default-zone` | `europe-west3-a` | Default zone for zonal resources. |
### 3. Transpile
Convert a YAML file to HCL. Run this from within the customer repository directory.
```bash
cfg2hcl transpile my-infra.yaml
```
- Input is read from `yaml_dir` (e.g., `./yaml/my-infra.yaml`).
- Output is written directly to the `hcl_dir` defined in your config.
- **Run from anywhere**: All paths are resolved relative to the configuration file's directory.
- **Automatic Schema Sync**: The tool will automatically fetch missing provider schemas via `tofu/terraform` during transpilation.
## YAML Configuration
The input YAML file is the source of truth for your infrastructure.
### Terraform & Backend
The `terraform` block is mandatory and used primarily for backend configuration.
```yaml
terraform:
backend:
gcs:
bucket: "my-infra-bucket"
prefix: "project-a"
```
### Providers
Define one or more provider instances.
```yaml
providers:
google:
region: "europe-west3"
zone: "europe-west3-a"
google: # Support for multiple aliased providers
- alias: "secondary"
region: "us-central1"
```
### Variables
Declare variables in a `variables` block. They are automatically merged to the root context and can be used with YAML anchors.
```yaml
variables:
customer-id: &customer-id "C34projectroot"
region: ®ion "europe-west3"
google_project:
my-project:
project_id: *customer-id
```
- Variables are declared as `string` types in `_variables.tf`.
- Values are written to `.tfvars`.
### 3. Update Schemas
Refresh provider schemas manually.
```bash
cfg2hcl update-schema --providers google,google-beta
```
## Configuration (config.toml)
The tool reads its settings from `config.toml`. Default values are:
| Key | Default | Description |
|-----|---------|-------------|
| `yaml_dir` | `"yaml"` | Source directory for YAML files |
| `hcl_dir` | `"hcl"` | Target directory for generated HCL |
| `schema_dir` | `"schemas"` | Directory where provider schemas are cached |
| `include_dirs` | `[".", "yaml"]` | Search paths for `!include` files |
| `tf_tool` | `"tofu"` | The binary used to fetch schemas |
| `google_providers` | `["google", "google-beta"]` | List of Google providers |
| `provider_version` | `"7.12.0"` | Provider version to use |
| `auto_explode` | `["google_project_service", ".*_iam_member"]` | Resources that use compact explosion |
| `validation_level` | `"warn"` | Validation level for mandatory parameters |
## Schema Validation
The tool automatically checks your YAML against the provider schemas to ensure all mandatory parameters and blocks are present.
- **Attributes**: Checks for `required` fields (e.g., `project_id`).
- **Blocks**: Checks for mandatory blocks with `min_items > 0` (e.g., `boot_disk` for a VM).
You can control the strictness via CLI `--validation` or `config.toml`.
## YAML Features
### Custom YAML Tags
Enhance your configuration with dynamic logic:
- **`!include `**: Recursively include other YAML snippets.
- **`!format [template, arg1, arg2]`**: Dynamic string formatting using placeholders (`{}`).
```yaml
member: !format
- "serviceAccount:svc-iac-001@{}.iam.gserviceaccount.com"
- *infra-project-name
```
- **`!join [arg1, arg2, ...]`**: Concatenate multiple values into a single string.
### Conditional Folding
Setting a folder's `display_name` to an empty string (`""`) will skip the `google_folder` resource and "implode" its contents into the parent context. This is useful for conditionally creating folders based on variables.
### Compact Explosion (CEX)
Resources named with a `CEX_` prefix (or listed in `auto_explode`) support compact definition styles:
- **IAM**: Define many roles for one member in a simple block.
- **Services**: Enable lists of GCP services in one block.
## Core Principles
The tool follows a central design philosophy based on **Hierarchy Context**, **Attribute Inheritance**, and **Strict Validation**.
### 1. Hierarchy Context & Nesting
Resources are defined within the context of their parent in the organization hierarchy:
- **Project Context**: Resources that require a project (e.g., Buckets, VMs, Networks) are usually nested directly within a `google_project` definition.
- **Folder Context**: Resources belonging to a folder (e.g., Folder IAM members) are usually nested within a `google_folder` block.
- **Organization Context**: Organization-wide resources (e.g., Group memberships, Org IAM) are defined at the root level of the YAML.
- **Explicit Placement**: Any resource can be defined outside its logical hierarchy container if the identifying parameter (e.g., `project_id`, `folder`) is provided explicitly.
### 2. Attribute Inheritance (Narrowest Context)
Nested resources automatically inherit identity attributes from their surrounding context if not explicitly defined:
- **Automatic Matching**: The tool identifies which identifier a resource needs based on its schema (e.g., `project_id`, `project`, `folder_id`, `org_id`).
- **Inheritance**:
- A resource inside a Project context inherits the Project ID.
- A resource inside a Folder context inherits the Folder ID.
- **Narrowest First**: If a resource is defined in a scope where multiple contexts apply (e.g., inside a Project which is inside a Folder), it inherits from the **most specific (narrowest)** context available.
- **Explicit Override**: Explicitly provided attributes in the YAML always take precedence over inherited context values.
### 3. Context Validation & Typo Detection
To ensure configuration correctness, nested blocks are strictly validated:
- **Attribute vs. Resource**: Every key within a `Project` or `Folder` block must be either:
- A valid native attribute/block of the parent resource (e.g., `name` for a project).
- A valid resource type from the cloud provider schema.
- **Error Detection**: Any key that is neither a known attribute nor a known resource type is treated as a typo and triggers a **Warning**.
- **Missing Context**: Resources that require a project or folder identifier but are defined outside such a context (without an explicit identifier provided) will trigger a **Warning**.
### 4. Flexible Placement
While the tool encourages a clean hierarchy, it allows placing cross-context resources (like `google_cloud_identity_group`) inside a Project block for configuration convenience (e.g., defining project-relevant groups near the project). The transpiler will process these correctly, ignoring the project context where it doesn't apply to the resource's schema.
## Handling Resource Renames (State Migration)
If you rename a resource in your YAML, the transpiler will generate a new HCL label. OpenTofu will see this as a "delete and recreate" action. To avoid downtime, you can use the built-in migration suite:
1. **Iterate Locally**: Use `tofu plan -out=plan.binary` and `tofu show -json plan.binary > plan.json` to identify changes.
2. **Map Moves**: Use `cfg2hcl scan-plan plan.json` to generate a `mapping.yaml`.
3. **Apply Renames**: Run `cfg2hcl generate-migration mapping.yaml` and execute the resulting script to perform the `mv` commands safely.
For switching between local and cloud backends, always use the high-level `cfg2hcl migrate` command.
### Scan Plan (`scan-plan`)
Analyze a Terraform/OpenTofu plan JSON file to identify resource renames and generate a mapping file.
```bash
cfg2hcl scan-plan plan.json --output mapping.yaml
```
**Parameters:**
- ``: Path to the plan JSON file (required).
- `--output `: Path to output mapping YAML file (default: `mapping.yaml`).
**Under the Hood:**
- Parses the plan JSON to identify resources that are being destroyed and recreated with new addresses.
- Generates a mapping file that correlates old and new resource addresses.
- The mapping file can be used with `generate-migration` to create state move commands.
### Generate Migration (`generate-migration`)
Generate a shell script with `tofu state mv` commands from a mapping YAML file.
```bash
cfg2hcl generate-migration mapping.yaml --output migrate.sh
```
**Parameters:**
- ``: Path to the mapping YAML file (default: `mapping.yaml`).
- `--output `: Path to output shell script (default: `migrate.sh`).
**Under the Hood:**
- Reads the mapping file generated by `scan-plan`.
- Generates a shell script with `tofu state mv` commands to safely rename resources in the state.
- The script can be reviewed and executed manually to perform the state migration.
## Day 0: Migration Playbook
This section outlines the general process for migrating existing infrastructure into `cfg2hcl` management.
### 1. State Discovery
Begin by capturing the current infrastructure state. If you have an existing Terraform/OpenTofu project, generate a JSON state file and use the discovery tool:
```bash
tofu show -json > state.json
cfg2hcl discover-from-state --state-json state.json --output yaml/migration-discovery.yaml
```
Alternatively, if you want to discover infrastructure directly from GCP without Terraform state:
```bash
cfg2hcl discover-from-organization --customer-organization-id "123456789012" --output yaml/migration-discovery.yaml
```
### 2. Hierarchical Refinement
The discovery tool produces a relatively flat YAML structure. Organize this into the `cfg2hcl` hierarchical format:
- Move projects into their respective folders.
- Nest resources (Buckets, Networks, etc.) inside their projects to leverage **Attribute Inheritance**.
- Remove redundant attributes (like `project_id`) that are now inherited from the context.
### 3. Resource Optimization
Convert standard resource definitions into optimized `cfg2hcl` patterns:
- **Services**: Group `google_project_service` resources into a single `project_service` list.
- **IAM**: Combine individual IAM members into compact `project_iam_member` or `folder_iam_member` blocks.
- **Formatting**: Ensure attributes with sub-structures (e.g., `project_service` with `disable_on_destroy`) are correctly indented.
### 4. Validation & Reconciliation
Generate the HCL and compare it with the live environment:
1. Run `cfg2hcl transpile migration-discovery.yaml`.
2. Run `tofu plan` in the `hcl/` directory.
3. **Reconcile**: If the plan shows "replace" instead of "no changes", it means the HCL labels or resource IDs don't match.
- Use `import-id` in the YAML to link existing resources.
- Or use `tofu state mv` to align the existing state with the new HCL labels.
### 5. Transition to Management
Once `tofu plan` shows no changes (or only intended updates), the migration is complete. You can now manage the infrastructure exclusively through the YAML configuration.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.