|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Module Overview |
| 6 | + |
| 7 | +This is a Terraform module for Snowflake Warehouse management that: |
| 8 | +- Creates Snowflake warehouses with comprehensive configuration options |
| 9 | +- Manages role-based access control through default and custom roles |
| 10 | +- Uses CloudPosse context provider for flexible naming conventions |
| 11 | +- Integrates with getindata/role/snowflake module (v4.0.0) for role management |
| 12 | + |
| 13 | +## Architecture |
| 14 | + |
| 15 | +### Naming Convention System |
| 16 | + |
| 17 | +The module uses CloudPosse context provider instead of deprecated `context.tf` (nulllabel): |
| 18 | + |
| 19 | +1. **Context Provider Setup**: The `data.context_label.this` data source generates resource names based on templates |
| 20 | +2. **Template Resolution**: `context_templates` variable defines naming patterns (e.g., `{{.environment}}_{{.name}}`) |
| 21 | +3. **Name Scheme Configuration**: Each resource has configurable `name_scheme` with properties, delimiter, and template selection |
| 22 | +4. **Template Lookup**: `local.context_template` resolves which template to use from `var.context_templates` |
| 23 | + |
| 24 | +Key files: |
| 25 | +- [locals.tf:1-3](locals.tf#L1-L3) - Template resolution logic |
| 26 | +- [main.tf:1-12](main.tf#L1-L12) - Context label data source usage |
| 27 | + |
| 28 | +### Role Management Architecture |
| 29 | + |
| 30 | +The module creates two types of roles through a merge-and-split pattern: |
| 31 | + |
| 32 | +1. **Default Roles** ([locals.tf:14-42](locals.tf#L14-L42)): Pre-defined functional roles (admin, usage, monitor) |
| 33 | +2. **Custom Roles** ([locals.tf:44-47](locals.tf#L44-L47)): User-provided roles via `var.roles` |
| 34 | +3. **Deep Merge** ([locals.tf:68-73](locals.tf#L68-L73)): Uses `Invicton-Labs/deepmerge/null` to merge default + provided roles |
| 35 | +4. **Split Logic** ([locals.tf:50-57](locals.tf#L50-L57)): Separates merged roles into default vs custom for different module calls |
| 36 | + |
| 37 | +Role modules are instantiated separately: |
| 38 | +- [main.tf:44-71](main.tf#L44-L71) - Default roles module |
| 39 | +- [main.tf:73-100](main.tf#L73-L100) - Custom roles module |
| 40 | + |
| 41 | +### Resource Structure |
| 42 | + |
| 43 | +- **Primary Resource**: `snowflake_warehouse.this` ([main.tf:14-39](main.tf#L14-L39)) |
| 44 | +- **Role Grants**: Handled by nested `getindata/role/snowflake` modules with `account_objects_grants` |
| 45 | +- **State Migration**: `moved` block at [main.tf:40-43](main.tf#L40-L43) handles v2 to v3 upgrade |
| 46 | + |
| 47 | +## Common Commands |
| 48 | + |
| 49 | +### Development Workflow |
| 50 | + |
| 51 | +```bash |
| 52 | +# Initialize module |
| 53 | +terraform init |
| 54 | + |
| 55 | +# Validate configuration |
| 56 | +terraform validate |
| 57 | + |
| 58 | +# Format code |
| 59 | +terraform fmt -recursive |
| 60 | + |
| 61 | +# Run pre-commit hooks (validates, formats, lints, generates docs, security scan) |
| 62 | +pre-commit install |
| 63 | +pre-commit run --all-files |
| 64 | +``` |
| 65 | + |
| 66 | +### Testing with Examples |
| 67 | + |
| 68 | +```bash |
| 69 | +# Simple example |
| 70 | +cd examples/simple |
| 71 | +make init |
| 72 | +make plan |
| 73 | +make apply |
| 74 | + |
| 75 | +# Complete example (full configuration) |
| 76 | +cd examples/complete |
| 77 | +make init |
| 78 | +make plan |
| 79 | +make apply |
| 80 | +``` |
| 81 | + |
| 82 | +### Documentation Generation |
| 83 | + |
| 84 | +```bash |
| 85 | +# Auto-generate README inputs/outputs tables |
| 86 | +terraform-docs . |
| 87 | +``` |
| 88 | + |
| 89 | +## Pre-commit Configuration |
| 90 | + |
| 91 | +The module uses pre-commit hooks in this order: |
| 92 | +1. `terraform-validate` - Must run first (performs `terraform init` required by tflint) |
| 93 | +2. `terraform-fmt` - Code formatting |
| 94 | +3. `tflint` - Terraform linting |
| 95 | +4. `terraform-docs` - Auto-generates documentation |
| 96 | +5. `checkov` - Security scanning (skips CKV_TF_1 for module sources) |
| 97 | + |
| 98 | +## Provider Version Requirements |
| 99 | + |
| 100 | +- **Snowflake Provider**: `>= 2.7` (snowflakedb/snowflake) |
| 101 | +- **Context Provider**: `>= 0.4.0` (cloudposse/context) |
| 102 | +- **Terraform**: `>= 1.3` |
| 103 | + |
| 104 | +**IMPORTANT**: ALWAYS use `snowflakedb/snowflake` provider. NEVER use `Snowflake-Labs/snowflake` provider. The Snowflake-Labs provider is deprecated and should not be used in any configuration or documentation queries. |
| 105 | + |
| 106 | +## Breaking Changes |
| 107 | + |
| 108 | +### v3.x Migration |
| 109 | +- Removed `context.tf` (nulllabel) - switched to context provider |
| 110 | +- Removed variables: `context`, `enabled`, `environment`, `namespace`, `tenant`, `stage`, `attributes`, `delimiter`, `tags`, `labels_as_tags`, etc. |
| 111 | +- Added: `context_templates` and `name_scheme` variables |
| 112 | +- State migration handled via `moved` blocks |
| 113 | + |
| 114 | +### v4.x Migration |
| 115 | +- Provider source changed from `Snowflake-Labs/snowflake` to `snowflakedb/snowflake` |
| 116 | + |
| 117 | +## Key Variables |
| 118 | + |
| 119 | +### Required |
| 120 | +- `name` - Base name for the warehouse resource |
| 121 | + |
| 122 | +### Naming Configuration |
| 123 | +- `name_scheme` - Object controlling naming behavior (properties, delimiter, template, regex, uppercase) |
| 124 | +- `context_templates` - Map of go-template strings for naming patterns (supersedes name_scheme properties/delimiter) |
| 125 | + |
| 126 | +### Warehouse Configuration |
| 127 | + |
| 128 | +- `warehouse_size`, `warehouse_type` - Warehouse compute settings |
| 129 | +- `generation` - Warehouse generation (only for STANDARD warehouses). Valid values: "1" or "2" (string type, not number - this is dictated by the Snowflake provider schema) |
| 130 | +- `auto_resume`, `auto_suspend`, `initially_suspended` - Power management |
| 131 | +- `min_cluster_count`, `max_cluster_count`, `scaling_policy` - Multi-cluster settings |
| 132 | +- `enable_query_acceleration`, `query_acceleration_max_scale_factor` - Query acceleration |
| 133 | +- `resource_monitor` - Credit quota monitoring |
| 134 | + |
| 135 | +### Role Management |
| 136 | +- `create_default_roles` - Boolean to create admin/usage/monitor roles |
| 137 | +- `roles` - Map of role definitions with grants and assignments |
| 138 | + |
| 139 | +## Examples Structure |
| 140 | + |
| 141 | +- **simple/** - Minimal configuration showing basic warehouse creation |
| 142 | +- **complete/** - Full-featured example with: |
| 143 | + - Resource monitor integration |
| 144 | + - Default roles enabled |
| 145 | + - Custom role with specific privileges |
| 146 | + - Multiple naming scheme patterns |
| 147 | + - Context template usage |
| 148 | + - Generation 2 warehouse configuration (warehouse_3) |
| 149 | + |
| 150 | +## Important Implementation Notes |
| 151 | + |
| 152 | +### Generation Field |
| 153 | + |
| 154 | +- Type: `string` (not `number`) - this is required by the Snowflake provider schema, not a design choice |
| 155 | +- Valid values: `"1"`, `"2"` |
| 156 | +- Only applicable to STANDARD warehouse type |
| 157 | +- Validation uses ternary operator to handle null: `var.generation == null ? true : contains(["1", "2"], var.generation)` |
| 158 | +- Added in provider version 2.7+ |
| 159 | +- The string type requirement comes from how Snowflake's SQL interface and provider handle this parameter |
| 160 | + |
| 161 | +### Variable Validation Pattern |
| 162 | + |
| 163 | +When validating optional (nullable) variables with `contains()`, use ternary operator to avoid null evaluation errors: |
| 164 | + |
| 165 | +```hcl |
| 166 | +validation { |
| 167 | + condition = var.field == null ? true : contains(["val1", "val2"], var.field) |
| 168 | + error_message = "Invalid value" |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +Do NOT use: `var.field == null || contains([...], var.field)` as it will fail when the value is null. |
0 commit comments