Skip to content

Change Namespace.Spec.Project structure - #67

Merged
jaypipes merged 1 commit into
mainfrom
resource-status
Nov 6, 2026
Merged

jaypipes merged 1 commit into
mainfrom
resource-status

Conversation

@jaypipes

@jaypipes jaypipes commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

This commit makes some changes to the Namespace CR to make the handling
of Temporal Cloud-returned identifiers more consistent and to provide
extensibility to allow referencing Temporal Cloud resources by their
Kubernetes Custom Resource counterpart.

We modify api/cloud/common.ResourceStatus by shortening the name of
the ResourceVersion field to just Version. This was done because
ResourceStatus is now no longer an inlined field in NamespaceStatus
but rather a named field inside the NamespaceStatus struct.
NamespaceStatus struct now has another field called References which
contains Temporal Cloud resource identifiers of any related resources --
e.g. Projects or Connectivity Rules:

// NamespaceStatus describes the current status of a Temporal Cloud namespace.
// This struct does not contain a FromProto or ToProto function because there is
// no corresponding NamespaceStatus struct in the Temporal Cloud API.
// +k8s:openapi-gen=true
type NamespaceStatus struct {
	tmprlcorev1.StatusBase `json:",inline"`
	// Resource contains common information about the Temporal Cloud resource
	// that this CR represents.
	Resource cloudcommon.ResourceStatus `json:"resource"`
	// References is an optional field containing the Temporal Cloud resource
	// IDs for any related resources.
	References NamespaceReferences `json:"references,omitempty"`
}

// NamespaceReferences is an optional field containing the
// Temporal Cloud resource IDs for any related resources.
type NamespaceReferences struct {
	// Project is the Temporal Cloud resource identifier for the Project
	// containing this Temporal Namespace.
	Project string `json:"project,omitempty"`
	// ConnectivityRules is the set of Temporal Cloud resource identifiers for
	// any Namespace ConnectivityRules associated with this Temporal Namespace
	ConnectivityRules []string `json:"connectivityRules,omitempty"`
}

The NamespaceSpec.Project field type has been modified from string
to ProjectReferenceOrID, which is a struct that can contain either a
Temporal Cloud resource identifier or a reference to a (to be created)
cloud.temporal.io/Project CR:

type ProjectReferenceOrID struct {
	// Ref is an optional field that points at a cloud.temporal.io/Project.
	// +optional
	Ref *ProjectReference `json:"ref,omitempty"`
	// ID is the Temporal Cloud Project resource identifier
	// +optional
	ID string `json:"id,omitempty"`
}

// ProjectReference points at a cloud.temporal.io/Project.
type ProjectReference struct {
	// Namespace contains the optional Kubernetes Namespace in which to find
	// the Project. If empty, the Kubernetes Namespace containing the referring
	// object is used.
	Namespace string `json:"namespace,omitempty"`
	// Name is the name of the Project.
	// +required
	Name string `json:"name"`
}

The reconciler's logic has been changed in the following important way:

Namespace.Spec.Project is NEVER mutated once by the user. Prior to
this commit, the ProjectId field in the CreateNamespaceResponse
struct was used to populate the Spec.Project field. This is no longer
the case. Instead, ProjectId is used to populate the
Status.References.Project field, which is specifically storing the
Temporal Cloud-returned resource identifier for the Temporal Cloud
Project containing the Temporal Namespace.

Anywhere that was previously checking for whether Spec.Project was
set is now checking Status.References.Project.

Issue #47

Signed-off-by: Jay Pipes jay.pipes@temporal.io

@tomba7

tomba7 commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

@jaypipes I would love to get your opinion on folding the fields under references directly into resource. That would let us drop the status.cloud level and use status.resource, which would hold the common fields + the resource specific ones.

apiVersion: cloud.temporal.io/v1alpha1
kind: Namespace
metadata:
  name: payments
spec:
  project:
    ref:
      name: payments-project
  connectivityRules:
  - ref:
      name: payments-privatelink
  replicas:
  - region: aws-us-east-1
  - region: aws-us-west-2
  retentionDays: 30
