name: kcc-identity-reference description: 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.
Kcc Identity Reference
Overview
This skill guides you through creating or updating the _identity.go and _reference.go files for a given Config Connector resource (e.g. MemoryStoreInstance). The goal is to implement identity.IdentityV2 and refs.Ref using the canonical gcpurls.Template pattern, identical to the pattern used in apis/artifactregistry/v1beta1/artifactregistryrepository_identity.go.
Hints
- If the identity or reference files already exist, do not update the copyright year.
Workflow
When asked to update or create the identity and reference for a "resource of the day" (e.g., group: memorystore.cnrm.cloud.google.com, kind: MemoryStoreInstance), follow these steps:
Step 1: Locate the target files
- Identify the
groupPrefix(the group without the.cnrm.cloud.google.comsuffix). Example:memorystore - Look for the resource version directory under
apis/<groupPrefix>/. Example:apis/memorystore/v1beta1/orapis/memorystore/v1alpha1/. (Check the filesystem to see which versions exist). - The files to edit/create are
apis/<groupPrefix>/<version>/<kind>_identity.goandapis/<groupPrefix>/<version>/<kind>_reference.go.- Note:
<kind>is typically the full lowercase Kind, e.g.memorystoreinstance. Sometimes thegroupPrefixis dropped, so check if the files already exist.
- Note:
Step 2: Determine the Identity Template
- Read the corresponding line in
docs/ai/metadata/cloudassetinventory_names.jsonlusing grep. Search for the resource kind to find its URL format.- Example:
grep -i memorystore docs/ai/metadata/cloudassetinventory_names.jsonl - Output might be:
{"resourceType": "memorystore.googleapis.com/Instance", "nameFormats": ["//memorystore.googleapis.com/projects/{{PROJECT_ID}}/locations/{{LOCATION}}/instances/{{INSTANCE}}"]} - Note: If the resource is missing from
cloudassetinventory_names.jsonl(e.g. not handled by CAIS), check the existing_identity.goor direct controller to infer the URL format. Pay attention to camelCase path segments (e.g.entryGroupsinstead ofentrygroups), as GCP URLs are case-sensitive. Additionally, if the resource is missing fromcloudassetinventory_names.jsonl, you will also need to add its URL format as an exception inpkg/gcpurls/registry_test.goto prevent theTestRegisteredTemplatesMatchCAItest from failing.
- Example:
- Map the format to the
gcpurls.Templateformat:"projects/{project}/locations/{location}/instances/{instance}". - Read the canonical
apis/artifactregistry/v1beta1/artifactregistryrepository_identity.goto refresh your understanding of the implementation details.
Step 3: Implement the Identity (<kind>_identity.go)
Create or update the file to match the canonical example. Key requirements:
- Use the standard copyright header (Year 2026).
- Declare interface implementations:
_ identity.IdentityV2 = &<Kind>Identity{}(or_ identity.ServerGeneratedIdentity = &<Kind>Identity{}if the resource has a server-generated ID) and_ identity.Resource = &<Kind>{} - Define the template var:
var <Kind>IdentityFormat = gcpurls.Template[<Kind>Identity]("api.googleapis.com", "projects/{project}/...") - The struct must map exactly to the template fields (e.g.,
Project string,Location string,Instance string) and have// +k8s:deepcopy-gen=false.- Important: Add a standard Go doc comment like
// <Kind>Identity is the identity of a GCP <Kind> resource.right above the struct definition. - Important: The variables in your
gcpurls.Template(e.g.{instance}) MUST match the struct fields when both are lowercased (e.g.{deploymentresourcepool}matchesDeploymentResourcePool). Do not use underscores in the template variables (e.g.{deployment_resource_pool}) or Go struct fields (e.g.Deployment_resource_pool). For GCP URL templates that originally contain snake_case placeholders (e.g.{aspect_type}), you must map them to camelCase variables in thegcpurls.Template(e.g.,{aspectType}) and use CamelCase in the corresponding Go struct fields (e.g.,AspectType string). Avoid snake_case fields with underscores (such asAspect_type string) in Go structs entirely. - Note: If an existing deepcopy method was previously generated for this identity struct, run
dev/tasks/generate-types-and-mappersto regenerate the types and remove the obsolete code.
- Important: Add a standard Go doc comment like
- Implement
String(),FromExternal(ref string), andHost()by delegating to the format var. - For Server-Generated IDs: If the resource can have its ID generated by the GCP server when not specified in the spec, implement
identity.ServerGeneratedIdentityinstead ofidentity.IdentityV2.- Implement
HasIdentitySpecified() bool(e.g., returni.ID != ""). - In
GetIdentity(), ifobj.Status.ExternalRefis set, parse it to extract the authoritative server-generated ID and default the empty spec identity ID field to it prior to cross-checking or returning. Seeapis/bigqueryconnection/v1beta1/bigqueryconnectionconnection_identity.gofor the exact reference implementation.
- Implement
- Implement
ParentString()to return the GCP parent URI string (e.g.,projects/{project}orprojects/{project}/locations/{location}) to simplify parent path construction in controllers. - Implement
getIdentityFrom<Kind>Spec(ctx context.Context, reader client.Reader, obj *<Kind>) (*<Kind>Identity, error)to extract fields from the spec/obj (often usingrefs.ResolveProjectID,refs.GetLocation, etc.).- Important: This function MUST take a typed pointer
*<Kind>directly. If any callers (such asNormalizefallback) only have an*unstructured.Unstructuredobject, those callers must first convert it usingcommon.ToStructuredType[*<Kind>](unstructuredObj)before callinggetIdentityFrom<Kind>Spec. This keeps the extraction code highly type-safe and avoids manual unstructured field parsing.
- Important: This function MUST take a typed pointer
- Implement
GetIdentity(ctx, reader)on the Resource struct, including cross-checkingexternalReforstatus.Nameif either exists on theStatusstruct. (Look atartifactregistryrepository_identity.go'sGetIdentityimplementation for exactly how to do this cross-check).CRITICAL / MANDATORY: Do NOT change the schema (e.g., do not add
status.externalReforstatus.namefields to the_types.gofile if they are not already there) in this phase. If the resource'sStatusstruct does not already contain anExternalReforNamefield, do NOT perform any cross-check against the status inGetIdentity. Simply return the parsedspecIdentitywithout checking status. We should never change the schema to introduce an identity or reference.Verification: Always run
dev/tasks/diff-crdsto check and guarantee that we have not changed the schema in any way.Note: If you are updating an existing resource's Identity struct to the IdentityV2 pattern, be sure to check for existing usages of the struct and its old methods (e.g.
.Parent(),.ID()) in dependent identity files and direct controllers, and update them to use the new fields (e.g..Project,.Location, etc.). The compiler is your friend: remove the functions, then rungo vet ./...orgo build ./...to look for references to functions that no longer exist.
Step 4: Implement the Reference (<kind>_reference.go)
Read the canonical apis/artifactregistry/v1beta1/artifactregistryrepository_reference.go to refresh your understanding.
Create or update the file to match the canonical example. Key requirements:
- Use the standard copyright header (Year 2026).
- Implement
_ refs.Ref = &<Kind>Ref{}. - Define the GVK variable:
var <Kind>GVK = schema.GroupVersionKind{...}(It is also acceptable if this is defined in<kind>_types.go). - Define the
<Kind>Refstruct with exactly 3 fields:External,Name, andNamespace.- Important: Add a clean, simple doc comment like
// <Kind>Ref is a reference to a GCP <Kind>.right above the struct definition. Avoid verbose or awkward boilerplate phrasing like "defines the resource reference to..." or "which External field...". - The
Externalfield MUST have specific godoc:"A reference to an externally managed <Kind> resource. Should be in the format \"projects/{{projectID}}/...\"". Do not use generic docstrings. - The
NameandNamespacefields should have godocs:"The name of a <Kind> resource."and"The namespace of a <Kind> resource.".
- Important: Add a clean, simple doc comment like
- Include
func init() { refs.Register(&<Kind>Ref{}) }. - Implement boilerplate methods:
GetGVK,GetNamespacedName,GetExternal,SetExternal,ValidateExternal,ParseExternalToIdentity. - Implement
Normalizedelegating torefs.NormalizeWithFallback. In the fallback functionfunc(u *unstructured.Unstructured) string, simply passudirectly togetIdentityFrom<Kind>Specsince*unstructured.Unstructuredimplementsclient.Object.
Step 5: Verify
Write Unit Tests:
- Write comprehensive unit tests for the Identity (e.g.,
<kind>_identity_test.go). - Do NOT create a separate
<kind>_reference_test.gofile (as it typically duplicates the parsing and formatting tests of the identity). Instead, add any validation or format test cases directly to the identity unit tests. - You MUST use
github.com/google/go-cmp/cmp(with thecmp.Difffunction) when comparing structs or multiple fields in tests, to ensure precise, clear diff outputs on failures. - Always use the standard got/want mismatch format for failures, e.g.
(-want +got):\n%s. - CRITICAL: When creating/modifying an identity type, always run
TestGoldenIdentitiesYamlFiles(defined inpkg/cli/powertools/cais/cmd_test.go) withWRITE_GOLDEN_OUTPUT=1usingWRITE_GOLDEN_OUTPUT=1 go test -v ./pkg/cli/powertools/cais/...to generate or update the golden output_identities.yamlfile(s) for the test fixtures. This prevents presubmit CI unit test failures.
- Write comprehensive unit tests for the Identity (e.g.,
Run Compilations and Linters:
- Ensure the code compiles and there are no lint errors. You MUST always run
go vet ./...andgo build ./...before sending the PR to verify that your changes have not introduced any compilation errors across the entire project. - If any CRDs, schemas, or reference definitions changed, always run
make resource-docsto regenerate the resource documentation and prevent doc validation pipeline breakages.
- Ensure the code compiles and there are no lint errors. You MUST always run