Skip to content

feat(corev1): migrate kubernetes_namespace_v1 to Plugin Framework (fixes #2812)#2858

Draft
gaetanars wants to merge 1 commit intohashicorp:mainfrom
gaetanars:feat/namespace-v1-plugin-framework-migration
Draft

feat(corev1): migrate kubernetes_namespace_v1 to Plugin Framework (fixes #2812)#2858
gaetanars wants to merge 1 commit intohashicorp:mainfrom
gaetanars:feat/namespace-v1-plugin-framework-migration

Conversation

@gaetanars
Copy link
Copy Markdown

Summary

This PR is the Phase 0 pilot of the progressive SDKv2 → Plugin Framework migration proposed in #2857. It migrates kubernetes_namespace_v1 to the Plugin Framework and re-enables moved block support broken since v3.0.0.

Note: This is a draft PR submitted alongside the discussion in #2857. The intent is to give maintainers a concrete implementation to review before the bulk migration of the remaining ~60 resources proceeds.

What changed

  • New internal/framework/provider/corev1/ package (8 files, mirroring the admissionregistrationv1/ pattern)
  • kubernetes_namespace and kubernetes_namespace_v1 removed from SDKv2 ResourcesMap (mux constraint: same type cannot be in both providers simultaneously)
  • KubeClientsets interface extended with GetIgnoreAnnotations() / GetIgnoreLabels() (needed to access provider-level ignore patterns from Framework resources)
  • DiffStringMap, IsInternalKey, IgnoreKey exported from the kubernetes package for reuse by Framework resources

State migration

Two interfaces are implemented to cover all upgrade paths:

Interface When it fires What it does
ResourceWithUpgradeState (v0→v1) terraform plan on any existing kubernetes_namespace_v1 state Converts SDKv2 TypeList metadata [{...}] → Framework SingleNestedAttribute {...}
ResourceWithMoveState User adds moved { from = kubernetes_namespace.x to = kubernetes_namespace_v1.x } Accepts state from the deprecated alias, same conversion

Critical implementation details established in this pilot (and reusable for all subsequent migrations):

  • PriorSchema must use schema.ListNestedAttribute for SDKv2 TypeList fields (not SingleNestedAttribute)
  • timeouts must be present in PriorSchema even if not all keys are in the new schema
  • Schema.Version = 1 on the Framework resource is required to trigger UpgradeState
  • annotations: {} / labels: {}nil (not empty non-null map) to avoid perpetual plan diffs

Testing

  • Unit tests (no cluster): SDKv2 state JSON fixtures exercising the upgrade path directly
  • Acceptance tests (KinD cluster): basic lifecycle, generate_name, import, moved block, SDKv2→Framework upgrade

Checklist

  • ResourceWithMoveState implemented
  • ResourceWithUpgradeState implemented
  • Unit tests with real SDKv2 state JSON fixtures
  • Acceptance test: provision with v3.0.1 → plan with local provider → plancheck.ExpectEmptyPlan()
  • Acceptance test: moved {} block → plancheck.ExpectEmptyPlan()
  • ImportStateVerify: true passes
  • make build + make test + make fmtcheck pass
  • Changelog entry (pending PR number — will rename .changelog/NEXT-namespace-v1-migration.txt)

Post-Deploy Monitoring & Validation

No additional operational monitoring required: this change affects provider binary distribution only; no infrastructure changes are made at runtime. Existing kubernetes_namespace_v1 resources will silently upgrade their state schema on next terraform plan.


Relates to: #2857 (migration strategy discussion)
Fixes: #2812

 hashicorp#2812)

Migrates kubernetes_namespace_v1 from SDKv2 to the Terraform Plugin Framework,
enabling `moved` block support for cross-type state migration.

Key changes:
- New internal/framework/provider/corev1/ package (8 files)
- ResourceWithMoveState: accepts state from kubernetes_namespace (deprecated alias)
- ResourceWithUpgradeState (v0→v1): converts SDKv2 TypeList metadata to
  SingleNestedAttribute transparently for all existing state files
- Removes kubernetes_namespace and kubernetes_namespace_v1 from SDKv2 ResourcesMap
  (mux constraint: same type cannot be registered in both providers simultaneously)
- Extends KubeClientsets interface with GetIgnoreAnnotations/GetIgnoreLabels
- Exports DiffStringMap, IsInternalKey, IgnoreKey from kubernetes package for
  reuse by Framework resources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@hashicorp-cla-app
Copy link
Copy Markdown

hashicorp-cla-app bot commented Mar 31, 2026

CLA assistant check
All committers have signed the CLA.

@bjornmage
Copy link
Copy Markdown

Endorsing this pilot from downstream. We have ~26 resources in production that hit #2812 (details in that issue). The file layout here (corev1/ package mirroring admissionregistrationv1/, one file per concern: crud, helpers, model, schema, state_migration) is clean and it's easy to see how kubernetes_secret_v1, kubernetes_service_account_v1, kubernetes_config_map_v1 and the rest of core/v1 would drop into the same structure.

Two things I want to flag from a consumer's perspective, since they both land as expected based on the PR description but it's worth confirming for anyone reviewing:

  1. ResourceWithMoveState + ResourceWithUpgradeState together. This is the exactly-right coverage for mixed-version environments: moved {} blocks in Terraform ≥ 1.8, and terraform state mv / refresh-triggered upgrades for pre-1.8 or non-declarative workflows. A resource that only implements one of the two would leave a gap.

  2. Mux constraint. Removing kubernetes_namespace and kubernetes_namespace_v1 from the SDKv2 ResourcesMap in the same commit (lines in kubernetes/provider.go) is the only way the mux stays consistent, since both the kubernetes_namespace alias and the _v1 name are currently served by the SDKv2 provider with "Deprecated; use kubernetes_namespace_v1." vs "" messages. Worth calling out in the PR description that the deprecated alias is simultaneously removed from SDKv2 and picked up by Framework's MoveState — consumers don't need to change anything, they just stop getting Move Resource State Not Supported.

Offering to contribute kubernetes_secret_v1 as a stacked follow-up PR once this one is accepted and the pattern is blessed by maintainers. It's the one blocking the most resources in our stack, and the legacy kubernetes_secret alias already routes to the exact same SDKv2 factory function as kubernetes_secret_v1 (see kubernetes/provider.go lines 266-267), so the MoveState path should be an identity copy of the state JSON — simpler than the ListNestedAttribute → SingleNestedAttribute metadata conversion you had to do here.

Happy to wait for maintainer feedback on the RFC (#2857) before I start. No local fork of the provider in the meantime — we're holding on the workaround and the hope that this lands cleanly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move Resource State Not Supported when migrating to 3.0.0

2 participants