status:
  conditions: [...]
  resource:
    id: payments.a1b2c
    version: "1730835700-3"
    state: Active
    asyncOperationID: 8f2c1e4a-...
    createdTime: "2026-11-05T19:40:42Z"
    lastModifiedTime: "2026-11-05T19:41:30Z"
    projectID: proj-123              # resolved from spec.project.ref
    connectivityRuleIDs:             # resolved from spec.connectivityRules[].ref
    - cr-1a2b3c4d
    endpoints:
      grpcAddress: us-east-1.aws.api.temporal.io:7233
      mtlsGrpcAddress: payments.a1b2c.tmprl.cloud:7233
      webAddress: https://cloud.temporal.io/namespaces/payments.a1b2c
    replicas:
    - region: aws-us-east-1
      isPrimary: true
      state: Active
    - region: aws-us-west-2
      isPrimary: false
      state: Active

I would summarize my thought process as follows

  • status.resource shows what Temporal Cloud sees (this includes the resolved IDs as how they are returned in the response)
  • every resource has the common fields
  • each resource adds its own fields as needed (key fields we may want to expose per resource on top of the common ones)
  • each resource has its own status.resource type that embeds the common fields struct

@jaypipes

jaypipes commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator Author

@jaypipes I would love to get your opinion on folding the fields under references directly into resource. That would let us drop the status.cloud level and use status.resource, which would hold the common fields + the resource specific ones.

@tomba7 The reason I created a separate named status.cloud field with a resource and references field is twofold:

  1. I anticipate that we will run into field naming conflicts if we inline the ResourceStatus struct into the CRD's Status struct. Particularly the fields id, version and state on ResourceStatus I anticipate there will likely be conflicting fields in the Temporal Cloud Ops API XXXResponse and XXXResponse.Spec structs that will cause us headaches. Using a named field like Status.Cloud.Resource allows us to entirely segregate the common fields related to the specific Temporal Cloud resource represented by the CR itself.
  2. Having a separate named field references enables two things that are important (to me at least! :) ):
  • Naming the field Cloud.References makes it clear that what is contained in the field value are specifically Temporal Cloud resource identifiers for any related resources. I would be open to naming the field Cloud.Relationships or Cloud.ReferenceIdentifiers if you think either of those names is better?
  • Since the Cloud.References field only contains Temporal Cloud resource identifiers, there is no need to suffix all of the composite field names with ID or IDs. Personally, I find Cloud.References.Project and Cloud.References.ConnectivityRules easier to read and the user doesn't need to remember whether the suffix is "ID" or "Id" or "IDs" or "Ids".

As for including other fields in the CRD's Status struct that correspond to read-only fields returned in the Temporal Cloud Ops API XXXResponse and XXXResponse.Spec structs (e.g. Endpoints and Replicas for a Namespace resource), I'd prefer to place those things into a Status.Info field (for "Informational"). This would make the Namespace look like this:

apiVersion: cloud.temporal.io/v1alpha1
kind: Namespace
metadata:
  name: payments
spec:
  project:
    ref:
      name: payments-project
  connectivityRules:
  - ref:
      name: payments-privatelink
  replicas:
  - region: aws-us-east-1
  - region: aws-us-west-2
  retentionDays: 30
status:
  conditions: [...]
  cloud:
    resource:
      id: payments.a1b2c
      version: "1730835700-3"
      state: Active
      asyncOperationID: 8f2c1e4a-...
      createdTime: "2026-11-05T19:40:42Z"
      lastModifiedTime: "2026-11-05T19:41:30Z"
    references:
      project: proj-123              # resolved from spec.project.ref
      connectivityRules:             # resolved from spec.connectivityRules[].ref
      - cr-1a2b3c4d
  info:
    endpoints:
      grpcAddress: us-east-1.aws.api.temporal.io:7233
      mtlsGrpcAddress: payments.a1b2c.tmprl.cloud:7233
      webAddress: https://cloud.temporal.io/namespaces/payments.a1b2c
    replicas:
    - region: aws-us-east-1
      isPrimary: true
      state: Active
    - region: aws-us-west-2
      isPrimary: false
      state: Active

If you would like to flatten the Status struct and remove the Status.Cloud nesting, I could go for that. That would make the Namespace look like this:

apiVersion: cloud.temporal.io/v1alpha1
kind: Namespace
metadata:
  name: payments
spec:
  project:
    ref:
      name: payments-project
  connectivityRules:
  - ref:
      name: payments-privatelink
  replicas:
  - region: aws-us-east-1
  - region: aws-us-west-2
  retentionDays: 30
