github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/cli/testing/fake.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package testing 21 22 import ( 23 "fmt" 24 "time" 25 26 chaosmeshv1alpha1 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1" 27 snapshotv1 "github.com/kubernetes-csi/external-snapshotter/client/v6/apis/volumesnapshot/v1" 28 "github.com/sethvargo/go-password/password" 29 appsv1 "k8s.io/api/apps/v1" 30 batchv1 "k8s.io/api/batch/v1" 31 corev1 "k8s.io/api/core/v1" 32 rbacv1 "k8s.io/api/rbac/v1" 33 storagev1 "k8s.io/api/storage/v1" 34 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 35 "k8s.io/apimachinery/pkg/api/resource" 36 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 37 "k8s.io/apimachinery/pkg/runtime/schema" 38 "k8s.io/kubectl/pkg/util/storage" 39 "k8s.io/utils/pointer" 40 41 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 42 dpv1alpha1 "github.com/1aal/kubeblocks/apis/dataprotection/v1alpha1" 43 extensionsv1alpha1 "github.com/1aal/kubeblocks/apis/extensions/v1alpha1" 44 storagev1alpha1 "github.com/1aal/kubeblocks/apis/storage/v1alpha1" 45 "github.com/1aal/kubeblocks/pkg/cli/types" 46 "github.com/1aal/kubeblocks/pkg/constant" 47 dptypes "github.com/1aal/kubeblocks/pkg/dataprotection/types" 48 "github.com/1aal/kubeblocks/pkg/dataprotection/utils/boolptr" 49 testapps "github.com/1aal/kubeblocks/pkg/testutil/apps" 50 ) 51 52 const ( 53 ClusterName = "fake-cluster-name" 54 Namespace = "fake-namespace" 55 ClusterVersionName = "fake-cluster-version" 56 ClusterDefName = "fake-cluster-definition" 57 ComponentName = "fake-component-name" 58 ComponentDefName = "fake-component-type" 59 NodeName = "fake-node-name" 60 SecretName = "fake-secret-conn-credential" 61 StorageClassName = "fake-storage-class" 62 PVCName = "fake-pvc" 63 ServiceRefName = "fake-serviceRef" 64 65 KubeBlocksRepoName = "fake-kubeblocks-repo" 66 KubeBlocksChartName = "fake-kubeblocks" 67 KubeBlocksChartURL = "fake-kubeblocks-chart-url" 68 BackupMethodName = "fake-backup-method" 69 ActionSetName = "fake-action-set" 70 BackupName = "fake-backup-name" 71 72 IsDefault = true 73 IsNotDefault = false 74 ) 75 76 var ( 77 ExtraComponentDefName = fmt.Sprintf("%s-%d", ComponentDefName, 1) 78 ) 79 80 func GetRandomStr() string { 81 seq, _ := password.Generate(6, 2, 0, true, true) 82 return seq 83 } 84 85 func FakeCluster(name, namespace string, conditions ...metav1.Condition) *appsv1alpha1.Cluster { 86 var replicas int32 = 1 87 88 return &appsv1alpha1.Cluster{ 89 TypeMeta: metav1.TypeMeta{ 90 Kind: types.KindCluster, 91 APIVersion: fmt.Sprintf("%s/%s", types.AppsAPIGroup, types.AppsAPIVersion), 92 }, 93 ObjectMeta: metav1.ObjectMeta{ 94 Name: name, 95 Namespace: namespace, 96 UID: "b262b889-a27f-42d8-b066-2978561c8167", 97 }, 98 Status: appsv1alpha1.ClusterStatus{ 99 Phase: appsv1alpha1.RunningClusterPhase, 100 Components: map[string]appsv1alpha1.ClusterComponentStatus{ 101 ComponentName: { 102 ConsensusSetStatus: &appsv1alpha1.ConsensusSetStatus{ 103 Leader: appsv1alpha1.ConsensusMemberStatus{ 104 Name: "leader", 105 AccessMode: appsv1alpha1.ReadWrite, 106 Pod: fmt.Sprintf("%s-pod-0", name), 107 }, 108 }, 109 }, 110 }, 111 Conditions: conditions, 112 }, 113 Spec: appsv1alpha1.ClusterSpec{ 114 ClusterDefRef: ClusterDefName, 115 ClusterVersionRef: ClusterVersionName, 116 TerminationPolicy: appsv1alpha1.WipeOut, 117 ComponentSpecs: []appsv1alpha1.ClusterComponentSpec{ 118 { 119 Name: ComponentName, 120 ComponentDefRef: ComponentDefName, 121 Replicas: replicas, 122 Resources: corev1.ResourceRequirements{ 123 Requests: corev1.ResourceList{ 124 corev1.ResourceCPU: resource.MustParse("100m"), 125 corev1.ResourceMemory: resource.MustParse("100Mi"), 126 }, 127 Limits: corev1.ResourceList{ 128 corev1.ResourceCPU: resource.MustParse("200m"), 129 corev1.ResourceMemory: resource.MustParse("2Gi"), 130 }, 131 }, 132 VolumeClaimTemplates: []appsv1alpha1.ClusterComponentVolumeClaimTemplate{ 133 { 134 Name: "data", 135 Spec: appsv1alpha1.PersistentVolumeClaimSpec{ 136 AccessModes: []corev1.PersistentVolumeAccessMode{ 137 corev1.ReadWriteOnce, 138 }, 139 Resources: corev1.ResourceRequirements{ 140 Requests: corev1.ResourceList{ 141 corev1.ResourceStorage: resource.MustParse("1Gi"), 142 }, 143 }, 144 }, 145 }, 146 }, 147 }, 148 { 149 Name: ComponentName + "-1", 150 ComponentDefRef: ComponentDefName, 151 Replicas: replicas, 152 Resources: corev1.ResourceRequirements{ 153 Requests: corev1.ResourceList{ 154 corev1.ResourceCPU: resource.MustParse("100m"), 155 corev1.ResourceMemory: resource.MustParse("100Mi"), 156 }, 157 }, 158 VolumeClaimTemplates: []appsv1alpha1.ClusterComponentVolumeClaimTemplate{ 159 { 160 Name: "data", 161 Spec: appsv1alpha1.PersistentVolumeClaimSpec{ 162 AccessModes: []corev1.PersistentVolumeAccessMode{ 163 corev1.ReadWriteOnce, 164 }, 165 Resources: corev1.ResourceRequirements{ 166 Requests: corev1.ResourceList{ 167 corev1.ResourceStorage: resource.MustParse("1Gi"), 168 }, 169 }, 170 }, 171 }, 172 }, 173 }, 174 }, 175 }, 176 } 177 } 178 179 func FakePods(replicas int, namespace string, cluster string) *corev1.PodList { 180 pods := &corev1.PodList{} 181 for i := 0; i < replicas; i++ { 182 role := "follower" 183 pod := corev1.Pod{} 184 pod.Name = fmt.Sprintf("%s-pod-%d", cluster, i) 185 pod.Namespace = namespace 186 187 if i == 0 { 188 role = "leader" 189 } 190 191 pod.Labels = map[string]string{ 192 constant.AppInstanceLabelKey: cluster, 193 constant.RoleLabelKey: role, 194 constant.KBAppComponentLabelKey: ComponentName, 195 constant.AppNameLabelKey: "mysql-apecloud-mysql", 196 constant.AppManagedByLabelKey: constant.AppName, 197 } 198 pod.Spec.NodeName = NodeName 199 pod.Spec.Containers = []corev1.Container{ 200 { 201 Name: "fake-container", 202 Image: "fake-container-image", 203 }, 204 } 205 pod.Status.Phase = corev1.PodRunning 206 pods.Items = append(pods.Items, pod) 207 } 208 return pods 209 } 210 211 // FakeSecret for test cluster create 212 func FakeSecret(namespace string, cluster string) *corev1.Secret { 213 secret := corev1.Secret{} 214 secret.Name = SecretName 215 secret.Namespace = namespace 216 secret.Type = corev1.SecretTypeServiceAccountToken 217 secret.Labels = map[string]string{ 218 constant.AppInstanceLabelKey: cluster, 219 "name": types.KubeBlocksChartName, 220 "owner": "helm", 221 } 222 223 secret.Data = map[string][]byte{ 224 corev1.ServiceAccountTokenKey: []byte("fake-secret-token"), 225 "fake-secret-key": []byte("fake-secret-value"), 226 "username": []byte("test-user"), 227 "password": []byte("test-password"), 228 } 229 return &secret 230 } 231 232 func FakeSecrets(namespace string, cluster string) *corev1.SecretList { 233 secret := corev1.Secret{} 234 secret.Name = SecretName 235 secret.Namespace = namespace 236 secret.Type = corev1.SecretTypeServiceAccountToken 237 secret.Labels = map[string]string{ 238 constant.AppInstanceLabelKey: cluster, 239 constant.AppManagedByLabelKey: constant.AppName, 240 } 241 242 secret.Data = map[string][]byte{ 243 corev1.ServiceAccountTokenKey: []byte("fake-secret-token"), 244 "fake-secret-key": []byte("fake-secret-value"), 245 "username": []byte("test-user"), 246 "password": []byte("test-password"), 247 } 248 return &corev1.SecretList{Items: []corev1.Secret{secret}} 249 } 250 251 func FakeSecretsWithLabels(namespace string, labels map[string]string) *corev1.SecretList { 252 secret := corev1.Secret{} 253 secret.Name = GetRandomStr() 254 secret.Namespace = namespace 255 secret.Labels = labels 256 secret.Data = map[string][]byte{ 257 "username": []byte("test-user"), 258 "password": []byte("test-password"), 259 } 260 return &corev1.SecretList{Items: []corev1.Secret{secret}} 261 } 262 263 func FakeNode() *corev1.Node { 264 node := &corev1.Node{} 265 node.Name = NodeName 266 node.Labels = map[string]string{ 267 constant.RegionLabelKey: "fake-node-region", 268 constant.ZoneLabelKey: "fake-node-zone", 269 } 270 return node 271 } 272 273 func FakeClusterDef() *appsv1alpha1.ClusterDefinition { 274 clusterDef := &appsv1alpha1.ClusterDefinition{} 275 clusterDef.Name = ClusterDefName 276 clusterDef.Spec.ComponentDefs = []appsv1alpha1.ClusterComponentDefinition{ 277 { 278 Name: ComponentDefName, 279 CharacterType: "mysql", 280 SystemAccounts: &appsv1alpha1.SystemAccountSpec{ 281 CmdExecutorConfig: &appsv1alpha1.CmdExecutorConfig{ 282 CommandExecutorEnvItem: appsv1alpha1.CommandExecutorEnvItem{ 283 Image: "", 284 }, 285 CommandExecutorItem: appsv1alpha1.CommandExecutorItem{ 286 Command: []string{"mysql"}, 287 Args: []string{"-h$(KB_ACCOUNT_ENDPOINT)", "-e $(KB_ACCOUNT_STATEMENT)"}, 288 }, 289 }, 290 PasswordConfig: appsv1alpha1.PasswordConfig{}, 291 Accounts: []appsv1alpha1.SystemAccountConfig{}, 292 }, 293 ConfigSpecs: []appsv1alpha1.ComponentConfigSpec{ 294 { 295 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 296 Name: "mysql-consensusset-config", 297 TemplateRef: "mysql8.0-config-template", 298 Namespace: Namespace, 299 VolumeName: "mysql-config", 300 }, 301 ConfigConstraintRef: "mysql8.0-config-constraints", 302 }, 303 }, 304 ServiceRefDeclarations: []appsv1alpha1.ServiceRefDeclaration{ 305 FakeServiceRef(ServiceRefName), 306 }, 307 }, 308 { 309 Name: ExtraComponentDefName, 310 CharacterType: "mysql", 311 ConfigSpecs: []appsv1alpha1.ComponentConfigSpec{ 312 { 313 ComponentTemplateSpec: appsv1alpha1.ComponentTemplateSpec{ 314 Name: "mysql-consensusset-config", 315 TemplateRef: "mysql8.0-config-template", 316 Namespace: Namespace, 317 VolumeName: "mysql-config", 318 }, 319 ConfigConstraintRef: "mysql8.0-config-constraints", 320 }, 321 }, 322 SwitchoverSpec: &appsv1alpha1.SwitchoverSpec{ 323 WithCandidate: &appsv1alpha1.SwitchoverAction{ 324 CmdExecutorConfig: &appsv1alpha1.CmdExecutorConfig{ 325 CommandExecutorEnvItem: appsv1alpha1.CommandExecutorEnvItem{ 326 Image: "", 327 }, 328 CommandExecutorItem: appsv1alpha1.CommandExecutorItem{ 329 Command: []string{"mysql"}, 330 Args: []string{"-h$(KB_CONSENSUS_LEADER_POD_FQDN)", "-e $(KB_SWITCHOVER_ACTION)"}, 331 }, 332 }, 333 }, 334 }, 335 }, 336 } 337 return clusterDef 338 } 339 340 func FakeComponentClassDef(name string, clusterDefRef string, componentDefRef string) *appsv1alpha1.ComponentClassDefinition { 341 testapps.NewComponentResourceConstraintFactory(testapps.DefaultResourceConstraintName). 342 AddConstraints(testapps.GeneralResourceConstraint). 343 GetObject() 344 345 componentClassDefinition := testapps.NewComponentClassDefinitionFactory(name, clusterDefRef, componentDefRef). 346 AddClasses([]appsv1alpha1.ComponentClass{testapps.Class1c1g, testapps.Class2c4g}). 347 GetObject() 348 349 return componentClassDefinition 350 } 351 352 func FakeClusterVersion() *appsv1alpha1.ClusterVersion { 353 cv := &appsv1alpha1.ClusterVersion{} 354 gvr := types.ClusterVersionGVR() 355 cv.TypeMeta.APIVersion = gvr.GroupVersion().String() 356 cv.TypeMeta.Kind = types.KindClusterVersion 357 cv.Name = ClusterVersionName 358 cv.SetLabels(map[string]string{ 359 constant.ClusterDefLabelKey: ClusterDefName, 360 constant.AppManagedByLabelKey: constant.AppName, 361 }) 362 cv.Spec.ClusterDefinitionRef = ClusterDefName 363 cv.SetCreationTimestamp(metav1.Now()) 364 return cv 365 } 366 367 func FakeActionSet() *dpv1alpha1.ActionSet { 368 as := &dpv1alpha1.ActionSet{} 369 as.Name = ActionSetName 370 return as 371 } 372 373 func FakeBackupPolicy(backupPolicyName, clusterName string) *dpv1alpha1.BackupPolicy { 374 template := &dpv1alpha1.BackupPolicy{ 375 TypeMeta: metav1.TypeMeta{ 376 APIVersion: fmt.Sprintf("%s/%s", types.DPAPIGroup, types.DPAPIVersion), 377 Kind: types.KindBackupPolicy, 378 }, 379 ObjectMeta: metav1.ObjectMeta{ 380 Name: backupPolicyName, 381 Namespace: Namespace, 382 Labels: map[string]string{ 383 constant.AppInstanceLabelKey: clusterName, 384 }, 385 Annotations: map[string]string{ 386 dptypes.DefaultBackupPolicyAnnotationKey: "true", 387 }, 388 }, 389 Spec: dpv1alpha1.BackupPolicySpec{ 390 BackupMethods: []dpv1alpha1.BackupMethod{ 391 { 392 Name: BackupMethodName, 393 SnapshotVolumes: boolptr.False(), 394 ActionSetName: ActionSetName, 395 }, 396 }, 397 Target: &dpv1alpha1.BackupTarget{ 398 PodSelector: &dpv1alpha1.PodSelector{ 399 LabelSelector: &metav1.LabelSelector{ 400 MatchLabels: map[string]string{ 401 constant.AppInstanceLabelKey: ClusterName, 402 constant.KBAppComponentLabelKey: ComponentName, 403 constant.AppManagedByLabelKey: constant.AppName}, 404 }, 405 }, 406 }, 407 }, 408 Status: dpv1alpha1.BackupPolicyStatus{ 409 Phase: dpv1alpha1.AvailablePhase, 410 }, 411 } 412 return template 413 } 414 415 func FakeBackup(backupName string) *dpv1alpha1.Backup { 416 backup := &dpv1alpha1.Backup{ 417 TypeMeta: metav1.TypeMeta{ 418 APIVersion: fmt.Sprintf("%s/%s", types.DPAPIGroup, types.DPAPIVersion), 419 Kind: types.KindBackup, 420 }, 421 ObjectMeta: metav1.ObjectMeta{ 422 Name: backupName, 423 Namespace: Namespace, 424 }, 425 } 426 backup.SetCreationTimestamp(metav1.Now()) 427 return backup 428 } 429 430 func FakeBackupSchedule(backupScheduleName, backupPolicyName string) *dpv1alpha1.BackupSchedule { 431 backupSchedule := &dpv1alpha1.BackupSchedule{ 432 TypeMeta: metav1.TypeMeta{ 433 APIVersion: fmt.Sprintf("%s/%s", types.DPAPIGroup, types.DPAPIVersion), 434 Kind: types.KindBackupSchedule, 435 }, 436 ObjectMeta: metav1.ObjectMeta{ 437 Name: backupScheduleName, 438 Namespace: Namespace, 439 Labels: map[string]string{ 440 constant.AppInstanceLabelKey: ClusterName, 441 }, 442 }, 443 Spec: dpv1alpha1.BackupScheduleSpec{ 444 BackupPolicyName: backupPolicyName, 445 Schedules: []dpv1alpha1.SchedulePolicy{ 446 { 447 Enabled: boolptr.True(), 448 CronExpression: "0 0 * * *", 449 BackupMethod: BackupMethodName, 450 RetentionPeriod: dpv1alpha1.RetentionPeriod("1d"), 451 }, 452 }, 453 }, 454 Status: dpv1alpha1.BackupScheduleStatus{ 455 Phase: dpv1alpha1.BackupSchedulePhaseAvailable, 456 }, 457 } 458 return backupSchedule 459 } 460 461 func FakeBackupPolicyTemplate(backupPolicyTemplateName string, clusterDef string) *appsv1alpha1.BackupPolicyTemplate { 462 backupPolicyTemplate := &appsv1alpha1.BackupPolicyTemplate{ 463 TypeMeta: metav1.TypeMeta{ 464 APIVersion: fmt.Sprintf("%s/%s", types.AppsAPIGroup, types.AppsAPIVersion), 465 Kind: types.KindBackupPolicyTemplate, 466 }, 467 ObjectMeta: metav1.ObjectMeta{ 468 Name: backupPolicyTemplateName, 469 Namespace: Namespace, 470 Labels: map[string]string{ 471 constant.ClusterDefLabelKey: ClusterDefName, 472 }, 473 }, 474 Spec: appsv1alpha1.BackupPolicyTemplateSpec{ 475 ClusterDefRef: clusterDef, 476 Identifier: "fake-identifier", 477 }, 478 } 479 return backupPolicyTemplate 480 } 481 482 func FakeBackupWithCluster(cluster *appsv1alpha1.Cluster, backupName string) *dpv1alpha1.Backup { 483 backup := &dpv1alpha1.Backup{ 484 TypeMeta: metav1.TypeMeta{ 485 APIVersion: fmt.Sprintf("%s/%s", types.DPAPIGroup, types.DPAPIVersion), 486 Kind: types.KindBackup, 487 }, 488 ObjectMeta: metav1.ObjectMeta{ 489 Name: backupName, 490 Namespace: Namespace, 491 Labels: map[string]string{ 492 constant.AppInstanceLabelKey: cluster.Name, 493 dptypes.ClusterUIDLabelKey: string(cluster.UID), 494 }, 495 }, 496 } 497 backup.SetCreationTimestamp(metav1.Now()) 498 return backup 499 } 500 501 func FakeServices() *corev1.ServiceList { 502 cases := []struct { 503 exposed bool 504 clusterIP string 505 floatingIP string 506 }{ 507 {false, "", ""}, 508 {false, "192.168.0.1", ""}, 509 {true, "192.168.0.1", ""}, 510 {true, "192.168.0.1", "172.31.0.4"}, 511 } 512 513 var services []corev1.Service 514 for idx, item := range cases { 515 svc := corev1.Service{ 516 ObjectMeta: metav1.ObjectMeta{ 517 Name: fmt.Sprintf("svc-%d", idx), 518 Namespace: Namespace, 519 Labels: map[string]string{ 520 constant.AppInstanceLabelKey: ClusterName, 521 constant.KBAppComponentLabelKey: ComponentName, 522 constant.AppManagedByLabelKey: constant.AppName, 523 }, 524 }, 525 Spec: corev1.ServiceSpec{ 526 Type: corev1.ServiceTypeClusterIP, 527 Ports: []corev1.ServicePort{{Port: 3306}}, 528 }, 529 } 530 531 if item.clusterIP == "" { 532 svc.Spec.ClusterIP = "None" 533 } else { 534 svc.Spec.ClusterIP = item.clusterIP 535 } 536 537 annotations := make(map[string]string) 538 if item.floatingIP != "" { 539 annotations[types.ServiceFloatingIPAnnotationKey] = item.floatingIP 540 } 541 if item.exposed { 542 annotations[types.ServiceHAVIPTypeAnnotationKey] = types.ServiceHAVIPTypeAnnotationValue 543 } 544 svc.ObjectMeta.SetAnnotations(annotations) 545 546 services = append(services, svc) 547 } 548 return &corev1.ServiceList{Items: services} 549 } 550 551 func FakePVCs() *corev1.PersistentVolumeClaimList { 552 pvcs := &corev1.PersistentVolumeClaimList{} 553 pvc := corev1.PersistentVolumeClaim{ 554 ObjectMeta: metav1.ObjectMeta{ 555 Namespace: Namespace, 556 Name: PVCName, 557 Labels: map[string]string{ 558 constant.AppInstanceLabelKey: ClusterName, 559 constant.KBAppComponentLabelKey: ComponentName, 560 constant.AppManagedByLabelKey: constant.AppName, 561 }, 562 }, 563 Spec: corev1.PersistentVolumeClaimSpec{ 564 StorageClassName: pointer.String(StorageClassName), 565 AccessModes: []corev1.PersistentVolumeAccessMode{"ReadWriteOnce"}, 566 Resources: corev1.ResourceRequirements{ 567 Requests: corev1.ResourceList{ 568 corev1.ResourceStorage: resource.MustParse("1Gi"), 569 }, 570 }, 571 }, 572 } 573 pvcs.Items = append(pvcs.Items, pvc) 574 return pvcs 575 } 576 577 func FakeEvents() *corev1.EventList { 578 eventList := &corev1.EventList{} 579 fakeEvent := func(name string, createTime metav1.Time) corev1.Event { 580 e := corev1.Event{} 581 e.Name = name 582 e.Type = "Warning" 583 e.SetCreationTimestamp(createTime) 584 e.LastTimestamp = createTime 585 return e 586 } 587 588 parseTime := func(t string) time.Time { 589 time, _ := time.Parse(time.RFC3339, t) 590 return time 591 } 592 593 for _, e := range []struct { 594 name string 595 createTime metav1.Time 596 }{ 597 { 598 name: "e1", 599 createTime: metav1.NewTime(parseTime("2023-01-04T00:00:00.000Z")), 600 }, 601 { 602 name: "e2", 603 createTime: metav1.NewTime(parseTime("2023-01-04T01:00:00.000Z")), 604 }, 605 } { 606 eventList.Items = append(eventList.Items, fakeEvent(e.name, e.createTime)) 607 } 608 return eventList 609 } 610 611 func FakeVolumeSnapshotClass() *snapshotv1.VolumeSnapshotClass { 612 return &snapshotv1.VolumeSnapshotClass{ 613 TypeMeta: metav1.TypeMeta{ 614 Kind: "VolumeSnapshotClass", 615 APIVersion: "snapshot.storage.k8s.io/v1", 616 }, 617 } 618 } 619 620 func FakeKBDeploy(version string) *appsv1.Deployment { 621 deploy := &appsv1.Deployment{ 622 TypeMeta: metav1.TypeMeta{ 623 Kind: "Deployment", 624 APIVersion: "apps/v1", 625 }, 626 } 627 deploy.SetLabels(map[string]string{ 628 "app.kubernetes.io/name": types.KubeBlocksChartName, 629 "app.kubernetes.io/component": "apps", 630 }) 631 if len(version) > 0 { 632 deploy.Labels["app.kubernetes.io/version"] = version 633 } 634 return deploy 635 } 636 637 func FakeAddon(name string) *extensionsv1alpha1.Addon { 638 addon := &extensionsv1alpha1.Addon{ 639 TypeMeta: metav1.TypeMeta{ 640 APIVersion: fmt.Sprintf("%s/%s", types.ExtensionsAPIGroup, types.ExtensionsAPIVersion), 641 Kind: "Addon", 642 }, 643 ObjectMeta: metav1.ObjectMeta{ 644 Name: name, 645 Namespace: Namespace, 646 }, 647 Spec: extensionsv1alpha1.AddonSpec{ 648 Installable: &extensionsv1alpha1.InstallableSpec{ 649 Selectors: []extensionsv1alpha1.SelectorRequirement{ 650 {Key: extensionsv1alpha1.KubeGitVersion, Operator: extensionsv1alpha1.Contains, Values: []string{"k3s"}}, 651 }, 652 }, 653 }, 654 } 655 addon.SetCreationTimestamp(metav1.Now()) 656 return addon 657 } 658 659 func FakeConfigMap(cmName string, namespace string, data map[string]string) *corev1.ConfigMap { 660 cm := &corev1.ConfigMap{ 661 TypeMeta: metav1.TypeMeta{ 662 APIVersion: "v1", 663 Kind: "ConfigMap", 664 }, 665 ObjectMeta: metav1.ObjectMeta{ 666 Name: cmName, 667 Namespace: Namespace, 668 }, 669 Data: data, 670 } 671 if namespace != "" { 672 cm.Namespace = namespace 673 } 674 return cm 675 } 676 677 func FakeConfigConstraint(ccName string) *appsv1alpha1.ConfigConstraint { 678 cm := &appsv1alpha1.ConfigConstraint{ 679 ObjectMeta: metav1.ObjectMeta{ 680 Name: ccName, 681 }, 682 Spec: appsv1alpha1.ConfigConstraintSpec{ 683 FormatterConfig: &appsv1alpha1.FormatterConfig{}, 684 }, 685 } 686 return cm 687 } 688 689 func FakeStorageClass(name string, isDefault bool) *storagev1.StorageClass { 690 storageClassObj := &storagev1.StorageClass{ 691 TypeMeta: metav1.TypeMeta{ 692 Kind: "StorageClass", 693 APIVersion: "storage.k8s.io/v1", 694 }, 695 ObjectMeta: metav1.ObjectMeta{ 696 Name: name, 697 }, 698 } 699 if isDefault { 700 storageClassObj.ObjectMeta.Annotations = make(map[string]string) 701 storageClassObj.ObjectMeta.Annotations[storage.IsDefaultStorageClassAnnotation] = "true" 702 } 703 return storageClassObj 704 } 705 706 func FakeServiceAccount(name string) *corev1.ServiceAccount { 707 return &corev1.ServiceAccount{ 708 ObjectMeta: metav1.ObjectMeta{ 709 Name: name, 710 Namespace: Namespace, 711 Labels: map[string]string{ 712 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 713 constant.AppNameLabelKey: KubeBlocksChartName}, 714 }, 715 } 716 } 717 718 func FakeClusterRole(name string) *rbacv1.ClusterRole { 719 return &rbacv1.ClusterRole{ 720 ObjectMeta: metav1.ObjectMeta{ 721 Name: name, 722 Labels: map[string]string{ 723 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 724 constant.AppNameLabelKey: KubeBlocksChartName}, 725 }, 726 Rules: []rbacv1.PolicyRule{ 727 { 728 APIGroups: []string{"*"}, 729 Resources: []string{"*"}, 730 Verbs: []string{"*"}, 731 }, 732 }, 733 } 734 } 735 736 func FakeClusterRoleBinding(name string, sa *corev1.ServiceAccount, clusterRole *rbacv1.ClusterRole) *rbacv1.ClusterRoleBinding { 737 return &rbacv1.ClusterRoleBinding{ 738 ObjectMeta: metav1.ObjectMeta{ 739 Name: name, 740 Labels: map[string]string{ 741 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 742 constant.AppNameLabelKey: KubeBlocksChartName}, 743 }, 744 RoleRef: rbacv1.RoleRef{ 745 Kind: clusterRole.Kind, 746 Name: clusterRole.Name, 747 }, 748 Subjects: []rbacv1.Subject{ 749 { 750 Kind: "ServiceAccount", 751 Name: sa.Name, 752 Namespace: sa.Namespace, 753 }, 754 }, 755 } 756 } 757 758 func FakeRole(name string) *rbacv1.Role { 759 return &rbacv1.Role{ 760 ObjectMeta: metav1.ObjectMeta{ 761 Name: name, 762 Labels: map[string]string{ 763 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 764 constant.AppNameLabelKey: KubeBlocksChartName}, 765 }, 766 Rules: []rbacv1.PolicyRule{ 767 { 768 APIGroups: []string{"*"}, 769 Resources: []string{"*"}, 770 Verbs: []string{"*"}, 771 }, 772 }, 773 } 774 } 775 776 func FakeRoleBinding(name string, sa *corev1.ServiceAccount, role *rbacv1.Role) *rbacv1.RoleBinding { 777 return &rbacv1.RoleBinding{ 778 ObjectMeta: metav1.ObjectMeta{ 779 Name: name, 780 Namespace: Namespace, 781 Labels: map[string]string{ 782 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 783 constant.AppNameLabelKey: KubeBlocksChartName}, 784 }, 785 RoleRef: rbacv1.RoleRef{ 786 Kind: role.Kind, 787 Name: role.Name, 788 }, 789 Subjects: []rbacv1.Subject{ 790 { 791 Kind: "ServiceAccount", 792 Name: sa.Name, 793 Namespace: sa.Namespace, 794 }, 795 }, 796 } 797 } 798 799 func FakeDeploy(name string, namespace string, extraLabels map[string]string) *appsv1.Deployment { 800 labels := map[string]string{ 801 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 802 } 803 // extraLabels will override the labels above if there is a conflict 804 for k, v := range extraLabels { 805 labels[k] = v 806 } 807 labels["app"] = name 808 809 return &appsv1.Deployment{ 810 ObjectMeta: metav1.ObjectMeta{ 811 Name: name, 812 Namespace: namespace, 813 Labels: labels, 814 }, 815 Spec: appsv1.DeploymentSpec{ 816 Replicas: pointer.Int32(1), 817 Selector: &metav1.LabelSelector{ 818 MatchLabels: labels, 819 }, 820 Template: corev1.PodTemplateSpec{ 821 ObjectMeta: metav1.ObjectMeta{ 822 Labels: labels, 823 }, 824 }, 825 }, 826 } 827 } 828 829 func FakeStatefulSet(name string, namespace string, extraLabels map[string]string) *appsv1.StatefulSet { 830 labels := map[string]string{ 831 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 832 } 833 // extraLabels will override the labels above if there is a conflict 834 for k, v := range extraLabels { 835 labels[k] = v 836 } 837 labels["app"] = name 838 return &appsv1.StatefulSet{ 839 ObjectMeta: metav1.ObjectMeta{ 840 Name: name, 841 Namespace: namespace, 842 Labels: labels, 843 }, 844 Spec: appsv1.StatefulSetSpec{ 845 Replicas: pointer.Int32(1), 846 Selector: &metav1.LabelSelector{ 847 MatchLabels: labels, 848 }, 849 Template: corev1.PodTemplateSpec{ 850 ObjectMeta: metav1.ObjectMeta{ 851 Labels: labels, 852 }, 853 }, 854 }, 855 Status: appsv1.StatefulSetStatus{ 856 Replicas: 1, 857 }, 858 } 859 } 860 861 func FakePodForSts(sts *appsv1.StatefulSet) *corev1.PodList { 862 pods := &corev1.PodList{} 863 for i := 0; i < int(*sts.Spec.Replicas); i++ { 864 pod := &corev1.Pod{ 865 ObjectMeta: metav1.ObjectMeta{ 866 Name: fmt.Sprintf("%s-%d", sts.Name, i), 867 Namespace: sts.Namespace, 868 Labels: sts.Spec.Template.Labels, 869 }, 870 Spec: corev1.PodSpec{ 871 Containers: []corev1.Container{ 872 { 873 Name: sts.Name, 874 Image: "fake-image", 875 }, 876 }, 877 }, 878 Status: corev1.PodStatus{ 879 Phase: corev1.PodRunning, 880 }, 881 } 882 pods.Items = append(pods.Items, *pod) 883 } 884 return pods 885 } 886 887 func FakeJob(name string, namespace string, extraLabels map[string]string) *batchv1.Job { 888 labels := map[string]string{ 889 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 890 } 891 // extraLabels will override the labels above if there is a conflict 892 for k, v := range extraLabels { 893 labels[k] = v 894 } 895 labels["app"] = name 896 897 return &batchv1.Job{ 898 ObjectMeta: metav1.ObjectMeta{ 899 Name: name, 900 Namespace: namespace, 901 Labels: labels, 902 }, 903 Spec: batchv1.JobSpec{ 904 Completions: pointer.Int32(1), 905 Template: corev1.PodTemplateSpec{ 906 ObjectMeta: metav1.ObjectMeta{ 907 Labels: labels, 908 }, 909 }, 910 }, 911 Status: batchv1.JobStatus{ 912 Active: 1, 913 Ready: pointer.Int32(1), 914 }, 915 } 916 } 917 918 func FakeCronJob(name string, namespace string, extraLabels map[string]string) *batchv1.CronJob { 919 labels := map[string]string{ 920 constant.AppInstanceLabelKey: types.KubeBlocksReleaseName, 921 } 922 // extraLabels will override the labels above if there is a conflict 923 for k, v := range extraLabels { 924 labels[k] = v 925 } 926 labels["app"] = name 927 928 return &batchv1.CronJob{ 929 ObjectMeta: metav1.ObjectMeta{ 930 Name: name, 931 Namespace: namespace, 932 Labels: labels, 933 }, 934 Spec: batchv1.CronJobSpec{ 935 Schedule: "*/1 * * * *", 936 JobTemplate: batchv1.JobTemplateSpec{ 937 ObjectMeta: metav1.ObjectMeta{ 938 Labels: labels, 939 }, 940 }, 941 }, 942 } 943 } 944 945 func FakeResourceNotFound(versionResource schema.GroupVersionResource, name string) *metav1.Status { 946 return &metav1.Status{ 947 TypeMeta: metav1.TypeMeta{ 948 Kind: "Status", 949 APIVersion: "v1", 950 }, 951 Status: "Failure", 952 Message: fmt.Sprintf("%s.%s \"%s\" not found", versionResource.Resource, versionResource.Group, name), 953 Reason: "NotFound", 954 Details: nil, 955 Code: 404, 956 } 957 } 958 959 func FakePodChaos(name, namespace string) *chaosmeshv1alpha1.PodChaos { 960 return &chaosmeshv1alpha1.PodChaos{ 961 TypeMeta: metav1.TypeMeta{ 962 Kind: "PodChaos", 963 APIVersion: "chaos-mesh.org/v1alpha1", 964 }, 965 ObjectMeta: metav1.ObjectMeta{ 966 Name: name, 967 Namespace: namespace, 968 }, 969 Spec: chaosmeshv1alpha1.PodChaosSpec{ 970 ContainerSelector: chaosmeshv1alpha1.ContainerSelector{ 971 PodSelector: chaosmeshv1alpha1.PodSelector{ 972 Selector: chaosmeshv1alpha1.PodSelectorSpec{ 973 GenericSelectorSpec: chaosmeshv1alpha1.GenericSelectorSpec{ 974 Namespaces: []string{namespace}, 975 }, 976 }, 977 }, 978 }, 979 Action: chaosmeshv1alpha1.PodKillAction, 980 }, 981 } 982 } 983 984 func FakeEventForObject(name string, namespace string, object string) *corev1.Event { 985 return &corev1.Event{ 986 TypeMeta: metav1.TypeMeta{ 987 Kind: "Event", 988 APIVersion: "v1", 989 }, 990 ObjectMeta: metav1.ObjectMeta{ 991 Name: name, 992 Namespace: namespace, 993 }, 994 InvolvedObject: corev1.ObjectReference{ 995 Name: object, 996 }, 997 } 998 } 999 1000 func FakeStorageProvider(name string, mutateFunc func(obj *storagev1alpha1.StorageProvider)) *storagev1alpha1.StorageProvider { 1001 storageProvider := &storagev1alpha1.StorageProvider{ 1002 TypeMeta: metav1.TypeMeta{ 1003 APIVersion: fmt.Sprintf("%s/%s", types.StorageAPIGroup, types.StorageAPIVersion), 1004 Kind: "StorageProvider", 1005 }, 1006 ObjectMeta: metav1.ObjectMeta{ 1007 Name: name, 1008 }, 1009 Spec: storagev1alpha1.StorageProviderSpec{ 1010 CSIDriverName: "fake-csi-s3", 1011 CSIDriverSecretTemplate: ` 1012 accessKeyId: {{ index .Parameters "accessKeyId" }} 1013 secretAccessKey: {{ index .Parameters "secretAccessKey" }} 1014 `, 1015 StorageClassTemplate: ` 1016 bucket: {{ index .Parameters "bucket" }} 1017 region: {{ index .Parameters "region" }} 1018 endpoint: {{ index .Parameters "endpoint" }} 1019 mountOptions: {{ index .Parameters "mountOptions" | default "" }} 1020 `, 1021 ParametersSchema: &storagev1alpha1.ParametersSchema{ 1022 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ 1023 Type: "object", 1024 Properties: map[string]apiextensionsv1.JSONSchemaProps{ 1025 "accessKeyId": {Type: "string"}, 1026 "secretAccessKey": {Type: "string"}, 1027 "bucket": {Type: "string"}, 1028 "region": { 1029 Type: "string", 1030 Enum: []apiextensionsv1.JSON{{Raw: []byte(`""`)}, {Raw: []byte(`"us-east-1"`)}, {Raw: []byte(`"us-west-1"`)}}, 1031 }, 1032 "endpoint": {Type: "string"}, 1033 "mountOptions": {Type: "string"}, 1034 }, 1035 Required: []string{ 1036 "accessKeyId", 1037 "secretAccessKey", 1038 }, 1039 }, 1040 CredentialFields: []string{ 1041 "accessKeyId", 1042 "secretAccessKey", 1043 }, 1044 }, 1045 }, 1046 } 1047 storageProvider.SetCreationTimestamp(metav1.Now()) 1048 if mutateFunc != nil { 1049 mutateFunc(storageProvider) 1050 } 1051 return storageProvider 1052 } 1053 1054 func FakeBackupRepo(name string, isDefault bool) *dpv1alpha1.BackupRepo { 1055 backupRepo := &dpv1alpha1.BackupRepo{ 1056 TypeMeta: metav1.TypeMeta{ 1057 APIVersion: fmt.Sprintf("%s/%s", types.DPAPIGroup, types.DPAPIVersion), 1058 Kind: "BackupRepo", 1059 }, 1060 ObjectMeta: metav1.ObjectMeta{ 1061 Name: name, 1062 }, 1063 Spec: dpv1alpha1.BackupRepoSpec{ 1064 StorageProviderRef: "fake-storage-provider", 1065 PVReclaimPolicy: "Retain", 1066 }, 1067 } 1068 if isDefault { 1069 backupRepo.Annotations = map[string]string{ 1070 dptypes.DefaultBackupRepoAnnotationKey: "true", 1071 } 1072 } 1073 return backupRepo 1074 } 1075 1076 func FakeClusterList() *appsv1alpha1.ClusterList { 1077 clusters := &appsv1alpha1.ClusterList{ 1078 ListMeta: metav1.ListMeta{ 1079 ResourceVersion: "15", 1080 }, 1081 Items: []appsv1alpha1.Cluster{ 1082 *FakeCluster(ClusterName, Namespace), 1083 *FakeCluster(ClusterName+"-other", Namespace), 1084 }, 1085 } 1086 clusters.Items = append(clusters.Items, *FakeCluster(ClusterName, Namespace)) 1087 return clusters 1088 } 1089 1090 func FakeServiceRef(serviceRefName string) appsv1alpha1.ServiceRefDeclaration { 1091 return appsv1alpha1.ServiceRefDeclaration{ 1092 Name: serviceRefName, 1093 ServiceRefDeclarationSpecs: []appsv1alpha1.ServiceRefDeclarationSpec{ 1094 { 1095 ServiceKind: "mysql", 1096 ServiceVersion: "8.0.\\d{1,2}$", 1097 }, 1098 }, 1099 } 1100 }