github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/apis/apps/v1alpha1/clusterdefinition_types.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1alpha1 18 19 import ( 20 "strings" 21 22 appsv1 "k8s.io/api/apps/v1" 23 corev1 "k8s.io/api/core/v1" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/util/intstr" 26 27 workloads "github.com/1aal/kubeblocks/apis/workloads/v1alpha1" 28 ) 29 30 // ClusterDefinitionSpec defines the desired state of ClusterDefinition 31 type ClusterDefinitionSpec struct { 32 33 // Cluster definition type defines well known application cluster type, e.g. mysql/redis/mongodb 34 // +kubebuilder:validation:MaxLength=24 35 // +kubebuilder:validation:Pattern:=`^[a-z0-9]([a-z0-9\-]*[a-z0-9])?$` 36 // +optional 37 Type string `json:"type,omitempty"` 38 39 // componentDefs provides cluster components definitions. 40 // +kubebuilder:validation:Required 41 // +kubebuilder:validation:MinItems=1 42 // +patchMergeKey=name 43 // +patchStrategy=merge,retainKeys 44 // +listType=map 45 // +listMapKey=name 46 ComponentDefs []ClusterComponentDefinition `json:"componentDefs" patchStrategy:"merge,retainKeys" patchMergeKey:"name"` 47 48 // Connection credential template used for creating a connection credential 49 // secret for cluster.apps.kubeblocks.io object. 50 // 51 // Built-in objects are: 52 // - `$(RANDOM_PASSWD)` - random 8 characters. 53 // - `$(UUID)` - generate a random UUID v4 string. 54 // - `$(UUID_B64)` - generate a random UUID v4 BASE64 encoded string. 55 // - `$(UUID_STR_B64)` - generate a random UUID v4 string then BASE64 encoded. 56 // - `$(UUID_HEX)` - generate a random UUID v4 HEX representation. 57 // - `$(HEADLESS_SVC_FQDN)` - headless service FQDN placeholder, value pattern - $(CLUSTER_NAME)-$(1ST_COMP_NAME)-headless.$(NAMESPACE).svc, 58 // where 1ST_COMP_NAME is the 1st component that provide `ClusterDefinition.spec.componentDefs[].service` attribute; 59 // - `$(SVC_FQDN)` - service FQDN placeholder, value pattern - $(CLUSTER_NAME)-$(1ST_COMP_NAME).$(NAMESPACE).svc, 60 // where 1ST_COMP_NAME is the 1st component that provide `ClusterDefinition.spec.componentDefs[].service` attribute; 61 // - `$(SVC_PORT_{PORT-NAME})` - a ServicePort's port value with specified port name, i.e, a servicePort JSON struct: 62 // `{"name": "mysql", "targetPort": "mysqlContainerPort", "port": 3306}`, and "$(SVC_PORT_mysql)" in the 63 // connection credential value is 3306. 64 // +optional 65 ConnectionCredential map[string]string `json:"connectionCredential,omitempty"` 66 } 67 68 // SystemAccountSpec specifies information to create system accounts. 69 type SystemAccountSpec struct { 70 // cmdExecutorConfig configs how to get client SDK and perform statements. 71 // +kubebuilder:validation:Required 72 CmdExecutorConfig *CmdExecutorConfig `json:"cmdExecutorConfig"` 73 // passwordConfig defines the pattern to generate password. 74 // +kubebuilder:validation:Required 75 PasswordConfig PasswordConfig `json:"passwordConfig"` 76 // accounts defines system account config settings. 77 // +kubebuilder:validation:Required 78 // +kubebuilder:validation:MinItems=1 79 // +patchMergeKey=name 80 // +patchStrategy=merge,retainKeys 81 // +listType=map 82 // +listMapKey=name 83 Accounts []SystemAccountConfig `json:"accounts" patchStrategy:"merge,retainKeys" patchMergeKey:"name"` 84 } 85 86 // CmdExecutorConfig specifies how to perform creation and deletion statements. 87 type CmdExecutorConfig struct { 88 CommandExecutorEnvItem `json:",inline"` 89 CommandExecutorItem `json:",inline"` 90 } 91 92 // PasswordConfig helps provide to customize complexity of password generation pattern. 93 type PasswordConfig struct { 94 // length defines the length of password. 95 // +kubebuilder:validation:Maximum=32 96 // +kubebuilder:validation:Minimum=8 97 // +kubebuilder:default=10 98 // +optional 99 Length int32 `json:"length,omitempty"` 100 // numDigits defines number of digits. 101 // +kubebuilder:validation:Maximum=20 102 // +kubebuilder:validation:Minimum=0 103 // +kubebuilder:default=2 104 // +optional 105 NumDigits int32 `json:"numDigits,omitempty"` 106 // numSymbols defines number of symbols. 107 // +kubebuilder:validation:Maximum=20 108 // +kubebuilder:validation:Minimum=0 109 // +kubebuilder:default=0 110 // +optional 111 NumSymbols int32 `json:"numSymbols,omitempty"` 112 // letterCase defines to use lower-cases, upper-cases or mixed-cases of letters. 113 // +kubebuilder:default=MixedCases 114 // +optional 115 LetterCase LetterCase `json:"letterCase,omitempty"` 116 } 117 118 // SystemAccountConfig specifies how to create and delete system accounts. 119 type SystemAccountConfig struct { 120 // name is the name of a system account. 121 // +kubebuilder:validation:Required 122 Name AccountName `json:"name"` 123 // provisionPolicy defines how to create account. 124 // +kubebuilder:validation:Required 125 ProvisionPolicy ProvisionPolicy `json:"provisionPolicy"` 126 } 127 128 // ProvisionPolicy defines the policy details for creating accounts. 129 type ProvisionPolicy struct { 130 // type defines the way to provision an account, either `CreateByStmt` or `ReferToExisting`. 131 // +kubebuilder:validation:Required 132 Type ProvisionPolicyType `json:"type"` 133 // scope is the scope to provision account, and the scope could be `AnyPods` or `AllPods`. 134 // +kubebuilder:default=AnyPods 135 Scope ProvisionScope `json:"scope"` 136 // statements will be used when Type is CreateByStmt. 137 // +optional 138 Statements *ProvisionStatements `json:"statements,omitempty"` 139 // secretRef will be used when Type is ReferToExisting. 140 // +optional 141 SecretRef *ProvisionSecretRef `json:"secretRef,omitempty"` 142 } 143 144 // ProvisionSecretRef defines the information of secret referred to. 145 type ProvisionSecretRef struct { 146 // name refers to the name of the secret. 147 // +kubebuilder:validation:Required 148 Name string `json:"name"` 149 // namespace refers to the namespace of the secret. 150 // +kubebuilder:validation:Required 151 Namespace string `json:"namespace"` 152 } 153 154 // ProvisionStatements defines the statements used to create accounts. 155 type ProvisionStatements struct { 156 // creation specifies statement how to create this account with required privileges. 157 // +kubebuilder:validation:Required 158 CreationStatement string `json:"creation"` 159 // update specifies statement how to update account's password. 160 // +optional 161 UpdateStatement string `json:"update,omitempty"` 162 // deletion specifies statement how to delete this account. 163 // Used in combination with `CreateionStatement` to delete the account before create it. 164 // For instance, one usually uses `drop user if exists` statement followed by `create user` statement to create an account. 165 // Deprecated: this field is deprecated, use `update` instead. 166 // +optional 167 DeletionStatement string `json:"deletion,omitempty"` 168 } 169 170 // ClusterDefinitionStatus defines the observed state of ClusterDefinition 171 type ClusterDefinitionStatus struct { 172 // ClusterDefinition phase, valid values are `empty`, `Available`, 'Unavailable`. 173 // Available is ClusterDefinition become available, and can be referenced for co-related objects. 174 Phase Phase `json:"phase,omitempty"` 175 176 // Extra message in current phase 177 // +optional 178 Message string `json:"message,omitempty"` 179 180 // observedGeneration is the most recent generation observed for this 181 // ClusterDefinition. It corresponds to the ClusterDefinition's generation, which is 182 // updated on mutation by the API Server. 183 // +optional 184 ObservedGeneration int64 `json:"observedGeneration,omitempty"` 185 } 186 187 func (r ClusterDefinitionStatus) GetTerminalPhases() []Phase { 188 return []Phase{AvailablePhase} 189 } 190 191 type ExporterConfig struct { 192 // scrapePort is exporter port for Time Series Database to scrape metrics. 193 // +kubebuilder:validation:Required 194 // +kubebuilder:validation:XIntOrString 195 ScrapePort intstr.IntOrString `json:"scrapePort"` 196 197 // scrapePath is exporter url path for Time Series Database to scrape metrics. 198 // +kubebuilder:validation:MaxLength=128 199 // +kubebuilder:default="/metrics" 200 // +optional 201 ScrapePath string `json:"scrapePath,omitempty"` 202 } 203 204 type MonitorConfig struct { 205 // builtIn is a switch to enable KubeBlocks builtIn monitoring. 206 // If BuiltIn is set to true, monitor metrics will be scraped automatically. 207 // If BuiltIn is set to false, the provider should set ExporterConfig and Sidecar container own. 208 // +kubebuilder:default=false 209 // +optional 210 BuiltIn bool `json:"builtIn,omitempty"` 211 212 // exporterConfig provided by provider, which specify necessary information to Time Series Database. 213 // exporterConfig is valid when builtIn is false. 214 // +optional 215 Exporter *ExporterConfig `json:"exporterConfig,omitempty"` 216 } 217 218 type LogConfig struct { 219 // name log type name, such as slow for MySQL slow log file. 220 // +kubebuilder:validation:Required 221 // +kubebuilder:validation:MaxLength=128 222 Name string `json:"name"` 223 224 // filePathPattern log file path pattern which indicate how to find this file 225 // corresponding to variable (log path) in database kernel. please don't set this casually. 226 // +kubebuilder:validation:Required 227 // +kubebuilder:validation:MaxLength=4096 228 FilePathPattern string `json:"filePathPattern"` 229 } 230 231 type VolumeTypeSpec struct { 232 // name definition is the same as the name of the VolumeMounts field in PodSpec.Container, 233 // similar to the relations of Volumes[*].name and VolumesMounts[*].name in Pod.Spec. 234 // +kubebuilder:validation:Required 235 // +kubebuilder:validation:Pattern:=`^[a-z0-9]([a-z0-9\.\-]*[a-z0-9])?$` 236 Name string `json:"name"` 237 238 // type is in enum of {data, log}. 239 // VolumeTypeData: the volume is for the persistent data storage. 240 // VolumeTypeLog: the volume is for the persistent log storage. 241 // +optional 242 Type VolumeType `json:"type,omitempty"` 243 } 244 245 type VolumeProtectionSpec struct { 246 // The high watermark threshold for volume space usage. 247 // If there is any specified volumes who's space usage is over the threshold, the pre-defined "LOCK" action 248 // will be triggered to degrade the service to protect volume from space exhaustion, such as to set the instance 249 // as read-only. And after that, if all volumes' space usage drops under the threshold later, the pre-defined 250 // "UNLOCK" action will be performed to recover the service normally. 251 // +kubebuilder:validation:Maximum=100 252 // +kubebuilder:validation:Minimum=0 253 // +kubebuilder:default=90 254 // +optional 255 HighWatermark int `json:"highWatermark,omitempty"` 256 257 // Volumes to protect. 258 // +optional 259 Volumes []ProtectedVolume `json:"volumes,omitempty"` 260 } 261 262 type ProtectedVolume struct { 263 // Name of volume to protect. 264 // +optional 265 Name string `json:"name,omitempty"` 266 267 // Volume specified high watermark threshold, it will override the component level threshold. 268 // If the value is invalid, it will be ignored and the component level threshold will be used. 269 // +kubebuilder:validation:Maximum=100 270 // +kubebuilder:validation:Minimum=0 271 // +optional 272 HighWatermark *int `json:"highWatermark,omitempty"` 273 } 274 275 type ServiceRefDeclaration struct { 276 // The name of the service reference declaration. 277 // The service reference can come from an external service that is not part of KubeBlocks, or services provided by other KubeBlocks Cluster objects. 278 // The specific type of service reference depends on the binding declaration when creates a Cluster. 279 // +kubebuilder:validation:Required 280 Name string `json:"name"` 281 282 // serviceRefDeclarationSpecs is a collection of service descriptions for a service reference declaration. 283 // Each ServiceRefDeclarationSpec defines a service Kind and Version. When multiple ServiceRefDeclarationSpecs are defined, 284 // it indicates that the ServiceRefDeclaration can be any one of the specified ServiceRefDeclarationSpecs. 285 // For example, when the ServiceRefDeclaration is declared to require an OLTP database, which can be either MySQL or PostgreSQL, 286 // you can define a ServiceRefDeclarationSpec for MySQL and another ServiceRefDeclarationSpec for PostgreSQL, 287 // when referencing the service within the cluster, as long as the serviceKind and serviceVersion match either MySQL or PostgreSQL, it can be used. 288 // +kubebuilder:validation:Required 289 ServiceRefDeclarationSpecs []ServiceRefDeclarationSpec `json:"serviceRefDeclarationSpecs"` 290 } 291 292 type ServiceRefDeclarationSpec struct { 293 // service kind, indicating the type or nature of the service. It should be well-known application cluster type, e.g. {mysql, redis, mongodb}. 294 // The serviceKind is case-insensitive and supports abbreviations for some well-known databases. 295 // For example, both 'zk' and 'zookeeper' will be considered as a ZooKeeper cluster, and 'pg', 'postgres', 'postgresql' will all be considered as a PostgreSQL cluster. 296 // +kubebuilder:validation:Required 297 ServiceKind string `json:"serviceKind"` 298 299 // The service version of the service reference. It is a regular expression that matches a version number pattern. 300 // For example, `^8.0.8$`, `8.0.\d{1,2}$`, `^[v\-]*?(\d{1,2}\.){0,3}\d{1,2}$` 301 // +kubebuilder:validation:Required 302 ServiceVersion string `json:"serviceVersion"` 303 } 304 305 // ClusterComponentDefinition provides a workload component specification template, 306 // with attributes that strongly work with stateful workloads and day-2 operations 307 // behaviors. 308 // +kubebuilder:validation:XValidation:rule="has(self.workloadType) && self.workloadType == 'Consensus' ? (has(self.consensusSpec) || has(self.rsmSpec)) : !has(self.consensusSpec)",message="componentDefs.consensusSpec(deprecated) or componentDefs.rsmSpec(recommended) is required when componentDefs.workloadType is Consensus, and forbidden otherwise" 309 type ClusterComponentDefinition struct { 310 // A component definition name, this name could be used as default name of `Cluster.spec.componentSpecs.name`, 311 // and so this name is need to conform with same validation rules as `Cluster.spec.componentSpecs.name`, that 312 // is currently comply with IANA Service Naming rule. This name will apply to "apps.kubeblocks.io/component-name" 313 // object label value. 314 // +kubebuilder:validation:Required 315 // +kubebuilder:validation:MaxLength=22 316 // +kubebuilder:validation:Pattern:=`^[a-z]([a-z0-9\-]*[a-z0-9])?$` 317 Name string `json:"name"` 318 319 // The description of component definition. 320 // +optional 321 Description string `json:"description,omitempty"` 322 323 // workloadType defines type of the workload. 324 // Stateless is a stateless workload type used to describe stateless applications. 325 // Stateful is a stateful workload type used to describe common stateful applications. 326 // Consensus is a stateful workload type used to describe applications based on consensus protocols, common consensus protocols such as raft and paxos. 327 // Replication is a stateful workload type used to describe applications based on the primary-secondary data replication protocol. 328 // +kubebuilder:validation:Required 329 WorkloadType WorkloadType `json:"workloadType"` 330 331 // characterType defines well-known database component name, such as mongos(mongodb), proxy(redis), mariadb(mysql) 332 // KubeBlocks will generate proper monitor configs for well-known characterType when builtIn is true. 333 // 334 // CharacterType will also be used in role probe to decide which probe engine to use. 335 // current available candidates are: mysql, postgres, mongodb, redis, etcd, kafka. 336 // +optional 337 CharacterType string `json:"characterType,omitempty"` 338 339 // The configSpec field provided by provider, and 340 // finally this configTemplateRefs will be rendered into the user's own configuration file according to the user's cluster. 341 // +optional 342 // +patchMergeKey=name 343 // +patchStrategy=merge,retainKeys 344 // +listType=map 345 // +listMapKey=name 346 ConfigSpecs []ComponentConfigSpec `json:"configSpecs,omitempty"` 347 348 // The scriptSpec field provided by provider, and 349 // finally this configTemplateRefs will be rendered into the user's own configuration file according to the user's cluster. 350 // +optional 351 // +patchMergeKey=name 352 // +patchStrategy=merge,retainKeys 353 // +listType=map 354 // +listMapKey=name 355 // +optional 356 ScriptSpecs []ComponentTemplateSpec `json:"scriptSpecs,omitempty"` 357 358 // probes setting for healthy checks. 359 // +optional 360 Probes *ClusterDefinitionProbes `json:"probes,omitempty"` 361 362 // monitor is monitoring config which provided by provider. 363 // +optional 364 Monitor *MonitorConfig `json:"monitor,omitempty"` 365 366 // logConfigs is detail log file config which provided by provider. 367 // +optional 368 // +patchMergeKey=name 369 // +patchStrategy=merge,retainKeys 370 // +listType=map 371 // +listMapKey=name 372 LogConfigs []LogConfig `json:"logConfigs,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name"` 373 374 // podSpec define pod spec template of the cluster component. 375 // +kubebuilder:pruning:PreserveUnknownFields 376 // +optional 377 PodSpec *corev1.PodSpec `json:"podSpec,omitempty"` 378 379 // service defines the behavior of a service spec. 380 // provide read-write service when WorkloadType is Consensus. 381 // +optional 382 Service *ServiceSpec `json:"service,omitempty"` 383 384 // statelessSpec defines stateless related spec if workloadType is Stateless. 385 // +optional 386 //+kubebuilder:deprecatedversion:warning="This field is deprecated from KB 0.7.0, use RSMSpec instead." 387 StatelessSpec *StatelessSetSpec `json:"statelessSpec,omitempty"` 388 389 // statefulSpec defines stateful related spec if workloadType is Stateful. 390 // +optional 391 //+kubebuilder:deprecatedversion:warning="This field is deprecated from KB 0.7.0, use RSMSpec instead." 392 StatefulSpec *StatefulSetSpec `json:"statefulSpec,omitempty"` 393 394 // consensusSpec defines consensus related spec if workloadType is Consensus, required if workloadType is Consensus. 395 // +optional 396 //+kubebuilder:deprecatedversion:warning="This field is deprecated from KB 0.7.0, use RSMSpec instead." 397 ConsensusSpec *ConsensusSetSpec `json:"consensusSpec,omitempty"` 398 399 // replicationSpec defines replication related spec if workloadType is Replication. 400 // +optional 401 //+kubebuilder:deprecatedversion:warning="This field is deprecated from KB 0.7.0, use RSMSpec instead." 402 ReplicationSpec *ReplicationSetSpec `json:"replicationSpec,omitempty"` 403 404 // RSMSpec defines workload related spec of this component. 405 // start from KB 0.7.0, RSM(ReplicatedStateMachineSpec) will be the underlying CR which powers all kinds of workload in KB. 406 // RSM is an enhanced stateful workload extension dedicated for heavy-state workloads like databases. 407 // +optional 408 RSMSpec *RSMSpec `json:"rsmSpec,omitempty"` 409 410 // horizontalScalePolicy controls the behavior of horizontal scale. 411 // +optional 412 HorizontalScalePolicy *HorizontalScalePolicy `json:"horizontalScalePolicy,omitempty"` 413 414 // Statement to create system account. 415 // +optional 416 SystemAccounts *SystemAccountSpec `json:"systemAccounts,omitempty"` 417 418 // volumeTypes is used to describe the purpose of the volumes 419 // mapping the name of the VolumeMounts in the PodSpec.Container field, 420 // such as data volume, log volume, etc. 421 // When backing up the volume, the volume can be correctly backed up 422 // according to the volumeType. 423 // 424 // For example: 425 // `name: data, type: data` means that the volume named `data` is used to store `data`. 426 // `name: binlog, type: log` means that the volume named `binlog` is used to store `log`. 427 // 428 // NOTE: 429 // When volumeTypes is not defined, the backup function will not be supported, 430 // even if a persistent volume has been specified. 431 // +listType=map 432 // +listMapKey=name 433 // +optional 434 VolumeTypes []VolumeTypeSpec `json:"volumeTypes,omitempty"` 435 436 // customLabelSpecs is used for custom label tags which you want to add to the component resources. 437 // +listType=map 438 // +listMapKey=key 439 // +optional 440 CustomLabelSpecs []CustomLabelSpec `json:"customLabelSpecs,omitempty"` 441 442 // switchoverSpec defines command to do switchover. 443 // in particular, when workloadType=Replication, the command defined in switchoverSpec will only be executed under the condition of cluster.componentSpecs[x].SwitchPolicy.type=Noop. 444 // +optional 445 SwitchoverSpec *SwitchoverSpec `json:"switchoverSpec,omitempty"` 446 447 // +optional 448 VolumeProtectionSpec *VolumeProtectionSpec `json:"volumeProtectionSpec,omitempty"` 449 450 // componentDefRef is used to inject values from other components into the current component. 451 // values will be saved and updated in a configmap and mounted to the current component. 452 // +patchMergeKey=componentDefName 453 // +patchStrategy=merge,retainKeys 454 // +listType=map 455 // +listMapKey=componentDefName 456 // +optional 457 ComponentDefRef []ComponentDefRef `json:"componentDefRef,omitempty" patchStrategy:"merge" patchMergeKey:"componentDefName"` 458 459 // serviceRefDeclarations is used to declare the service reference of the current component. 460 // +optional 461 ServiceRefDeclarations []ServiceRefDeclaration `json:"serviceRefDeclarations,omitempty"` 462 } 463 464 func (r *ClusterComponentDefinition) GetStatefulSetWorkload() StatefulSetWorkload { 465 switch r.WorkloadType { 466 case Stateless: 467 return nil 468 case Stateful: 469 return r.StatefulSpec 470 case Consensus: 471 return r.ConsensusSpec 472 case Replication: 473 return r.ReplicationSpec 474 } 475 panic("unreachable") 476 } 477 478 // GetMinAvailable get workload's minAvailable settings, return 51% for workloadType=Consensus, 479 // value 1 pod for workloadType=[Stateless|Stateful|Replication]. 480 func (r *ClusterComponentDefinition) GetMinAvailable() *intstr.IntOrString { 481 if r == nil { 482 return nil 483 } 484 switch r.WorkloadType { 485 case Consensus: 486 // Consensus workload have min pods of >50%. 487 v := intstr.FromString("51%") 488 return &v 489 case Replication, Stateful, Stateless: 490 // Stateful & Replication workload have min. pod being 1. 491 v := intstr.FromInt(1) 492 return &v 493 } 494 return nil 495 } 496 497 // GetMaxUnavailable get workload's maxUnavailable settings, this value is not suitable for PDB.spec.maxUnavailable 498 // usage, as a PDB with maxUnavailable=49% and if workload's replicaCount=3 and allowed disruption pod count is 2, 499 // check following setup: 500 // 501 // #cmd: kubectl get sts,po,pdb -l app.kubernetes.io/instance=consul 502 // NAME READY AGE 503 // statefulset.apps/consul 3/3 3h23m 504 // 505 // NAME READY STATUS RESTARTS AGE 506 // pod/consul-0 1/1 Running 0 3h 507 // pod/consul-2 1/1 Running 0 16s 508 // pod/consul-1 1/1 Running 0 16s 509 // 510 // NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE 511 // poddisruptionbudget.policy/consul N/A 49% 2 3h23m 512 // 513 // VS. using minAvailable=51% will result allowed disruption pod count is 1 514 // 515 // NAME READY AGE 516 // statefulset.apps/consul 3/3 3h26m 517 // 518 // NAME READY STATUS RESTARTS AGE 519 // pod/consul-0 1/1 Running 0 3h3m 520 // pod/consul-2 1/1 Running 0 3m35s 521 // pod/consul-1 1/1 Running 0 3m35s 522 // 523 // NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE 524 // poddisruptionbudget.policy/consul 51% N/A 1 3h26m 525 func (r *ClusterComponentDefinition) GetMaxUnavailable() *intstr.IntOrString { 526 if r == nil { 527 return nil 528 } 529 530 getMaxUnavailable := func(ssus appsv1.StatefulSetUpdateStrategy) *intstr.IntOrString { 531 if ssus.RollingUpdate == nil { 532 return nil 533 } 534 return ssus.RollingUpdate.MaxUnavailable 535 } 536 537 switch r.WorkloadType { 538 case Stateless: 539 if r.StatelessSpec == nil || r.StatelessSpec.UpdateStrategy.RollingUpdate == nil { 540 return nil 541 } 542 return r.StatelessSpec.UpdateStrategy.RollingUpdate.MaxUnavailable 543 case Stateful, Consensus, Replication: 544 _, s := r.GetStatefulSetWorkload().FinalStsUpdateStrategy() 545 return getMaxUnavailable(s) 546 } 547 panic("unreachable") 548 } 549 550 func (r *ClusterComponentDefinition) IsStatelessWorkload() bool { 551 return r.WorkloadType == Stateless 552 } 553 554 func (r *ClusterComponentDefinition) GetCommonStatefulSpec() (*StatefulSetSpec, error) { 555 if r.IsStatelessWorkload() { 556 return nil, ErrWorkloadTypeIsStateless 557 } 558 switch r.WorkloadType { 559 case Stateful: 560 return r.StatefulSpec, nil 561 case Consensus: 562 if r.ConsensusSpec != nil { 563 return &r.ConsensusSpec.StatefulSetSpec, nil 564 } 565 case Replication: 566 if r.ReplicationSpec != nil { 567 return &r.ReplicationSpec.StatefulSetSpec, nil 568 } 569 default: 570 panic("unreachable") 571 // return nil, ErrWorkloadTypeIsUnknown 572 } 573 return nil, nil 574 } 575 576 type ServiceSpec struct { 577 // The list of ports that are exposed by this service. 578 // More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies 579 // +patchMergeKey=port 580 // +patchStrategy=merge 581 // +listType=map 582 // +listMapKey=port 583 // +listMapKey=protocol 584 // +optional 585 Ports []ServicePort `json:"ports,omitempty" patchStrategy:"merge" patchMergeKey:"port" protobuf:"bytes,1,rep,name=ports"` 586 587 // NOTES: name also need to be key 588 } 589 590 func (r *ServiceSpec) toSVCPorts() []corev1.ServicePort { 591 ports := make([]corev1.ServicePort, 0, len(r.Ports)) 592 for _, p := range r.Ports { 593 ports = append(ports, p.toSVCPort()) 594 } 595 return ports 596 } 597 598 func (r ServiceSpec) ToSVCSpec() corev1.ServiceSpec { 599 return corev1.ServiceSpec{ 600 Ports: r.toSVCPorts(), 601 } 602 } 603 604 type ServicePort struct { 605 // The name of this port within the service. This must be a DNS_LABEL. 606 // All ports within a ServiceSpec must have unique names. When considering 607 // the endpoints for a Service, this must match the 'name' field in the 608 // EndpointPort. 609 // +kubebuilder:validation:Required 610 Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` 611 612 // The IP protocol for this port. Supports "TCP", "UDP", and "SCTP". 613 // Default is TCP. 614 // +kubebuilder:validation:Enum={TCP,UDP,SCTP} 615 // +default="TCP" 616 // +optional 617 Protocol corev1.Protocol `json:"protocol,omitempty" protobuf:"bytes,2,opt,name=protocol,casttype=Protocol"` 618 619 // The application protocol for this port. 620 // This field follows standard Kubernetes label syntax. 621 // Un-prefixed names are reserved for IANA standard service names (as per 622 // RFC-6335 and https://www.iana.org/assignments/service-names). 623 // Non-standard protocols should use prefixed names such as 624 // mycompany.com/my-custom-protocol. 625 // +optional 626 AppProtocol *string `json:"appProtocol,omitempty" protobuf:"bytes,6,opt,name=appProtocol"` 627 628 // The port that will be exposed by this service. 629 Port int32 `json:"port" protobuf:"varint,3,opt,name=port"` 630 631 // Number or name of the port to access on the pods targeted by the service. 632 // Number must be in the range 1 to 65535. Name must be an IANA_SVC_NAME. 633 // If this is a string, it will be looked up as a named port in the 634 // target Pod's container ports. If this is not specified, the value 635 // of the 'port' field is used (an identity map). 636 // This field is ignored for services with clusterIP=None, and should be 637 // omitted or set equal to the 'port' field. 638 // More info: https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service 639 // +kubebuilder:validation:XIntOrString 640 // +optional 641 TargetPort intstr.IntOrString `json:"targetPort,omitempty" protobuf:"bytes,4,opt,name=targetPort"` 642 } 643 644 func (r *ServicePort) toSVCPort() corev1.ServicePort { 645 return corev1.ServicePort{ 646 Name: r.Name, 647 Protocol: r.Protocol, 648 AppProtocol: r.AppProtocol, 649 Port: r.Port, 650 TargetPort: r.TargetPort, 651 } 652 } 653 654 type HorizontalScalePolicy struct { 655 // type controls what kind of data synchronization do when component scale out. 656 // Policy is in enum of {None, CloneVolume}. The default policy is `None`. 657 // None: Default policy, create empty volume and no data clone. 658 // CloneVolume: Do data clone to newly scaled pods. Prefer to use volume snapshot first, 659 // and will try backup tool if volume snapshot is not enabled, finally 660 // report error if both above cannot work. 661 // Snapshot: Deprecated, alias for CloneVolume. 662 // +kubebuilder:default=None 663 // +optional 664 Type HScaleDataClonePolicyType `json:"type,omitempty"` 665 666 // BackupPolicyTemplateName reference the backup policy template. 667 // +optional 668 BackupPolicyTemplateName string `json:"backupPolicyTemplateName,omitempty"` 669 670 // volumeMountsName defines which volumeMount of the container to do backup, 671 // only work if Type is not None 672 // if not specified, the 1st volumeMount will be chosen 673 // +optional 674 VolumeMountsName string `json:"volumeMountsName,omitempty"` 675 } 676 677 type ClusterDefinitionProbeCMDs struct { 678 // Write check executed on probe sidecar, used to check workload's allow write access. 679 // +optional 680 Writes []string `json:"writes,omitempty"` 681 682 // Read check executed on probe sidecar, used to check workload's readonly access. 683 // +optional 684 Queries []string `json:"queries,omitempty"` 685 } 686 687 type ClusterDefinitionProbe struct { 688 // How often (in seconds) to perform the probe. 689 // +kubebuilder:default=1 690 // +kubebuilder:validation:Minimum=1 691 PeriodSeconds int32 `json:"periodSeconds,omitempty"` 692 693 // Number of seconds after which the probe times out. Defaults to 1 second. 694 // +kubebuilder:default=1 695 // +kubebuilder:validation:Minimum=1 696 TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"` 697 698 // Minimum consecutive failures for the probe to be considered failed after having succeeded. 699 // +kubebuilder:default=3 700 // +kubebuilder:validation:Minimum=2 701 FailureThreshold int32 `json:"failureThreshold,omitempty"` 702 703 // commands used to execute for probe. 704 // +optional 705 Commands *ClusterDefinitionProbeCMDs `json:"commands,omitempty"` 706 } 707 708 type ClusterDefinitionProbes struct { 709 // Probe for DB running check. 710 // +optional 711 RunningProbe *ClusterDefinitionProbe `json:"runningProbe,omitempty"` 712 713 // Probe for DB status check. 714 // +optional 715 StatusProbe *ClusterDefinitionProbe `json:"statusProbe,omitempty"` 716 717 // Probe for DB role changed check. 718 // +optional 719 //+kubebuilder:deprecatedversion:warning="This field is deprecated from KB 0.7.0, use RSMSpec instead." 720 RoleProbe *ClusterDefinitionProbe `json:"roleProbe,omitempty"` 721 722 // roleProbeTimeoutAfterPodsReady(in seconds), when all pods of the component are ready, 723 // it will detect whether the application is available in the pod. 724 // if pods exceed the InitializationTimeoutSeconds time without a role label, 725 // this component will enter the Failed/Abnormal phase. 726 // Note that this configuration will only take effect if the component supports RoleProbe 727 // and will not affect the life cycle of the pod. default values are 60 seconds. 728 // +optional 729 // +kubebuilder:validation:Minimum=30 730 RoleProbeTimeoutAfterPodsReady int32 `json:"roleProbeTimeoutAfterPodsReady,omitempty"` 731 } 732 733 type StatelessSetSpec struct { 734 // updateStrategy defines the underlying deployment strategy to use to replace existing pods with new ones. 735 // +optional 736 // +patchStrategy=retainKeys 737 UpdateStrategy appsv1.DeploymentStrategy `json:"updateStrategy,omitempty"` 738 } 739 740 type StatefulSetSpec struct { 741 // updateStrategy, Pods update strategy. 742 // In case of workloadType=Consensus the update strategy will be following: 743 // 744 // serial: update Pods one by one that guarantee minimum component unavailable time. 745 // Learner -> Follower(with AccessMode=none) -> Follower(with AccessMode=readonly) -> Follower(with AccessMode=readWrite) -> Leader 746 // bestEffortParallel: update Pods in parallel that guarantee minimum component un-writable time. 747 // Learner, Follower(minority) in parallel -> Follower(majority) -> Leader, keep majority online all the time. 748 // parallel: force parallel 749 // +kubebuilder:default=Serial 750 // +optional 751 UpdateStrategy UpdateStrategy `json:"updateStrategy,omitempty"` 752 753 // llPodManagementPolicy is the low-level controls how pods are created during initial scale up, 754 // when replacing pods on nodes, or when scaling down. 755 // `OrderedReady` policy specify where pods are created in increasing order (pod-0, then 756 // pod-1, etc) and the controller will wait until each pod is ready before 757 // continuing. When scaling down, the pods are removed in the opposite order. 758 // `Parallel` policy specify create pods in parallel 759 // to match the desired scale without waiting, and on scale down will delete 760 // all pods at once. 761 // +optional 762 LLPodManagementPolicy appsv1.PodManagementPolicyType `json:"llPodManagementPolicy,omitempty"` 763 764 // llUpdateStrategy indicates the low-level StatefulSetUpdateStrategy that will be 765 // employed to update Pods in the StatefulSet when a revision is made to 766 // Template. Will ignore `updateStrategy` attribute if provided. 767 // +optional 768 LLUpdateStrategy *appsv1.StatefulSetUpdateStrategy `json:"llUpdateStrategy,omitempty"` 769 } 770 771 var _ StatefulSetWorkload = &StatefulSetSpec{} 772 773 func (r *StatefulSetSpec) GetUpdateStrategy() UpdateStrategy { 774 if r == nil { 775 return SerialStrategy 776 } 777 return r.UpdateStrategy 778 } 779 780 func (r *StatefulSetSpec) FinalStsUpdateStrategy() (appsv1.PodManagementPolicyType, appsv1.StatefulSetUpdateStrategy) { 781 if r == nil { 782 r = &StatefulSetSpec{ 783 UpdateStrategy: SerialStrategy, 784 } 785 } 786 return r.finalStsUpdateStrategy() 787 } 788 789 func (r *StatefulSetSpec) finalStsUpdateStrategy() (appsv1.PodManagementPolicyType, appsv1.StatefulSetUpdateStrategy) { 790 if r.LLUpdateStrategy != nil { 791 return r.LLPodManagementPolicy, *r.LLUpdateStrategy 792 } 793 794 zeroPartition := int32(0) 795 switch r.UpdateStrategy { 796 case BestEffortParallelStrategy: 797 m := intstr.FromString("49%") 798 return appsv1.ParallelPodManagement, appsv1.StatefulSetUpdateStrategy{ 799 Type: appsv1.RollingUpdateStatefulSetStrategyType, 800 RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ 801 // explicitly set the partition as 0 to avoid update workload unexpectedly. 802 Partition: &zeroPartition, 803 // alpha feature since v1.24 804 // ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods 805 MaxUnavailable: &m, 806 }, 807 } 808 case ParallelStrategy: 809 return appsv1.ParallelPodManagement, appsv1.StatefulSetUpdateStrategy{ 810 Type: appsv1.RollingUpdateStatefulSetStrategyType, 811 } 812 case SerialStrategy: 813 fallthrough 814 default: 815 m := intstr.FromInt(1) 816 return appsv1.OrderedReadyPodManagement, appsv1.StatefulSetUpdateStrategy{ 817 Type: appsv1.RollingUpdateStatefulSetStrategyType, 818 RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ 819 // explicitly set the partition as 0 to avoid update workload unexpectedly. 820 Partition: &zeroPartition, 821 // alpha feature since v1.24 822 // ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#maximum-unavailable-pods 823 MaxUnavailable: &m, 824 }, 825 } 826 } 827 } 828 829 type ConsensusSetSpec struct { 830 StatefulSetSpec `json:",inline"` 831 832 // leader, one single leader. 833 // +kubebuilder:validation:Required 834 Leader ConsensusMember `json:"leader"` 835 836 // followers, has voting right but not Leader. 837 // +optional 838 Followers []ConsensusMember `json:"followers,omitempty"` 839 840 // learner, no voting right. 841 // +optional 842 Learner *ConsensusMember `json:"learner,omitempty"` 843 } 844 845 var _ StatefulSetWorkload = &ConsensusSetSpec{} 846 847 func (r *ConsensusSetSpec) GetUpdateStrategy() UpdateStrategy { 848 if r == nil { 849 return SerialStrategy 850 } 851 return r.UpdateStrategy 852 } 853 854 func (r *ConsensusSetSpec) FinalStsUpdateStrategy() (appsv1.PodManagementPolicyType, appsv1.StatefulSetUpdateStrategy) { 855 if r == nil { 856 r = NewConsensusSetSpec() 857 } 858 if r.LLUpdateStrategy != nil { 859 return r.LLPodManagementPolicy, *r.LLUpdateStrategy 860 } 861 _, s := r.StatefulSetSpec.finalStsUpdateStrategy() 862 // switch r.UpdateStrategy { 863 // case SerialStrategy, BestEffortParallelStrategy: 864 s.Type = appsv1.OnDeleteStatefulSetStrategyType 865 s.RollingUpdate = nil 866 // } 867 return appsv1.ParallelPodManagement, s 868 } 869 870 func NewConsensusSetSpec() *ConsensusSetSpec { 871 return &ConsensusSetSpec{ 872 Leader: DefaultLeader, 873 StatefulSetSpec: StatefulSetSpec{ 874 UpdateStrategy: SerialStrategy, 875 }, 876 } 877 } 878 879 type ConsensusMember struct { 880 // name, role name. 881 // +kubebuilder:validation:Required 882 // +kubebuilder:default=leader 883 Name string `json:"name"` 884 885 // accessMode, what service this member capable. 886 // +kubebuilder:validation:Required 887 // +kubebuilder:default=ReadWrite 888 AccessMode AccessMode `json:"accessMode"` 889 890 // replicas, number of Pods of this role. 891 // default 1 for Leader 892 // default 0 for Learner 893 // default Cluster.spec.componentSpec[*].Replicas - Leader.Replicas - Learner.Replicas for Followers 894 // +kubebuilder:default=0 895 // +kubebuilder:validation:Minimum=0 896 // +optional 897 Replicas *int32 `json:"replicas,omitempty"` 898 } 899 900 type RSMSpec struct { 901 // Roles, a list of roles defined in the system. 902 // +optional 903 Roles []workloads.ReplicaRole `json:"roles,omitempty"` 904 905 // RoleProbe provides method to probe role. 906 // +optional 907 RoleProbe *workloads.RoleProbe `json:"roleProbe,omitempty"` 908 909 // MembershipReconfiguration provides actions to do membership dynamic reconfiguration. 910 // +optional 911 MembershipReconfiguration *workloads.MembershipReconfiguration `json:"membershipReconfiguration,omitempty"` 912 913 // MemberUpdateStrategy, Members(Pods) update strategy. 914 // serial: update Members one by one that guarantee minimum component unavailable time. 915 // Learner -> Follower(with AccessMode=none) -> Follower(with AccessMode=readonly) -> Follower(with AccessMode=readWrite) -> Leader 916 // bestEffortParallel: update Members in parallel that guarantee minimum component un-writable time. 917 // Learner, Follower(minority) in parallel -> Follower(majority) -> Leader, keep majority online all the time. 918 // parallel: force parallel 919 // +kubebuilder:validation:Enum={Serial,BestEffortParallel,Parallel} 920 // +optional 921 MemberUpdateStrategy *workloads.MemberUpdateStrategy `json:"memberUpdateStrategy,omitempty"` 922 } 923 924 type ReplicationSetSpec struct { 925 StatefulSetSpec `json:",inline"` 926 } 927 928 var _ StatefulSetWorkload = &ReplicationSetSpec{} 929 930 func (r *ReplicationSetSpec) GetUpdateStrategy() UpdateStrategy { 931 if r == nil { 932 return SerialStrategy 933 } 934 return r.UpdateStrategy 935 } 936 937 func (r *ReplicationSetSpec) FinalStsUpdateStrategy() (appsv1.PodManagementPolicyType, appsv1.StatefulSetUpdateStrategy) { 938 if r == nil { 939 r = &ReplicationSetSpec{} 940 } 941 if r.LLUpdateStrategy != nil { 942 return r.LLPodManagementPolicy, *r.LLUpdateStrategy 943 } 944 _, s := r.StatefulSetSpec.finalStsUpdateStrategy() 945 s.Type = appsv1.OnDeleteStatefulSetStrategyType 946 s.RollingUpdate = nil 947 return appsv1.ParallelPodManagement, s 948 } 949 950 type SwitchoverSpec struct { 951 // withCandidate corresponds to the switchover of the specified candidate primary or leader instance. 952 // +optional 953 WithCandidate *SwitchoverAction `json:"withCandidate,omitempty"` 954 955 // withoutCandidate corresponds to a switchover that does not specify a candidate primary or leader instance. 956 // +optional 957 WithoutCandidate *SwitchoverAction `json:"withoutCandidate,omitempty"` 958 } 959 960 type SwitchoverAction struct { 961 // cmdExecutorConfig is the executor configuration of the switchover command. 962 // +kubebuilder:validation:Required 963 CmdExecutorConfig *CmdExecutorConfig `json:"cmdExecutorConfig"` 964 965 // scriptSpecSelectors defines the selector of the scriptSpecs that need to be referenced. 966 // Once ScriptSpecSelectors is defined, the scripts defined in scriptSpecs can be referenced in the SwitchoverAction.CmdExecutorConfig. 967 // +optional 968 ScriptSpecSelectors []ScriptSpecSelector `json:"scriptSpecSelectors,omitempty"` 969 } 970 971 type ScriptSpecSelector struct { 972 // ScriptSpec name of the referent, refer to componentDefs[x].scriptSpecs[y].Name. 973 // +kubebuilder:validation:Required 974 // +kubebuilder:validation:MaxLength=63 975 // +kubebuilder:validation:Pattern:=`^[a-z0-9]([a-z0-9\.\-]*[a-z0-9])?$` 976 Name string `json:"name"` 977 } 978 979 type CommandExecutorEnvItem struct { 980 // image for Connector when executing the command. 981 // +kubebuilder:validation:Required 982 Image string `json:"image"` 983 // envs is a list of environment variables. 984 // +kubebuilder:pruning:PreserveUnknownFields 985 // +patchMergeKey=name 986 // +patchStrategy=merge,retainKeys 987 // +optional 988 Env []corev1.EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name"` 989 } 990 991 type CommandExecutorItem struct { 992 // command to perform statements. 993 // +kubebuilder:validation:Required 994 // +kubebuilder:validation:MinItems=1 995 Command []string `json:"command"` 996 // args is used to perform statements. 997 // +optional 998 Args []string `json:"args,omitempty"` 999 } 1000 1001 type CustomLabelSpec struct { 1002 // key name of label 1003 // +kubebuilder:validation:Required 1004 Key string `json:"key"` 1005 1006 // value of label 1007 // +kubebuilder:validation:Required 1008 Value string `json:"value"` 1009 1010 // resources defines the resources to be labeled. 1011 // +kubebuilder:validation:Required 1012 Resources []GVKResource `json:"resources,omitempty"` 1013 } 1014 1015 type GVKResource struct { 1016 // gvk is Group/Version/Kind, for example "v1/Pod", "apps/v1/StatefulSet", etc. 1017 // when the gvk resource filtered by the selector already exists, if there is no corresponding custom label, it will be added, and if label already exists, it will be updated. 1018 // +kubebuilder:validation:Required 1019 GVK string `json:"gvk"` 1020 1021 // selector is a label query over a set of resources. 1022 // +optional 1023 Selector map[string]string `json:"selector,omitempty"` 1024 } 1025 1026 // +genclient 1027 // +genclient:nonNamespaced 1028 // +k8s:openapi-gen=true 1029 // +kubebuilder:object:root=true 1030 // +kubebuilder:subresource:status 1031 // +kubebuilder:resource:categories={kubeblocks},scope=Cluster,shortName=cd 1032 // +kubebuilder:printcolumn:name="MAIN-COMPONENT-NAME",type="string",JSONPath=".spec.componentDefs[0].name",description="main component names" 1033 // +kubebuilder:printcolumn:name="STATUS",type="string",JSONPath=".status.phase",description="status phase" 1034 // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" 1035 1036 // ClusterDefinition is the Schema for the clusterdefinitions API 1037 type ClusterDefinition struct { 1038 metav1.TypeMeta `json:",inline"` 1039 metav1.ObjectMeta `json:"metadata,omitempty"` 1040 1041 Spec ClusterDefinitionSpec `json:"spec,omitempty"` 1042 Status ClusterDefinitionStatus `json:"status,omitempty"` 1043 } 1044 1045 // +kubebuilder:object:root=true 1046 1047 // ClusterDefinitionList contains a list of ClusterDefinition 1048 type ClusterDefinitionList struct { 1049 metav1.TypeMeta `json:",inline"` 1050 metav1.ListMeta `json:"metadata,omitempty"` 1051 Items []ClusterDefinition `json:"items"` 1052 } 1053 1054 func init() { 1055 SchemeBuilder.Register(&ClusterDefinition{}, &ClusterDefinitionList{}) 1056 } 1057 1058 // ValidateEnabledLogConfigs validates enabledLogs against component compDefName, and returns the invalid logNames undefined in ClusterDefinition. 1059 func (r *ClusterDefinition) ValidateEnabledLogConfigs(compDefName string, enabledLogs []string) []string { 1060 invalidLogNames := make([]string, 0, len(enabledLogs)) 1061 logTypes := make(map[string]struct{}) 1062 for _, comp := range r.Spec.ComponentDefs { 1063 if !strings.EqualFold(compDefName, comp.Name) { 1064 continue 1065 } 1066 for _, logConfig := range comp.LogConfigs { 1067 logTypes[logConfig.Name] = struct{}{} 1068 } 1069 } 1070 // imply that all values in enabledLogs config are invalid. 1071 if len(logTypes) == 0 { 1072 return enabledLogs 1073 } 1074 for _, name := range enabledLogs { 1075 if _, ok := logTypes[name]; !ok { 1076 invalidLogNames = append(invalidLogNames, name) 1077 } 1078 } 1079 return invalidLogNames 1080 } 1081 1082 // GetComponentDefByName gets component definition from ClusterDefinition with compDefName 1083 func (r *ClusterDefinition) GetComponentDefByName(compDefName string) *ClusterComponentDefinition { 1084 for _, component := range r.Spec.ComponentDefs { 1085 if component.Name == compDefName { 1086 return &component 1087 } 1088 } 1089 return nil 1090 } 1091 1092 // FailurePolicyType specifies the type of failure policy 1093 // +enum 1094 // +kubebuilder:validation:Enum={Ignore,Fail} 1095 type FailurePolicyType string 1096 1097 const ( 1098 // Ignore means that an error will be ignored but logged. 1099 FailurePolicyIgnore FailurePolicyType = "Ignore" 1100 // ReportError means that an error will be reported. 1101 FailurePolicyFail FailurePolicyType = "Fail" 1102 ) 1103 1104 // ComponentValueFromType specifies the type of component value from. 1105 // +enum 1106 // +kubebuilder:validation:Enum={FieldRef,ServiceRef,HeadlessServiceRef} 1107 type ComponentValueFromType string 1108 1109 const ( 1110 FromFieldRef ComponentValueFromType = "FieldRef" 1111 FromServiceRef ComponentValueFromType = "ServiceRef" 1112 FromHeadlessServiceRef ComponentValueFromType = "HeadlessServiceRef" 1113 ) 1114 1115 // ComponentDefRef is used to select the component and its fields to be referenced. 1116 type ComponentDefRef struct { 1117 // componentDefName is the name of the componentDef to select. 1118 // +kubebuilder:validation:Required 1119 ComponentDefName string `json:"componentDefName"` 1120 // failurePolicy is the failure policy of the component. 1121 // If failed to find the component, the failure policy will be used. 1122 // +kubebuilder:validation:Enum={Ignore,Fail} 1123 // +default="Ignore" 1124 // +optional 1125 FailurePolicy FailurePolicyType `json:"failurePolicy,omitempty"` 1126 // componentRefEnv specifies a list of values to be injected as env variables to each component. 1127 // +kbubebuilder:validation:Required 1128 // +patchMergeKey=name 1129 // +patchStrategy=merge,retainKeys 1130 // +listType=map 1131 // +listMapKey=name 1132 // +optional 1133 ComponentRefEnvs []ComponentRefEnv `json:"componentRefEnv" patchStrategy:"merge" patchMergeKey:"name"` 1134 } 1135 1136 // ComponentRefEnv specifies name and value of an env. 1137 type ComponentRefEnv struct { 1138 // name is the name of the env to be injected, and it must be a C identifier. 1139 // +kubebuilder:validation:Required 1140 // +kubebuilder:validation:Pattern=`^[A-Za-z_][A-Za-z0-9_]*$` 1141 Name string `json:"name"` 1142 // value is the value of the env to be injected. 1143 // +optional 1144 Value string `json:"value,omitempty"` 1145 // valueFrom specifies the source of the env to be injected. 1146 // +optional 1147 ValueFrom *ComponentValueFrom `json:"valueFrom,omitempty"` 1148 } 1149 1150 type ComponentValueFrom struct { 1151 // type is the type of the source to select. There are three types: `FieldRef`, `ServiceRef`, `HeadlessServiceRef`. 1152 // +kubebuilder:validation:Enum={FieldRef,ServiceRef,HeadlessServiceRef} 1153 // +kubebuilder:validation:Required 1154 Type ComponentValueFromType `json:"type"` 1155 // fieldRef is the jsonpath of the source to select when type is `FieldRef`. 1156 // there are two objects registered in the jsonpath: `componentDef` and `components`. 1157 // componentDef is the component definition object specified in `componentRef.componentDefName`. 1158 // components is the component list objects referring to the component definition object. 1159 // +optional 1160 FieldPath string `json:"fieldPath,omitempty"` 1161 // format is the format of each headless service address. 1162 // there are three builtin variables can be used as placeholder: $POD_ORDINAL, $POD_FQDN, $POD_NAME 1163 // $POD_ORDINAL is the ordinal of the pod. 1164 // $POD_FQDN is the fully qualified domain name of the pod. 1165 // $POD_NAME is the name of the pod 1166 // +optional 1167 // +kubebuilder:default=="$POD_FQDN" 1168 Format string `json:"format,omitempty"` 1169 // joinWith is the string to join the values of headless service addresses. 1170 // +optional 1171 // +kubebuilder:default="," 1172 JoinWith string `json:"joinWith,omitempty"` 1173 }