# Kcc Direct Service Generated Id

> Standards and rules for implementing KCC direct controllers for GCP resources that ONLY support service-generated IDs.

- Skill: `googlecloudplatform/kcc-direct-service-generated-id` (Agent Skill)
- Install (CLI): `npx skillmds@latest add googlecloudplatform/kcc-direct-service-generated-id`
- Raw SKILL.md: https://api.skillmd.com/api/skills/googlecloudplatform/kcc-direct-service-generated-id/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: GoogleCloudPlatform (https://skillmd.com/u/googlecloudplatform)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/googlecloudplatform/kcc-direct-service-generated-id

---


# KCC Direct Service-Generated Resource IDs

This skill outlines the mandatory implementation requirements for direct KCC resources whose unique identifiers (IDs) are exclusively assigned/generated by the Google Cloud Platform (GCP) service itself (i.e., resources that ONLY support service-generated IDs).

*Note: Resources that support both user-specified and service-generated IDs (or have alternative selection mechanisms) should be handled differently and are not covered by this skill.*

For such resources, the Kubernetes configuration uses `spec.resourceID` to specify a service-generated ID (if acquiring or targeting a pre-existing resource), but can also leave it empty to request that KCC let the GCP service assign an ID.

---

## The 4 Rules for Service-Generated Resource IDs

When implementing or migrating direct controllers for resources that use service-assigned or service-generated identifiers, you must strictly follow these four architectural rules:

### Rule 1: Identity Construction (`getIdentityFromSpec`)
- Retrieve the resource ID using `GetServiceGeneratedResourceID(obj)` (or `common.ValueOf(obj.Spec.ResourceID)`).
- **MUST NEVER** fall back to using `metadata.name` as a default resource ID.
- If `spec.resourceID` is empty or unset, the parsed `specIdentity.<ResourceID>` MUST be set to `""`.

### Rule 2: `Find()` Pre-Check Guard
- The first line of the `Find()` method **MUST** check if the parsed identifier is empty:
  ```go
  if a.id.<ResourceID> == "" {
      return false, nil
  }
  ```
- This guard returns `false, nil` immediately, preventing invalid GET requests to GCP prior to resource creation.
- **NotFound Error Clarification:** Standard NotFound behavior applies: if the identifier is not empty but the GCP service returns a NotFound/404 error during the standard GET call, `Find()` should return `false, nil` as usual. There should be no special service-generated ID handling for the NotFound error itself.

### Rule 3: `Create()` Request Payload
- The `Create()` implementation **MUST NEVER** set the `desiredpb.Name` (or equivalent identifier field) in the GCP request payload before calling the GCP Create API. The identifier must be left empty so that the GCP service knows to generate it.

### Rule 4: Identity Comparison in `GetIdentity()`
When `status.externalRef` is present during reconciliation:
- **If `GetServiceGeneratedResourceID(obj) == ""` (Empty)**:
  - Do **NOT** compare `specIdentity.<ResourceID>` (`""`) against `statusIdentity.<ResourceID>` (e.g., `"12345"`).
  - Verify that immutable parent fields (such as `Project` and `Location`) match.
  - Return `statusIdentity` (which carries the server-assigned ID).
- **If `GetServiceGeneratedResourceID(obj) != ""` (Non-Empty)**:
  - `specIdentity` **MUST equal `statusIdentity`** (i.e. `specIdentity.<ResourceID> == statusIdentity.<ResourceID>`).
  - If `specIdentity.<ResourceID> != statusIdentity.<ResourceID>`, return an error:  
    `cannot change resource identity (old=%q, new=%q)`

---

## Coding Reference Example

Below is a reference example demonstrating how these rules are mapped into typical direct controller adapter Go code.

```go
package service

import (
    "context"
    "fmt"

    "github.com/GoogleCloudPlatform/k8s-config-connector/apis/common"
)

// Rule 1: Identity Construction
func GetServiceGeneratedResourceID(obj *krm.MyResource) string {
    return common.ValueOf(obj.Spec.ResourceID)
}

func (a *Adapter) Find(ctx context.Context) (bool, error) {
    // Rule 2: Find() Pre-Check Guard
    if a.id.<ResourceID> == "" {
        return false, nil
    }

    // Normal Find logic (e.g., standard GET call)
    // No special service-generated ID handling is needed for NotFound/404 errors.
    // ...
    return true, nil
}

func (a *Adapter) Create(ctx context.Context, desired *krm.MyResource) error {
    // Rule 3: Create() Request Payload
    // Do not set desiredpb.Name, let GCP generate the identifier.
    // ...
    return nil
}

// Rule 4: Identity Comparison in GetIdentity()
func GetIdentity(ctx context.Context, obj *krm.MyResource, statusIdentity *Identity) (*Identity, error) {
    specID := GetServiceGeneratedResourceID(obj)
    
    if specID == "" {
        // Verify that immutable parent fields match (e.g., statusIdentity.Parent == specIdentity.Parent)
        // ...

        return statusIdentity, nil
    }

    if specID != statusIdentity.<ResourceID> {
        return nil, fmt.Errorf("cannot change resource identity (old=%q, new=%q)", statusIdentity.<ResourceID>, specID)
    }

    // Return identity mapped from spec
    return specIdentity, nil
}
```
