apache / apache/cloudstack-terraform-provider

Migrate resources, data sources from terraform-plugin-sdk/v2 to terraform-plugin-framework

Offen
#333 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
improvement
Vorherrschende Sprache
Go
Sterne
53
Forks
67
Ø Merge
3 T. 14 Std.
Gemergte PRs (30 T.)
15

Beschreibung

## Summary

The provider is already a muxed provider serving both `terraform-plugin-sdk/v2` and
`terraform-plugin-framework` behind a single protocol-v6 endpoint, but only 3 of 95
resource types have been migrated to the framework. This issue tracks migrating the
remaining 63 resources and 29 data sources.

## Current state

`main.go` combines two provider servers via `tf6muxserver`:

- `providerserver.NewProtocol6(cloudstack.New())` — framework provider, defined in `cloudstack/provider_v6.go`
- `cloudstack.Provider().GRPCProvider` — SDKv2 provider, wrapped by `tf5to6server.UpgradeServer()` to bridge protocol 5 → 6

Split of resource types by SDK:

| | Resources | Data sources |
|---|---|---|
| SDKv2 (`cloudstack/provider.go`) | 63 | 29 |
| Framework (`CloudstackProvider.Resources()`) | 3 | 0 |

Already on the framework: `cloudstack_service_offering_constrained`,
`cloudstack_service_offering_fixed`, `cloudstack_service_offering_unconstrained`.

100 of the ~109 Go files under `cloudstack/` still import `terraform-plugin-sdk/v2`;
9 import the framework.

Relevant dependencies in `go.mod` — both SDKs and the mux are already present, so no
dependency work is needed:

| Module | Version |
|---|---|
| `terraform-plugin-framework` | v1.12.0 |
| `terraform-plugin-framework-validators` | v0.12.0 |
| `terraform-plugin-mux` | v0.16.0 |
| `terraform-plugin-go` | v0.24.0 |
| `terraform-plugin-sdk/v2` | v2.33.0 |
| `terraform-plugin-testing` | v1.7.0 |
| Go | 1.23.0 |

## References

