Skip to content
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
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ Makefile -- Generated build orchestration
```

### Key Files
- `provider/resources.go` - Resource definitions
- `provider/resources.go` - Provider assembly and language configuration
- `provider/resource_overrides.go`, `provider/data_source_overrides.go`, and `provider/tokens.go` - Bridge overrides and Terraform-to-Pulumi token strategy
- `provider/resources_test.go` - Provider tests

## Development Workflow
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Please refer to the [main Pulumi repo](https://github.com/pulumi/pulumi/)'s [CON

## Committing Generated Code

You must generate and check in the SDKs on each pull request containing a code change, e.g. adding a new resource to `resources.go`.
You must generate and check in the SDKs on each pull request containing a code change, e.g. adding a new resource override to `provider/resource_overrides.go`.

1. Run `make schema && make provider` to regenerate schema artifacts and the provider binary.
1. Run `make build_sdks` from the root of this repository (this regenerates SDK artifacts as needed).
Expand All @@ -33,7 +33,7 @@ For most provider-code changes, run this loop before opening a pull request:

1. `make lint`
1. `make test_provider`
1. If schema-affecting files changed (for example `provider/resources.go`, overlays, or mappings), also run:
1. If schema-affecting files changed (for example `provider/resources.go`, override files, overlays, or token mappings), also run:
- `make schema`
- `make build_sdks`

Expand Down Expand Up @@ -73,7 +73,7 @@ Copy the content of `policies.go` and insert into the `iam_managed_policy.go` fi
## Updating pulumi-terraform-aws dependency

Keeping the pulumi-terraform-aws dependency up-to-date involves updating the `./upstream` Git sub-module, resolving
patch conflicts, adjusting `resources.go` mappings configurations and re-generating the SDKs. For a fully worked
patch conflicts, adjusting provider overrides and token mappings, and re-generating the SDKs. For a fully worked
example, to update to v5.60.0 (actual update in #4309):

```bash
Expand All @@ -90,7 +90,7 @@ git add ./upstream && git commit -m "Move upstream to v5.60.0"
./scripts/upstream.sh init -f # verify patches apply cleanly with no changes
./scripts/tidy-all.sh
git add . && git commit -m "./scripts/tidy-all.sh"
make tfgen # iterate on editing resources.go configurations as needed
make tfgen # iterate on editing provider overrides and token mappings as needed
git add . && git commit -m "make tfgen"
make build_sdks && git add . && git commit -m "make build_sdks"
```
4 changes: 2 additions & 2 deletions docs/provider-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ a test or regeneration command.
| Control surface | Entry point | What changes here |
| --- | --- | --- |
| Upstream provider assembly | [`provider/upstream_provider.go`](../provider/upstream_provider.go), [`provider/pkg/iam/`](../provider/pkg/iam/), and [`provider/pkg/rds/`](../provider/pkg/rds/) | Adjustments applied to the SDKv2 or Plugin Framework provider before the bridge consumes it. This constructor runs during schema generation and runtime startup. |
| Bridge configuration | [`provider/resources.go`](../provider/resources.go) | Provider configuration, Terraform-to-Pulumi tokens, field overrides, autonaming, aliases, ID overrides, and input/output or state transforms. |
| Pulumi-side input handling | [`provider/region.go`](../provider/region.go), [`provider/tags.go`](../provider/tags.go), and the pre-configure callback in `provider/resources.go` | Behavior that must run before upstream Terraform logic, such as provider credential diagnostics or Pulumi-specific `Check` inputs. |
| Bridge configuration | [`provider/resources.go`](../provider/resources.go), [`provider/tokens.go`](../provider/tokens.go), [`provider/resource_overrides.go`](../provider/resource_overrides.go), and [`provider/data_source_overrides.go`](../provider/data_source_overrides.go) | Provider assembly, Terraform-to-Pulumi tokens, and resource or data-source overrides. Compatibility behavior is split into adjacent focused files such as `aliases.go`, `autonaming.go`, and `computed_ids.go`. |
| Pulumi-side input handling | [`provider/region.go`](../provider/region.go), [`provider/tags.go`](../provider/tags.go), and [`provider/config.go`](../provider/config.go) | Behavior that must run before upstream Terraform logic, such as provider credential diagnostics or Pulumi-specific `Check` inputs. |
| Schema additions and post-processing | [`provider/overlays.go`](../provider/overlays.go), [`provider/types.go`](../provider/types.go), and [`provider/enums.go`](../provider/enums.go) | Pulumi-only resources and types, generated API shape, and schema transformations not supplied by upstream. |
| Generated documentation edits | [`provider/doc_edits.go`](../provider/doc_edits.go) and [`provider/replacements.json`](../provider/replacements.json) | Targeted changes to converted upstream documentation. |
| Runtime assembly and metadata | [`provider/cmd/pulumi-resource-aws/`](../provider/cmd/pulumi-resource-aws/), [`provider/cmd/pulumi-tfgen-aws/`](../provider/cmd/pulumi-tfgen-aws/), and [`provider/pkg/minimalschema/`](../provider/pkg/minimalschema/) | SDKv2/Plugin Framework mux startup, embedded schema, and generated bridge/runtime metadata. Generated JSON files are outputs, not editing points. |
Expand Down
128 changes: 128 additions & 0 deletions provider/aliases.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package provider

import (
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
)

// applyLegacyResourceAliases preserves URN compatibility for historical token corrections and module moves.
func applyLegacyResourceAliases(prov *tfbridge.ProviderInfo) {
addLegacyAlias := func(token string, prev, current tokens.Type, info *tfbridge.ResourceInfo) {
_, ok := prov.Resources[token]
contract.Assertf(!ok, "We don't alias an existing resource")
if info == nil {
info = new(tfbridge.ResourceInfo)
}
info.Tok = current
info.Aliases = append(info.Aliases, tfbridge.AliasInfo{Type: new(string(prev))})
prov.Resources[token] = info
}

// Fix the spelling mistake on `aws_ses_configuration_set` Tok
addLegacyAlias("aws_ses_configuration_set",
awsResource(sesMod, "ConfgurationSet"), awsResource(sesMod, "ConfigurationSet"),
nil)

// Preserve URNs from before the `elb` resources moved out of the `elasticloadbalancing` module.
addLegacyAlias("aws_app_cookie_stickiness_policy",
awsResource(legacyElbMod, "AppCookieStickinessPolicy"),
awsResource(elbMod, "AppCookieStickinessPolicy"),
nil)
addLegacyAlias("aws_elb",
awsResource(legacyElbMod, "LoadBalancer"), awsResource(elbMod, "LoadBalancer"),
nil)
addLegacyAlias("aws_elb_attachment",
awsResource(legacyElbMod, "Attachment"), awsResource(elbMod, "Attachment"),
nil)
addLegacyAlias("aws_lb_cookie_stickiness_policy",
awsResource(legacyElbMod, "LoadBalancerCookieStickinessPolicy"),
awsResource(elbMod, "LoadBalancerCookieStickinessPolicy"),
nil)
addLegacyAlias("aws_load_balancer_policy",
awsResource(legacyElbMod, "LoadBalancerPolicy"), awsResource(elbMod, "LoadBalancerPolicy"),
nil)
addLegacyAlias("aws_load_balancer_listener_policy",
awsResource(legacyElbMod, "ListenerPolicy"), awsResource(elbMod, "ListenerPolicy"),
nil)
addLegacyAlias("aws_lb_ssl_negotiation_policy",
awsResource(legacyElbMod, "SslNegotiationPolicy"), awsResource(elbMod, "SslNegotiationPolicy"),
nil)
addLegacyAlias("aws_load_balancer_backend_server_policy",
awsResource(legacyElbMod, "LoadBalancerBackendServerPolicy"),
awsResource(elbMod, "LoadBalancerBackendServerPolicy"),
nil)

// Preserve URNs from before the `lb` resources moved out of the `elasticloadbalancingv2` module.
addLegacyAlias("aws_lb",
awsResource(legacyElbv2Mod, "LoadBalancer"), awsResource(lbMod, "LoadBalancer"),
nil)
addLegacyAlias("aws_lb_listener",
awsResource(legacyElbv2Mod, "Listener"), awsResource(lbMod, "Listener"),
nil)
addLegacyAlias("aws_lb_listener_certificate",
awsResource(legacyElbv2Mod, "ListenerCertificate"), awsResource(lbMod, "ListenerCertificate"),
nil)
addLegacyAlias("aws_lb_listener_rule",
awsResource(legacyElbv2Mod, "ListenerRule"), awsResource(lbMod, "ListenerRule"),
nil)
addLegacyAlias("aws_lb_target_group",
awsResource(legacyElbv2Mod, "TargetGroup"),
awsResource(lbMod, "TargetGroup"),
&tfbridge.ResourceInfo{
Fields: map[string]*tfbridge.SchemaInfo{
// https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_CreateTargetGroup.html
"name": tfbridge.AutoName("name", 32, "-"),
"deregistration_delay": {
Type: "integer",
},
},
})
addLegacyAlias("aws_lb_target_group_attachment",
awsResource(legacyElbv2Mod, "TargetGroupAttachment"), awsResource(lbMod, "TargetGroupAttachment"),
nil)

// Ec2 Transit Gateway
addLegacyAlias("aws_ec2_transit_gateway_peering_attachment_accepter",
awsResource(ec2Mod, "TransitGatewayPeeringAttachmentAccepter"),
awsResource(ec2TransitGatewayMod, "PeeringAttachmentAccepter"),
nil)

// Preserve URNs from before the `alb` resources moved out of the `applicationloadbalancing` module.
addLegacyAlias("aws_alb", awsResource(legacyAlbMod, "LoadBalancer"),
awsResource(albMod, "LoadBalancer"), &tfbridge.ResourceInfo{
Fields: map[string]*tfbridge.SchemaInfo{
"load_balancer_type": {Type: awsType(albMod, "LoadBalancerType", "LoadBalancerType")},
"ip_address_type": {
Type: "string",
AltTypes: []tokens.Type{awsType(albMod, "IpAddressType", "IpAddressType")},
},
},
Docs: &tfbridge.DocInfo{Source: "lb.html.markdown"},
})
addLegacyAlias("aws_alb_listener", awsResource(legacyAlbMod, "Listener"),
awsResource(albMod, "Listener"), &tfbridge.ResourceInfo{
Docs: &tfbridge.DocInfo{Source: "lb_listener.html.markdown"},
})
addLegacyAlias("aws_alb_listener_certificate", awsResource(legacyAlbMod, "ListenerCertificate"),
awsResource(albMod, "ListenerCertificate"), &tfbridge.ResourceInfo{
Docs: &tfbridge.DocInfo{Source: "lb_listener_certificate.html.markdown"},
})
addLegacyAlias("aws_alb_listener_rule", awsResource(legacyAlbMod, "ListenerRule"),
awsResource(albMod, "ListenerRule"), &tfbridge.ResourceInfo{
Docs: &tfbridge.DocInfo{Source: "lb_listener_rule.html.markdown"},
})
addLegacyAlias("aws_alb_target_group", awsResource(legacyAlbMod, "TargetGroup"),
awsResource(albMod, "TargetGroup"), &tfbridge.ResourceInfo{
Docs: &tfbridge.DocInfo{Source: "lb_target_group.html.markdown"},
Fields: map[string]*tfbridge.SchemaInfo{
"deregistration_delay": {
Type: "integer",
},
},
})
addLegacyAlias("aws_alb_target_group_attachment", awsResource(legacyAlbMod, "TargetGroupAttachment"),
awsResource(albMod, "TargetGroupAttachment"), &tfbridge.ResourceInfo{
Docs: &tfbridge.DocInfo{Source: "lb_target_group_attachment.html.markdown"},
})
}
60 changes: 60 additions & 0 deletions provider/autonaming.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package provider

import (
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
)

const nameProperty = "name"

// prov.SetAutonaming is too inefficient for AWS as it forces SchemaFunc calls for large resources
// that use up RAM. Instead of doing prov.SetAutonaming(255, "-") we call a surgically crafted
// setAutonaming that avoids these calls.
func setAutonaming(p *tfbridge.ProviderInfo, resourceMetadata awsResourceMetadataLookup) {
maxLength := 255
separator := "-"
for resname, res := range p.Resources {
var schemaResource shim.Resource
if p.P != nil {
schemaResource = p.P.ResourcesMap().Get(resname)
}
// Only apply auto-name to input properties (Optional || Required) named `name`
if !resourceMetadata(p.P, resname, schemaResource).HasInputName {
continue
}
if _, hasfield := res.Fields[nameProperty]; !hasfield {
if res.Fields == nil {
res.Fields = make(map[string]*tfbridge.SchemaInfo)
}
res.Fields[nameProperty] = tfbridge.AutoName(nameProperty, maxLength, separator)
}
}
}

func hasOptionalOrRequiredNameProperty(p shim.Provider, tfResourceName string) bool {
if schema := p.ResourcesMap().Get(tfResourceName); schema != nil {
// Only apply auto-name to input properties (Optional || Required) named `name`
if sch := schema.Schema().Get(nameProperty); sch != nil && (sch.Optional() || sch.Required()) {
return true
}
}
return false
}

func hasNonComputedTagsAndTagsAll(_ string, res shim.Resource) bool {
// Skip resources that don't have tags.
tagsF, ok := res.Schema().GetOk("tags")
if !ok {
return false
}
// Skip resources that don't have tags_all.
_, ok = res.Schema().GetOk("tags_all")
if !ok {
return false
}
// tags must be non-computed.
if tagsF.Computed() && !tagsF.Optional() {
return false
}
return true
}
Loading
Loading