Provider Definition Specification¶
Audience: Contributors | Status: Stable — Internal | Verified against: v0.43.0
CloudBlocks uses ProviderDefinition as the canonical provider abstraction for generation.
This keeps the architecture model provider-neutral while allowing Terraform, Bicep, and Pulumi output from the same model. Provider coverage varies by template, resource, and export path — the learning experience is provider-aware, not provider-locked.
Purpose¶
The provider layer exists to:
- map generic block concepts to provider resources
- preserve provider-neutral modeling in the architecture DSL
- enable consistent multi-generator output from one provider definition
- surface unsupported mappings explicitly instead of silently dropping resources
Canonical Abstraction: ProviderDefinition¶
ProviderDefinition is the single source of truth for provider generation behavior.
interface ProviderDefinition {
name: ProviderType;
displayName: string;
blockMappings: BlockResourceMap;
containerBlockMappings: ContainerBlockResourceMap;
generators: {
terraform: TerraformProviderConfig;
bicep: BicepProviderConfig;
pulumi: PulumiProviderConfig;
};
subtypeBlockMappings?: SubtypeResourceMap;
}
generators section¶
Every provider definition includes generator-specific settings:
terraform: TerraformProviderConfig— V1 Core (Terraform Starter Export)requiredProviders(): string— Terraform required_providers blockproviderBlock(region: string): string— Provider configuration blockregionVariableDescription?: string— Description for the location variable (default: "Deployment region")renderSharedResources?(ctx: TerraformRenderContext): string[]— Top-level shared resources (e.g., Azure resource group, service plan). Optional.renderContainerBody(ctx: TerraformContainerContext): string[]— Body lines for container block resources. Required.renderContainerCompanions?(ctx: TerraformContainerContext): string[]— Companion resources adjacent to containers (e.g., route tables, NAT attachments). Optional.renderBlockCompanions?(ctx: TerraformBlockContext): string[]— Companion resources for blocks (e.g., Azure PIP + NIC for VMs). Optional.renderBlockBody(ctx: TerraformBlockContext): string[]— Body lines for resource block resources. Required.extraVariables?(ctx: TerraformRenderContext): string[]— Provider-specific variable declarations (e.g., GCP project_id). Optional.extraOutputs?(ctx: TerraformRenderContext): TerraformOutputSpec[]— Provider-specific output declarations. Optional.bicep: BicepProviderConfig— ExperimentaltargetScope: 'resourceGroup' | 'subscription'pulumi: PulumiProviderConfig— ExperimentalpackageName: stringruntime: 'nodejs'
Terraform Render Hooks¶
The Terraform generator delegates all provider-specific code to render hooks defined in TerraformProviderConfig. The orchestrator (terraform.ts) is fully provider-agnostic — it calls hooks in a fixed order and assembles the output.
Hook Execution Order¶
1. requiredProviders() → terraform {} block
2. providerBlock(region) → provider "..." {} block
3. renderSharedResources(ctx) → shared resources (resource group, service plan, etc.)
4. For each container:
a. renderContainerBody(ctx) → container resource body lines
b. renderContainerCompanions(ctx) → companion resources for container
5. For each block:
a. renderBlockCompanions(ctx) → companion resources (PIP, NIC, etc.)
b. renderBlockBody(ctx) → block resource body lines
6. Connection comments
Context Types¶
All hooks receive context objects that provide the normalized model, generation options, and resource name mappings:
TerraformRenderContext— Base context withnormalized,options,resourceNamesTerraformContainerContext— Extends base withcontainer,mapping,resourceName,parentResourceNameTerraformBlockContext— Extends base withblock,mapping,resourceName,parentResourceName
Return Convention¶
- Body hooks (
renderContainerBody,renderBlockBody) return indented lines (2-space indent) that go insideresource "..." "..." { ... } - Top-level hooks (
renderSharedResources,renderBlockCompanions,renderContainerCompanions) return complete top-level HCL blocks including the resource declaration extraVariablesreturns completevariable "..." { ... }blocks as linesextraOutputsreturnsTerraformOutputSpecobjects (name + value pairs) that the orchestrator wraps inoutput "..." { ... }
Required vs Optional¶
| Hook | Required | Reason |
|---|---|---|
renderContainerBody |
✅ Yes | Every provider must produce container resource bodies |
renderBlockBody |
✅ Yes | Every provider must produce block resource bodies |
renderSharedResources |
❌ No | Not all providers need shared scaffolding |
renderContainerCompanions |
❌ No | Container-adjacent resources are provider-specific |
renderBlockCompanions |
❌ No | Block companion resources are provider-specific |
extraVariables |
❌ No | Provider-specific variables (e.g., GCP project) |
extraOutputs |
❌ No | Provider-specific outputs (e.g., Azure resource_group_name) |
Implemented Providers¶
Azure (V1 Active)¶
renderSharedResources: Emitsazurerm_resource_group+azurerm_service_planrenderContainerBody: Azure VNet / subnet withaddress_spaceandaddress_prefixesrenderBlockBody: Category-based dispatch (azurerm_linux_web_app,azurerm_mssql_database, etc.)renderBlockCompanions: NIC + PIP for VMsextraOutputs:resource_group_name
AWS (V1 Starter)¶
renderSharedResources: SSM parameter data source (region-agnostic Amazon Linux 2 AMI) +aws_availability_zonesdata sourcerenderContainerBody: VPC withcidr_block/enable_dns_*/ tags; subnet withvpc_id, indexedcidr_block,availability_zonefrom data sourcerenderBlockBody: Switch onresourceType— concrete bodies for EC2, RDS, DynamoDB, S3, SQS, SNS, IAM, CloudWatch, API Gateway, Security Group; explicit "cannot be planned" warnings for ECS, Lambda, ALB, NATrenderBlockCompanions:[]extraVariables:[]extraOutputs:[]- EC2 AMI uses
data.aws_ssm_parameter.amazon_linux_ami.value(no hardcoded AMI IDs) - S3 uses
bucket_prefixwith sanitized/trimmed name (24-char limit) - Security groups emit error comment when no ancestor VPC found
GCP (V1 Starter)¶
renderSharedResources: Conditionalgoogle_project_serviceresources for each GCP API used (compute, run, cloudfunctions, sqladmin, firestore, storage, pubsub, eventarc, apigateway, iam, monitoring); usesdisable_on_destroy = falserenderContainerBody: VPC withname(RFC 1035),auto_create_subnetworks = false,depends_on; subnet withname,networkreference, indexedip_cidr_range,regionrenderBlockBody: Switch onresourceType— concrete bodies for Compute Engine, Cloud Run, Cloud SQL, Cloud Storage, Firestore, Pub/Sub, Service Account, Firewall, BigQuery, Monitoring Dashboard, API Gateway, Compute URL Map; explicit "cannot be planned" warnings for Cloud Functions, Cloud NAT, EventarcrenderBlockCompanions:google_compute_imagedata source for Compute Engine instances (Debian 12)extraVariables:project_id(GCP project ID) +zone(compute zone)extraOutputs:[]- All GCP resource
nameattributes use RFC 1035 naming (hyphens, not underscores) viatoGcpName()helper - Firewall emits minimal scaffold with
direction,source_ranges, andallowblock (with WARNING for production) - Cloud SQL uses
deletion_protection = falsewith production WARNING - Storage bucket naming uses
var.project_idprefix for global uniqueness - Firestore warns about
(default)database singleton constraint - All resources include
depends_onreferencing theirgoogle_project_serviceAPI enablement resource
Subtype-Aware Resource Resolution¶
Use subtypeBlockMappings when a block category has multiple provider resources depending on subtype.
- base mapping:
blockMappings[category] - subtype override:
subtypeBlockMappings[category][subtype]
resolveBlockMapping()¶
resolveBlockMapping(blockMappings, subtypeMappings, category, subtype?) resolves in this order:
- Return subtype mapping when
subtypeis provided and exists - Otherwise return
blockMappings[category] - Return
undefinedwhen neither mapping exists
This gives deterministic fallback behavior while supporting subtype precision.
Generation Pipeline Flow¶
Provider resolution is part of the generation pipeline:
validate- run generator/plugin validation rulesresolve provider- loadProviderDefinitionby target providernormalize- convert architecture into generator-ready normalized modelgenerate- produce files using provider + generator configformat- apply optional generator formatter pass
Pipeline stages are pure and deterministic for the same input model and options.
ProviderAdapter Deprecation¶
ProviderAdapter is deprecated and kept only for backward compatibility with older Terraform-only paths.
Migration guidance:
- new provider work must implement
ProviderDefinition - new generator capabilities must read from
ProviderDefinition.generators - existing
ProviderAdapterusages should be incrementally migrated toProviderDefinition
Constraints¶
Provider definitions and resolution logic must:
- not mutate the canonical architecture model
- keep generation deterministic
- report unsupported mappings clearly
- avoid leaking provider-specific semantics back into the DSL
Cross-references:
- Generator pipeline: generator.md
- Architecture model: DOMAIN_MODEL.md