- [Terraform Plugin Framework benefits](https://developer.hashicorp.com/terraform/plugin/framework-benefits)
- [Migrate from SDKv2 to the plugin framework](https://developer.hashicorp.com/terraform/plugin/framework/migrating)
- [Migrating providers](https://developer.hashicorp.com/terraform/plugin/framework/migrating/providers)
- [terraform-plugin-mux](https://github.com/hashicorp/terraform-plugin-mux)
- In-tree reference pattern: `cloudstack/service_offering_*.go`, `cloudstack/provider_v6.go`, `main.go`

## Motivation

Per [HashiCorp's framework benefits page](https://developer.hashicorp.com/terraform/plugin/framework-benefits),
HashiCorp has stopped most feature development on SDKv2 and recommends the framework for
new development and for migrating existing providers. Staying on SDKv2 for the bulk of
the provider costs us:

- **Null vs unknown vs zero.** SDKv2 conflates "unset", `""`, `0` and `false`, so optional
attributes cannot distinguish "user did not set this" from "user set the zero value".
- **No provider-defined functions.**
- **No ephemeral resources / write-only attributes**, the modern mechanism for handling
short-lived secrets (API keys, VM passwords, Kubernetes cluster configs) without
persisting them in state.
- **No list operations** for discovering unmanaged resources.
- Two schema idioms in one repo, so every new contribution has to pick a side.

## Scope

Port each remaining SDKv2 resource and data source to the framework: remove it from
`ResourcesMap`/`DataSourcesMap` and register it in
`CloudstackProvider.Resources()`/`DataSources()`. Once the lists below are complete,
`terraform-plugin-sdk/v2`, `cloudstack/provider.go` and the `tf5to6server` bridge in
`main.go` can be removed.

No user-facing HCL change is expected or intended: attribute names, block shapes and
semantics must be preserved, and upgrading from the last SDKv2 release should produce
an empty plan for every resource type.

The in-tree reference pattern is `cloudstack/service_offering_*.go` together with
`cloudstack/provider_v6.go`.

## Notes for implementers

- A resource type may be served by exactly **one** server in the mux. Registering a type
with the framework while it remains in `ResourcesMap` makes the mux server fail at
startup with a duplicate-type error, so both changes belong in the same commit.
- Every SDKv2 `ForceNew: true` must be reproduced as a `RequiresReplace()` plan modifier
on the same attribute. There are 296 across 59 files.
- `ConflictsWith` (16 uses), `ValidateFunc` (11), `CustomizeDiff` (13) and
`DiffSuppressFunc` (1) become framework validators and plan modifiers.
- `ImportState` must be written explicitly for the 45 files that currently have an
`Importer`.
- There are no `StateUpgraders`, `MigrateState`, `Timeouts` blocks, partial state or
`resource.Retry` uses anywhere in the SDKv2 surface.
- 35 `schema.TypeSet` and 22 `schema.TypeList` uses need a deliberate choice between
nested blocks and nested attributes; turning a block into an attribute is a
config-breaking change.
- The `cloudstack-go` call sites port verbatim — `NewCreate*Params` / `Set*` are identical
on both sides. Only the surrounding plumbing changes.
- Acceptance tests largely survive unchanged; `terraform-plugin-testing` is already a
dependency and is protocol-agnostic.

## Resources (63)

- [ ] `cloudstack_account`
- [ ] `cloudstack_affinity_group`
- [ ] `cloudstack_attach_volume`
- [ ] `cloudstack_autoscale_policy`
- [ ] `cloudstack_autoscale_vm_group`
- [ ] `cloudstack_autoscale_vm_profile`
- [ ] `cloudstack_cluster`
- [ ] `cloudstack_cni_configuration`
- [ ] `cloudstack_condition`
- [ ] `cloudstack_configuration`
- [ ] `cloudstack_counter`
- [ ] `cloudstack_disk`
- [ ] `cloudstack_disk_offering`
- [ ] `cloudstack_domain`
- [ ] `cloudstack_egress_firewall`
- [ ] `cloudstack_firewall`
- [ ] `cloudstack_host`
- [ ] `cloudstack_instance`
- [ ] `cloudstack_ipaddress`
- [ ] `cloudstack_kubernetes_cluster`
- [ ] `cloudstack_kubernetes_version`
- [ ] `cloudstack_limits`
- [ ] `cloudstack_loadbalancer`
- [ ] `cloudstack_loadbalancer_rule`
- [ ] `cloudstack_network`
- [ ] `cloudstack_network_acl`
- [ ] `cloudstack_network_acl_rule`
- [ ] `cloudstack_network_acl_ruleset`
- [ ] `cloudstack_network_offering`
- [ ] `cloudstack_network_service_provider`
- [ ] `cloudstack_network_service_provider_state`
- [ ] `cloudstack_nic`
- [ ] `cloudstack_physical_network`
- [ ] `cloudstack_pod`
- [ ] `cloudstack_port_forward`
- [ ] `cloudstack_private_gateway`
- [ ] `cloudstack_project`
- [ ] `cloudstack_quota_tariff`
- [ ] `cloudstack_role`
- [ ] `cloudstack_role_permission`
- [ ] `cloudstack_secondary_ipaddress`
- [ ] `cloudstack_secondary_storage`
- [ ] `cloudstack_security_group`
- [ ] `cloudstack_security_group_rule`
- [ ] `cloudstack_service_offering`
- [ ] `cloudstack_snapshot_policy`
- [ ] `cloudstack_ssh_keypair`
- [ ] `cloudstack_static_nat`
- [ ] `cloudstack_static_route`
- [ ] `cloudstack_storage_network_ip_range`
- [ ] `cloudstack_storage_pool`
- [ ] `cloudstack_template`
- [ ] `cloudstack_traffic_type`
- [ ] `cloudstack_user`
- [ ] `cloudstack_user_data`
- [ ] `cloudstack_vlan_ip_range`
- [ ] `cloudstack_volume`
- [ ] `cloudstack_vpc`
- [ ] `cloudstack_vpc_offering`
- [ ] `cloudstack_vpn_connection`
- [ ] `cloudstack_vpn_customer_gateway`
- [ ] `cloudstack_vpn_gateway`
- [ ] `cloudstack_zone`

## Data sources (29)

- [ ] `cloudstack_autoscale_policy`
- [ ] `cloudstack_autoscale_vm_group`
- [ ] `cloudstack_autoscale_vm_profile`
- [ ] `cloudstack_cluster`
- [ ] `cloudstack_condition`
- [ ] `cloudstack_counter`
- [ ] `cloudstack_domain`
- [ ] `cloudstack_instance`
- [ ] `cloudstack_ipaddress`
- [ ] `cloudstack_kubernetes_cluster_config`
- [ ] `cloudstack_limits`
- [ ] `cloudstack_network_offering`
- [ ] `cloudstack_physical_network`
- [ ] `cloudstack_pod`
- [ ] `cloudstack_project`
- [ ] `cloudstack_quota`
- [ ] `cloudstack_quota_enabled`
- [ ] `cloudstack_quota_tariff`
- [ ] `cloudstack_role`
- [ ] `cloudstack_service_offering`
- [ ] `cloudstack_ssh_keypair`
- [ ] `cloudstack_template`
- [ ] `cloudstack_user`
- [ ] `cloudstack_user_data`
- [ ] `cloudstack_volume`
- [ ] `cloudstack_vpc`
- [ ] `cloudstack_vpc_offering`
- [ ] `cloudstack_vpn_connection`
- [ ] `cloudstack_zone`

## Teardown once the above is complete

- [ ] Remove `terraform-plugin-sdk/v2` from `go.mod`
- [ ] Remove the `tf5to6server` bridge from `main.go`
- [ ] Delete `cloudstack/provider.go` and the SDKv2 test helpers

## Related findings

- `cloudstack_service_offering` (SDKv2) coexists with the three framework
`cloudstack_service_offering_*` resources, giving two ways to create a service
offering. Needs a decision on whether the older one is deprecated.

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Beginne mit cloudstack/service_offering_*.go, cloudstack/provider_v6.go und main.go, um das bestehende framework und die mux-Muster zu verstehen, und wähle dann eine einzelne aufgeführte Ressource oder Datenquelle aus. Vergleiche deren SDKv2-Implementierung mit den framework-Beispielen und den zugehörigen Akzeptanztests. Als abgeschlossen gilt die Arbeit, wenn sie nur auf dem framework-Server registriert ist, ihr Schema und Verhalten beibehält und die relevanten Tests besteht.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
go, terraform
Bereich
cloud, devops, infrastructure
Issue-Typ
Refactoring
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
30/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.