status:
  conditions: [...]
  resource:
    id: payments.a1b2c
    version: "1730835700-3"
    state: Active
    asyncOperationID: 8f2c1e4a-...
    createdTime: "2026-11-05T19:40:42Z"
    lastModifiedTime: "2026-11-05T19:41:30Z"
  references:
    project: proj-123              # resolved from spec.project.ref
    connectivityRules:             # resolved from spec.connectivityRules[].ref
    - cr-1a2b3c4d
  info:
    endpoints:
      grpcAddress: us-east-1.aws.api.temporal.io:7233
      mtlsGrpcAddress: payments.a1b2c.tmprl.cloud:7233
      webAddress: https://cloud.temporal.io/namespaces/payments.a1b2c
    replicas:
    - region: aws-us-east-1
      isPrimary: true
      state: Active
    - region: aws-us-west-2
      isPrimary: false
      state: Active

/cc @zainawaisn @nmechack27

@tomba7

tomba7 commented Nov 6, 2026

Copy link
Copy Markdown
Collaborator

Thanks @jaypipes. Very well explained and I love the clean distinction on what each section is intended for. I am opting for the later flattened example as I find it much easier to read from the users perspsective.

This commit makes some changes to the Namespace CR to make the handling
of Temporal Cloud-returned identifiers more consistent and to provide
extensibility to allow referencing Temporal Cloud resources by their
Kubernetes Custom Resource counterpart.

We modify `api/cloud/common.ResourceStatus` by shortening the name of
the `ResourceVersion` field to just `Version`. This was done because
`ResourceStatus` is now no longer an inlined field in `NamespaceStatus`
but rather a named field inside the `NamespaceStatus` struct.
`NamespaceStatus` struct now has another field called `References` which
contains Temporal Cloud resource identifiers of any related resources --
e.g. Projects or Connectivity Rules:

```go
// NamespaceStatus describes the current status of a Temporal Cloud namespace.
// This struct does not contain a FromProto or ToProto function because there is
// no corresponding NamespaceStatus struct in the Temporal Cloud API.
// +k8s:openapi-gen=true
type NamespaceStatus struct {
	tmprlcorev1.StatusBase `json:",inline"`
	// Resource contains common information about the Temporal Cloud resource
	// that this CR represents.
	Resource cloudcommon.ResourceStatus `json:"resource"`
	// References is an optional field containing the Temporal Cloud resource
	// IDs for any related resources.
	References NamespaceReferences `json:"references,omitempty"`
}

// NamespaceReferences is an optional field containing the
// Temporal Cloud resource IDs for any related resources.
type NamespaceReferences struct {
	// Project is the Temporal Cloud resource identifier for the Project
	// containing this Temporal Namespace.
	Project string `json:"project,omitempty"`
	// ConnectivityRules is the set of Temporal Cloud resource identifiers for
	// any Namespace ConnectivityRules associated with this Temporal Namespace
	ConnectivityRules []string `json:"connectivityRules,omitempty"`
}
```

The `NamespaceSpec.Project` field type has been modified from `string`
to `ProjectReferenceOrID`, which is a struct that can contain *either* a
Temporal Cloud resource identifier *or* a reference to a (to be created)
`cloud.temporal.io/Project` CR:

```go
type ProjectReferenceOrID struct {
	// Ref is an optional field that points at a cloud.temporal.io/Project.
	// +optional
	Ref *ProjectReference `json:"ref,omitempty"`
	// ID is the Temporal Cloud Project resource identifier
	// +optional
	ID string `json:"id,omitempty"`
}

// ProjectReference points at a cloud.temporal.io/Project.
type ProjectReference struct {
	// Namespace contains the optional Kubernetes Namespace in which to find
	// the Project. If empty, the Kubernetes Namespace containing the referring
	// object is used.
	Namespace string `json:"namespace,omitempty"`
	// Name is the name of the Project.
	// +required
	Name string `json:"name"`
}
```

The reconciler's logic has been changed in the following important way:

`Namespace.Spec.Project` is NEVER mutated once by the user. Prior to
this commit, the `ProjectId` field in the `CreateNamespaceResponse`
struct was used to populate the Spec.Project field. This is no longer
the case. Instead, `ProjectId` is used to populate the
`Status.References.Project` field, which is specifically storing the
Temporal Cloud-returned resource identifier for the Temporal Cloud
Project containing the Temporal Namespace.

Anywhere that was previously checking for whether `Spec.Project` was
set is now checking `Status.References.Project`.

Issue #47

Signed-off-by: Jay Pipes <jay.pipes@temporal.io>

@tomba7 tomba7 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @jaypipes!

@jaypipes
jaypipes merged commit 6c70930 into main Nov 6, 2026
7 checks passed
@jaypipes
jaypipes deleted the resource-status branch November 6, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants