Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
*.swp
*.swo
*~
Expand Down
9 changes: 1 addition & 8 deletions .mk/gen.mk
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,10 @@ gen-kube-register: $(KUBE_CODEGEN_PATH) ## Generate API scheme and groupversion

.PHONY: gen-kube-manifests
CONTROLLER_ROLE_NAME ?= temporal-resource-operator
# Note that the option maxDescLen=0 was added in the default scaffold in
# order to sort out the issue Too long: must have at most 262144 bytes. By
# using kubectl apply to create / update resources an annotation is created
# by K8s API to store the latest version of the resource (
# kubectl.kubernetes.io/last-applied-configuration). However, it has a
# size limit and if the CRD is too big with so many long descriptions as
# this one it will cause the failure.
gen-kube-manifests: $(CONTROLLER_GEN) ## Generate WebhookConfiguration, ClusterRole objects.
@echo -n "generating Kubernetes manifests ... "
@$(CONTROLLER_GEN) rbac:roleName=$(CONTROLLER_ROLE_NAME) \
crd:maxDescLen=0 webhook paths="./api/...;./controller/..." \
crd webhook paths="./api/...;./controller/..." \
output:crd:dir=deploy/kustomize/crd/bases \
output:rbac:dir=deploy/kustomize/rbac
@echo "ok."
6 changes: 5 additions & 1 deletion .mk/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ test-clean-build:
test-clean: test-clean-build test-cluster-delete ## Clean up the test environment.

.PHONY: test-e2e
test-e2e: test-e2e-install test-e2e-namespace ## Run all end to end tests.
test-e2e: test-e2e-install test-e2e-namespace-validation test-e2e-namespace ## Run all end to end tests.

.PHONY: test-e2e-install
test-e2e-install: $(GDT) ## Test that expected artifacts are all present in test cluster.
Expand All @@ -102,3 +102,7 @@ test-e2e-install: $(GDT) ## Test that expected artifacts are all present in test
.PHONY: test-e2e-namespace
test-e2e-namespace: $(GDT) ## Test lifecycle management of Temporal Cloud Namespace by the temporal-resource-operator.
@TEST_USER_NAMESPACE=tro-e2e-cluster $(GDT) $(TEST_GDT_ARGS) run test/e2e/namespace/happy-default.yaml

.PHONY: test-e2e-namespace-validation
test-e2e-namespace-validation: $(GDT) ## Test that the Namespace CRD accepts valid and rejects invalid Namespace manifests.
@TEST_USER_NAMESPACE=tro-e2e-validation $(GDT) $(TEST_GDT_ARGS) run test/e2e/namespace/validation.yaml
Comment thread
tomba7 marked this conversation as resolved.
71 changes: 71 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ kind: Namespace
metadata:
name: my-org-namespace
namespace: temporal-cloud # NOTE: this is the Kubernetes Namespace, not the Temporal Cloud Namespace.
spec:
replicas:
- region: aws-us-west-2
retentionDays: 30
apiKeyAuth:
enabled: true
EOF
```

Expand Down Expand Up @@ -58,6 +64,63 @@ $ kubectl apply -n temporal-resource-operator -k "https://github.com/temporalio/

## Create a new Temporal Cloud Namespace

Describe the Temporal Cloud Namespace in a `Namespace` manifest, such as
[`examples/namespace.yaml`](examples/namespace.yaml):

```yaml
apiVersion: cloud.temporal.io/v1alpha1
kind: Namespace
metadata:
name: payments-prod
spec:
tags:
environment: production
team: payments
replicas:
- region: aws-us-west-2
retentionDays: 30
apiKeyAuth:
enabled: true
capacity:
onDemand: {}
description: Payment workflows for production.
```

Apply it to the Kubernetes Namespace that holds your Temporal Cloud
resources:

```bash
$ kubectl apply -n temporal-cloud -f examples/namespace.yaml
namespace.cloud.temporal.io/payments-prod created
```

The Temporal Cloud Namespace takes its name from `metadata.name`, which must
be a valid Temporal Cloud Namespace name. To list every `spec` field with the
Temporal Cloud field it maps to, run:

```bash
$ kubectl explain namespaces.spec --api-version=cloud.temporal.io/v1alpha1
```

The Kubernetes API server checks the structure of the manifest when you apply
it:

```bash
$ kubectl apply -n temporal-cloud -f examples/namespace.yaml # with both onDemand and provisioned capacity
The Namespace "payments-prod" is invalid: spec.capacity: Invalid value: exactly one of onDemand or provisioned must be set
```

The API server checks that:

* `replicas` and `retentionDays` are set, and `replicas` is not empty.
* Enum values are valid, replica regions are unique, and exactly one capacity
mode is set.
* Updates do not change `project`, and do not remove search attributes or
change their type.

Temporal Cloud reports all other errors, such as invalid tags or a retention
period out of range.

## Modify a Temporal Cloud Namespace

## Delete a Temporal Cloud Namespace
Expand Down Expand Up @@ -181,4 +244,12 @@ manages the lifecycle of Temporal Cloud resources:
make test-e2e-cluster
```

