|
| 1 | +// Unless explicitly stated otherwise all files in this repository are licensed under the MIT License. |
| 2 | +// |
| 3 | +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2024 Datadog, Inc. |
| 4 | + |
| 5 | +package v1alpha1 |
| 6 | + |
| 7 | +import ( |
| 8 | + corev1 "k8s.io/api/core/v1" |
| 9 | + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
| 10 | +) |
| 11 | + |
| 12 | +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. |
| 13 | + |
| 14 | +// TemporalConnectionReference contains the name of a TemporalConnection resource |
| 15 | +// in the same namespace as the TemporalWorkerDeployment. |
| 16 | +type TemporalConnectionReference struct { |
| 17 | + // Name of the TemporalConnection resource. |
| 18 | + // +kubebuilder:validation:Required |
| 19 | + // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$` |
| 20 | + Name string `json:"name"` |
| 21 | +} |
| 22 | + |
| 23 | +type DeprecatedWorkerOptions struct { |
| 24 | + // The name of a TemporalConnection in the same namespace as the TemporalWorkerDeployment. |
| 25 | + TemporalConnectionRef TemporalConnectionReference `json:"connectionRef"` |
| 26 | + // The Temporal namespace for the worker to connect to. |
| 27 | + // +kubebuilder:validation:MinLength=1 |
| 28 | + TemporalNamespace string `json:"temporalNamespace"` |
| 29 | + // UnsafeCustomBuildID optionally overrides the auto-generated build ID for this worker deployment. |
| 30 | + // When set, the controller uses this value instead of computing a build ID from the |
| 31 | + // pod template hash. This enables rolling updates for non-workflow code changes |
| 32 | + // (bug fixes, config changes) while preserving the same build ID. |
| 33 | + // |
| 34 | + // WARNING: Using a custom build ID requires careful management. If workflow code changes |
| 35 | + // but UnsafeCustomBuildID stays the same, pinned workflows may execute on workers running incompatible |
| 36 | + // code. Only use this when you have a reliable way to detect changes in your workflow |
| 37 | + // definitions (e.g., hashing workflow source files in CI/CD). |
| 38 | + // |
| 39 | + // When the UnsafeCustomBuildID is stable but pod template spec changes, the controller triggers |
| 40 | + // a rolling update instead of creating a new deployment version. The controller uses |
| 41 | + // a hash of the user-provided pod template spec to detect ANY changes, including |
| 42 | + // container images, env vars, commands, volumes, resources, and all other fields. |
| 43 | + // +optional |
| 44 | + // +kubebuilder:validation:MaxLength=63 |
| 45 | + // +kubebuilder:validation:Pattern=`^[a-zA-Z0-9]([a-zA-Z0-9._-]*[a-zA-Z0-9])?$` |
| 46 | + UnsafeCustomBuildID string `json:"unsafeCustomBuildID,omitempty"` |
| 47 | +} |
| 48 | + |
| 49 | +// TemporalWorkerDeploymentSpec defines the desired state of TemporalWorkerDeployment |
| 50 | +type TemporalWorkerDeploymentSpec struct { |
| 51 | + |
| 52 | + // Number of desired pods. When set, the controller manages replicas for all active |
| 53 | + // worker versions. When omitted (nil), the controller creates versioned Deployments |
| 54 | + // with nil replicas and never calls UpdateScale on active versions — following the |
| 55 | + // Kubernetes-recommended pattern for HPA and other external autoscalers |
| 56 | + // (https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#migrating-deployments-and-statefulsets-to-horizontal-autoscaling). |
| 57 | + // The controller still scales drained versions (and inactive versions that are not |
| 58 | + // the rollout target) to zero regardless. |
| 59 | + // This field makes TemporalWorkerDeploymentSpec implement the scale subresource, which is compatible with auto-scalers. |
| 60 | + // +optional |
| 61 | + Replicas *int32 `json:"replicas,omitempty" protobuf:"varint,1,opt,name=replicas"` |
| 62 | + |
| 63 | + // Template describes the pods that will be created. |
| 64 | + // The only allowed template.spec.restartPolicy value is "Always". |
| 65 | + Template corev1.PodTemplateSpec `json:"template"` |
| 66 | + |
| 67 | + // Minimum number of seconds for which a newly created pod should be ready |
| 68 | + // without any of its container crashing, for it to be considered available. |
| 69 | + // Defaults to 0 (pod will be considered available as soon as it is ready) |
| 70 | + // +optional |
| 71 | + // +kubebuilder:default=0 |
| 72 | + MinReadySeconds int32 `json:"minReadySeconds,omitempty"` |
| 73 | + |
| 74 | + // The maximum time in seconds for a deployment to make progress before it |
| 75 | + // is considered to be failed. The deployment controller will continue to |
| 76 | + // process failed deployments and a condition with a ProgressDeadlineExceeded |
| 77 | + // reason will be surfaced in the deployment status. Note that progress will |
| 78 | + // not be estimated during the time a deployment is paused. Defaults to 600s. |
| 79 | + // +kubebuilder:default=600 |
| 80 | + ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty" protobuf:"varint,9,opt,name=progressDeadlineSeconds"` |
| 81 | + |
| 82 | + // How to rollout new workflow executions to the target version. |
| 83 | + RolloutStrategy RolloutStrategy `json:"rollout"` |
| 84 | + |
| 85 | + // How to manage sunsetting drained versions. |
| 86 | + SunsetStrategy SunsetStrategy `json:"sunset"` |
| 87 | + |
| 88 | + // WorkerOptions configures the worker's connection to Temporal. |
| 89 | + WorkerOptions DeprecatedWorkerOptions `json:"workerOptions"` |
| 90 | +} |
| 91 | + |
| 92 | +// Condition reason constants for TemporalWorkerDeployment. |
| 93 | +// |
| 94 | +// These strings appear in status.conditions[].reason and are part of the CRD's |
| 95 | +// status API. Operators, monitoring rules, and scripts may depend on them. |
| 96 | +// They should be treated as stable within an API version and renamed only with |
| 97 | +// a corresponding version bump. |
| 98 | +const ( |
| 99 | + // ReasonTemporalConnectionNotFound is set on ConditionProgressing=False when the |
| 100 | + // referenced TemporalConnection resource cannot be found. |
| 101 | + ReasonTemporalConnectionNotFound = "TemporalConnectionNotFound" |
| 102 | + |
| 103 | + // Deprecated: Use ReasonRolloutComplete on ConditionReady instead. |
| 104 | + ReasonTemporalConnectionHealthy = "TemporalConnectionHealthy" |
| 105 | +) |
| 106 | + |
| 107 | +// TemporalWorkerDeploymentStatus defines the observed state of TemporalWorkerDeployment |
| 108 | +type TemporalWorkerDeploymentStatus struct { |
| 109 | + // Remember, status should be able to be reconstituted from the state of the world, |
| 110 | + // so it's generally not a good idea to read from the status of the root object. |
| 111 | + // Instead, you should reconstruct it every run. |
| 112 | + |
| 113 | + // TargetVersion is the desired next version. If TargetVersion.Deployment is nil, |
| 114 | + // then the controller should create it. If not nil, the controller should |
| 115 | + // wait for it to become healthy and then move it to the CurrentVersion. |
| 116 | + TargetVersion TargetWorkerDeploymentVersion `json:"targetVersion"` |
| 117 | + |
| 118 | + // CurrentVersion is the version that is currently registered with |
| 119 | + // Temporal as the current version of its worker deployment. This will be nil |
| 120 | + // during initial bootstrap until a version is registered and set as current. |
| 121 | + CurrentVersion *CurrentWorkerDeploymentVersion `json:"currentVersion,omitempty"` |
| 122 | + |
| 123 | + // DeprecatedVersions are deployment versions that are no longer the default. Any |
| 124 | + // deployment versions that are unreachable should be deleted by the controller. |
| 125 | + DeprecatedVersions []*DeprecatedWorkerDeploymentVersion `json:"deprecatedVersions,omitempty"` |
| 126 | + |
| 127 | + // VersionConflictToken prevents concurrent modifications to the deployment status. |
| 128 | + // It ensures reconciliation operations don't inadvertently override changes made |
| 129 | + // by external systems while processing is underway. |
| 130 | + VersionConflictToken []byte `json:"versionConflictToken,omitempty"` |
| 131 | + |
| 132 | + // LastModifierIdentity is the identity of the client that most recently modified the worker deployment. |
| 133 | + // +optional |
| 134 | + LastModifierIdentity string `json:"lastModifierIdentity,omitempty"` |
| 135 | + |
| 136 | + // ManagerIdentity is the identity that has exclusive rights to modify this Worker Deployment's routing config. |
| 137 | + // When set, clients whose identity does not match will be blocked from making routing changes. |
| 138 | + // Empty by default. Use `temporal worker deployment manager-identity set/unset` to change. |
| 139 | + // +optional |
| 140 | + ManagerIdentity string `json:"managerIdentity,omitempty"` |
| 141 | + |
| 142 | + // VersionCount is the total number of versions currently known by the worker deployment. |
| 143 | + // This includes current, target, ramping, and deprecated versions. |
| 144 | + // +optional |
| 145 | + // +kubebuilder:validation:Minimum=0 |
| 146 | + VersionCount int32 `json:"versionCount,omitempty"` |
| 147 | + |
| 148 | + // Conditions represent the latest available observations of the TemporalWorkerDeployment's current state. |
| 149 | + // +optional |
| 150 | + Conditions []metav1.Condition `json:"conditions,omitempty"` |
| 151 | +} |
| 152 | + |
| 153 | +//+kubebuilder:object:root=true |
| 154 | +//+kubebuilder:subresource:status |
| 155 | +// +kubebuilder:resource:shortName=twd;twdeployment;tworkerdeployment |
| 156 | +//+kubebuilder:printcolumn:name="Current",type="string",JSONPath=".status.currentVersion.buildID",description="Current build ID" |
| 157 | +//+kubebuilder:printcolumn:name="Target",type="string",JSONPath=".status.targetVersion.buildID",description="Target build ID" |
| 158 | +//+kubebuilder:printcolumn:name="Ramp %",type="number",JSONPath=".status.targetVersion.rampPercentage",description="Ramp percentage" |
| 159 | +//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Age" |
| 160 | +// +kubebuilder:validation:XValidation:rule="size(self.metadata.name) <= 63",message="name cannot be more than 63 characters" |
| 161 | +// +kubebuilder:validation:XValidation:rule="oldSelf != null",message="TemporalWorkerDeployment is deprecated and cannot be created. Use WorkerDeployment instead." |
| 162 | +// +kubebuilder:deprecatedversion:warning="TemporalWorkerDeployment is deprecated. Use WorkerDeployment instead." |
| 163 | + |
| 164 | +// TemporalWorkerDeployment is the Schema for the temporalworkerdeployments API |
| 165 | +type TemporalWorkerDeployment struct { |
| 166 | + metav1.TypeMeta `json:",inline"` |
| 167 | + metav1.ObjectMeta `json:"metadata,omitempty"` |
| 168 | + |
| 169 | + Spec TemporalWorkerDeploymentSpec `json:"spec,omitempty"` |
| 170 | + Status TemporalWorkerDeploymentStatus `json:"status,omitempty"` |
| 171 | +} |
| 172 | + |
| 173 | +//+kubebuilder:object:root=true |
| 174 | + |
| 175 | +// TemporalWorkerDeploymentList contains a list of TemporalWorkerDeployment |
| 176 | +type TemporalWorkerDeploymentList struct { |
| 177 | + metav1.TypeMeta `json:",inline"` |
| 178 | + metav1.ListMeta `json:"metadata,omitempty"` |
| 179 | + Items []TemporalWorkerDeployment `json:"items"` |
| 180 | +} |
| 181 | + |
| 182 | +func init() { |
| 183 | + SchemeBuilder.Register(&TemporalWorkerDeployment{}, &TemporalWorkerDeploymentList{}) |
| 184 | +} |
0 commit comments