一键导入
crd-mapper-fuzzer-existing-type
Standards and workflows for creating direct KRM Go types for an existing CRD while maintaining strict schema compatibility.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Standards and workflows for creating direct KRM Go types for an existing CRD while maintaining strict schema compatibility.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Implement the controller, mappers, and fuzzer for a direct KCC resource, ensuring package isolation and CI compliance. Use this when implementing the main reconciliation logic for a "direct" resource.
Guides the implementation of export support for a direct controller, including implementing AdapterForURL and verifying it through the unified test runner.
Creates or updates the _identity.go and _reference.go files for a Config Connector resource, ensuring they follow the canonical gcpurls.Template pattern. Use this when you need to make sure the identity and reference is up to date for a KCC resource or when implementing IdentityV2 and refs.Ref for a resource.
Guides modifying, patching, and updating resources and fields managed by the Terraform/legacy controller, including patching the local/vendored Terraform Google Beta provider.
Base skill containing shared standards for all KCC direct resource types (both greenfield and brownfield).
| name | crd-mapper-fuzzer-existing-type |
| description | Standards and workflows for creating direct KRM Go types for an existing CRD while maintaining strict schema compatibility. |
This skill outlines standard practices when transitioning an existing KCC resource (e.g., from Terraform or DCL) to a direct controller by generating the initial KRM types (_types.go), ensuring strict schema compatibility with the baseline CRD. You must NOT change the schema at all (other than descriptions). Do not add any new fields, including spec.projectRef, unless it was already part of the baseline CRD. You MUST run dev/tasks/diff-crds to check for any schema changes.
Configure apis/<service>/<version>/generate.sh to include the resource and pass the --include-skipped-output flag. Passing --include-skipped-output to both generate-types and generate-mapper ensures that any output otherwise skipped is still generated but commented out. This provides an invaluable reference when manual modifications/hand-coding of types are needed.
NotebookInstance but Proto Instance), do NOT rename the types file to follow the lowercase KRM Kind name (e.g. notebookinstance_types.go). The generate-types tool expects the file to be named <lowercase_proto_message_name>_types.go (e.g. instance_types.go). Renaming it will cause generator panics and duplicate/untracked file generation.go run . generate-types \
--service <proto.package> \
--api-version "<service>.cnrm.cloud.google.com/<version>" \
--include-skipped-output \
--resource <Kind>:<ProtoMessage>
go run . generate-mapper \
--service <proto.package> \
--api-version "<service>.cnrm.cloud.google.com/<version>" \
--include-skipped-output
When defining the KRM Go type in <kind>_types.go, you must ensure it matches the original CRD schema exactly. You must not add, remove, or modify any fields (including spec.projectRef) in a way that alters the KRM schema:
projectRef if the baseline CRD did not have it) is strictly forbidden.generate-mapper to traverse and map them automatically, completely eliminating the need for hand-coded mapper functions. If the baseline CRD schema requires those nested fields, mark the pointer fields with // +required (or // +kubebuilder:validation:Required) to ensure they remain required in the generated CRD schema.dev/tasks/diff-crds frequently (and definitely before opening/updating a PR) to identify any schema changes or deviations between the baseline CRD and the generated one. The diff-crds output must be absolutely empty (or contain only minor description reflows if expected).spec.projectRef, do not add it to the Spec struct in <kind>_types.go.FolderRef, OrganizationRef, or BillingAccountRef) lacks a kind field or retains specific fields (like name/namespace in OrganizationRef), you must hand-code custom reference types locally in <kind>_types.go. For a project reference without a kind field, you MUST import and use refs.ProjectRef from github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs instead of defining a local structure.StorageBucketRef or BigQueryTableRef) locally. Instead, import and use the real, canonical reference types from their respective packages under apis/<service>/<version> (e.g., github.com/GoogleCloudPlatform/k8s-config-connector/apis/storage/v1beta1 for StorageBucketRef). This ensures they correctly implement refs.Ref and successfully resolve with common KCC helper functions.scripts/add-validation-to-crds automatically adds OpenAPI oneOf blocks depending on field signatures.
external, name, and namespace, its signature is "external,name,namespace", which triggers the generator to automatically append the oneOf reference constraint block.scripts/add-validation-to-crds/parse-crds.go so they are successfully preserved in the generated CRD.int64) does not match the proto's field type (such as int32), the generated assignment code will fail compilation. Solve this by writing handcoded mapping functions (e.g., KindSpec_FromProto / ToProto) in a handcoded mapper.go file within the direct controller package. The generator will automatically detect these and skip generating the conflicting versions.
int32 in the CRD/Go types but its corresponding field in the GCP Go client library (e.g., computepb) is defined as int64, you should convert the Go KRM type of that field from int32 to int64. This is backward compatible (as int64 is a superset of int32 on the Kubernetes side), allows the generated mapping code to compile cleanly, and completely removes any need for hand-coded mapping functions, lossy conversions, or fuzzer truncation filters.// +kcc:proto=<proto_message> annotation. However, the top-level root KRM struct (e.g., ComputeMachineImage) does NOT need the // +kcc:proto=<proto_message> annotation on its definition (place it only on Spec and Status structures). Leaving +kcc:proto off the root struct prevents the generator from outputting conflicting root-level mapping functions (such as FromProto / ToProto), avoiding type assignment errors where the GCP proto status field (such as a string pointer) conflicts with the KRM custom status struct.// +kubebuilder:validation:Format=date-time to match original formats.// +kubebuilder:metadata:labels="cnrm.cloud.google.com/dcl2crd=true" (or tf2crd=true for Terraform-based resources) on the struct definition in <kind>_types.go. Removing these labels will prevent the corresponding legacy controllers from being registered correctly for the resource during the transition phase. Additionally, if the baseline CRD contains older versions that must be preserved (e.g., v1alpha1), you MUST add // +kubebuilder:metadata:labels="internal.cloud.google.com/additional-versions=v1alpha1" to the beta resource structure so that those versions are still generated.observedState or externalRef to the Status struct of the newly generated Go types if they were not already present in the original baseline CRD. Even though externalRef is standard for direct controllers, adding it changes the schema and must be avoided for strict schema-compatibility. The output of dev/tasks/diff-crds must be absolutely empty.filterLabels), we can rename the Go struct field to match the proto name exactly (e.g., renaming the Go field name to Labels while preserving the JSON tag json:"filterLabels,omitempty" so that there is absolutely no schema change). This allows us to fully leverage automatic mapper generation and completely avoid writing hand-coded mappers. If the mapped type is defined in a different package (like google.api.MonitoredResource), we can also specify multiple services to the --service flag of generate-mapper (e.g. --service google.monitoring.v3,google.api) to enable automatic traversal and generation for that shared type.Fuzzer implementation timing: Note that implementing a fuzzer is NOT required for brownfield resources in the first step (defining direct types). The fuzzer is implemented and run later in the transition lifecycle (e.g., in Step 3 or 4 when writing and validating the controller reconciliation logic).
When writing a KRM round-trip fuzzer, or if a fuzzer already exists:
<kind>_fuzzer.go (e.g., entitlement_fuzzer.go) in lowercase. Do not use generic names like fuzzers.go.f.SpecFields.Insert, f.StatusFields.Insert, or f.UnimplementedFields.Insert directly on sets. Instead, use the type-safe helper methods defined on the KRMTypedFuzzer struct:
f.SpecField(fieldPath) to mark a field as round-tripping to/from the Spec.f.StatusField(fieldPath) to mark a field as round-tripping to/from the Status.f.Unimplemented_Identity(fieldPath) for identity/URL fields like .name.f.Unimplemented_Internal(fieldPath) for internal service-only/hidden implementation details (e.g., resource fields that are duplicates of KRM metadata or parent references).f.Unimplemented_NotYetTriaged(fieldPath) for fields that are not implemented or under development.f.Unimplemented_LabelsAnnotations(fieldPath) for labels or annotations.mappers.go within the direct controller package to distinguish them from the generated mapper file mapper.generated.go.No Dedicated Unit Test Needed: There is no need to add a dedicated/standalone _fuzzer_test.go file for the resource. Simply registering the fuzzer using fuzztesting.RegisterKRMFuzzer() in your fuzzer implementation file (e.g. backupvault_fuzzer.go) is fully sufficient. The existing shared testing framework (such as pkg/fuzztesting/fuzztests/fuzz_test.go) will automatically discover and run it.
dev/tasks/diff-crds to verify there are absolutely no unintended schema changes.make ready-pr to regenerate Go clients (and compile-check the changes, run custom linters, format the files, and regenerate static configs).dev/tasks/generate-resource-report to update the resource reports docs/reports/crd_report.csv and docs/reports/crd_report.md to reflect the transition.