To run functional tests that verify that the Namespace CRD accepts valid
manifests, including `examples/namespace.yaml`, and rejects invalid ones at
`kubectl apply`:

```
make test-e2e-namespace-validation
```

[gdt]: https://github.com/gdt-dev/gdt
4 changes: 4 additions & 0 deletions api/cloud/common/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Package common contains API types shared by the Temporal Cloud resource
// CRDs.
// +k8s:deepcopy-gen=package
package common
10 changes: 10 additions & 0 deletions api/cloud/common/lifecycle_spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package common

// LifecycleSpec configures lifecycle settings for a Temporal Cloud resource.
// Maps to Temporal Cloud proto `LifecycleSpec`.
type LifecycleSpec struct {
// EnableDeleteProtection prevents the resource from being deleted.
// Maps to Temporal Cloud proto `LifecycleSpec.enable_delete_protection`.
// +optional
EnableDeleteProtection bool `json:"enableDeleteProtection,omitempty"`
}
72 changes: 72 additions & 0 deletions api/cloud/common/resource_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package common

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ResourceStatus describes the state of a Temporal Cloud resource as reported
// by Temporal Cloud. Not every resource type reports every field. Fields that
// a resource type does not report are left unset.
//
// Ref: https://github.com/temporalio/cloud-api/blob/main/temporal/api/cloud/resource/v1/message.proto
type ResourceStatus struct {
// ID is the identifier Temporal Cloud uses for the resource. Not set for
// resources that Temporal Cloud identifies by name.
// Maps to Temporal Cloud proto `id`, or `Namespace.namespace` for
// Namespaces.
// +optional
ID string `json:"id,omitempty"`
// ResourceVersion is the version of the resource in Temporal Cloud. It is
// sent with each update and delete request.
// Maps to Temporal Cloud proto `resource_version`.
// +optional
ResourceVersion string `json:"resourceVersion,omitempty"`
// State is the state of the resource in Temporal Cloud.
// Maps to Temporal Cloud proto `state`.
// +optional
State ResourceState `json:"state,omitempty"`
// AsyncOperationID is the ID of the most recent asynchronous operation
// started on the resource.
// Maps to Temporal Cloud proto `async_operation_id`.
// +optional
AsyncOperationID string `json:"asyncOperationID,omitempty"`
// CreatedTime is when the resource was created in Temporal Cloud.
// Maps to Temporal Cloud proto `created_time`.
// +optional
CreatedTime *metav1.Time `json:"createdTime,omitempty"`
// LastModifiedTime is when the resource was last modified in Temporal
// Cloud.
// Maps to Temporal Cloud proto `last_modified_time`.
// +optional
LastModifiedTime *metav1.Time `json:"lastModifiedTime,omitempty"`
}

// ResourceState is the state of a resource in Temporal Cloud.
// Maps to Temporal Cloud proto `ResourceState`.
// +kubebuilder:validation:Enum=Activating;ActivationFailed;Active;Updating;UpdateFailed;Deleting;DeleteFailed;Deleted;Suspended;Expired
type ResourceState string

const (
// ResourceStateActivating means the resource is being activated.
ResourceStateActivating ResourceState = "Activating"
// ResourceStateActivationFailed means the resource failed to activate.
ResourceStateActivationFailed ResourceState = "ActivationFailed"
// ResourceStateActive means the resource is active and ready to use.
ResourceStateActive ResourceState = "Active"
// ResourceStateUpdating means the resource is being updated.
ResourceStateUpdating ResourceState = "Updating"
// ResourceStateUpdateFailed means the resource failed to update.
ResourceStateUpdateFailed ResourceState = "UpdateFailed"
// ResourceStateDeleting means the resource is being deleted.
ResourceStateDeleting ResourceState = "Deleting"
// ResourceStateDeleteFailed means the resource failed to delete.
ResourceStateDeleteFailed ResourceState = "DeleteFailed"
// ResourceStateDeleted means the resource has been deleted.
ResourceStateDeleted ResourceState = "Deleted"
// ResourceStateSuspended means the resource is suspended and not
// available for use.
ResourceStateSuspended ResourceState = "Suspended"
// ResourceStateExpired means the resource has expired and is no longer
// available for use.
ResourceStateExpired ResourceState = "Expired"
)
46 changes: 46 additions & 0 deletions api/cloud/common/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading