From abfc40cb227cddb6917fb735c37add9c911d57f6 Mon Sep 17 00:00:00 2001 From: Lukas Piwowarski Date: Thu, 26 Oct 2023 17:43:39 +0300 Subject: [PATCH] Add tempest options This patch introduces a set of parameters for the tempestRun section in the Tempest CR. This field parameters allow a user to specify parameters with which tempest command should be executed inside the Tempest pod. The documentation is updated as well so that it demonstrates how the new field should be utilized. --- api/bases/test.openstack.org_tempests.yaml | 37 ++-- api/v1beta1/tempest_types.go | 31 +++- api/v1beta1/zz_generated.deepcopy.go | 12 +- .../bases/test.openstack.org_tempests.yaml | 37 ++-- config/samples/test_v1beta1_tempest.yaml | 19 ++- controllers/tempest_controller.go | 158 ++++++++++++------ docs/source/samples/tempest-config.yaml | 22 +++ docs/source/samples/tempest-deployment.yaml | 6 +- 8 files changed, 216 insertions(+), 106 deletions(-) diff --git a/api/bases/test.openstack.org_tempests.yaml b/api/bases/test.openstack.org_tempests.yaml index 01f71c16..191dddb5 100644 --- a/api/bases/test.openstack.org_tempests.yaml +++ b/api/bases/test.openstack.org_tempests.yaml @@ -112,25 +112,34 @@ spec: tempestRun: description: TempestSpec TempestRun parts properties: - allowedTests: - default: - - tempest.api.identity.v3 - description: AllowedTests - items: - type: string - type: array concurrency: default: -1 description: Concurrency is the Default concurrency format: int64 type: integer - skippedTests: - description: SkippedTests - items: - type: string - type: array + excludeList: + default: "" + description: ExcludeList + type: string + includeList: + default: tempest.api.identity.v3 + description: IncludeList + type: string + parallel: + default: true + description: Run tests in parallel + type: boolean + serial: + default: false + description: Serial run + type: boolean + smoke: + default: false + description: Smoke tests + type: boolean workerFile: - description: WorkerFile is the detailed concurry spec file + default: "" + description: WorkerFile is the detailed concurrency spec file type: string type: object tempestconfRun: @@ -210,7 +219,7 @@ spec: description: Output file type: string overrides: - default: "" + default: identity.v3_endpoint_type public description: Override options type: string profile: diff --git a/api/v1beta1/tempest_types.go b/api/v1beta1/tempest_types.go index 3433e42f..e8bbcee7 100644 --- a/api/v1beta1/tempest_types.go +++ b/api/v1beta1/tempest_types.go @@ -38,13 +38,14 @@ type Hash struct { // TempestSpec TempestRun parts type TempestRunSpec struct { // +kubebuilder:validation:Optional - // +kubebuilder:default={"tempest.api.identity.v3"} - // AllowedTests - AllowedTests []string `json:"allowedTests,omitempty"` + // +kubebuilder:default="tempest.api.identity.v3" + // IncludeList + IncludeList string `json:"includeList,omitempty"` // +kubebuilder:validation:Optional - // SkippedTests - SkippedTests []string `json:"skippedTests,omitempty"` + // +kubebuilder:default="" + // ExcludeList + ExcludeList string `json:"excludeList,omitempty"` // +kubebuilder:validation:Optional // +kubebuilder:default:=-1 @@ -52,7 +53,23 @@ type TempestRunSpec struct { Concurrency int64 `json:"concurrency,omitempty"` // +kubebuilder:validation:Optional - // WorkerFile is the detailed concurry spec file + // +kubebuilder:default:=false + // Smoke tests + Smoke bool `json:"smoke,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default:=true + // Run tests in parallel + Parallel bool `json:"parallel,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default:=false + // Serial run + Serial bool `json:"serial,omitempty"` + + // +kubebuilder:validation:Optional + // +kubebuilder:default:="" + // WorkerFile is the detailed concurrency spec file WorkerFile string `json:"workerFile,omitempty"` } @@ -169,7 +186,7 @@ type TempestconfRunSpec struct { Remove string `json:"remove"` // +kubebuilder:validation:Optional - // +kubebuilder:default="" + // +kubebuilder:default="identity.v3_endpoint_type public" // Override options Overrides string `json:"overrides"` diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 18b58f36..ad5c474a 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -123,16 +123,6 @@ func (in *TempestList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TempestRunSpec) DeepCopyInto(out *TempestRunSpec) { *out = *in - if in.AllowedTests != nil { - in, out := &in.AllowedTests, &out.AllowedTests - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.SkippedTests != nil { - in, out := &in.SkippedTests, &out.SkippedTests - *out = make([]string, len(*in)) - copy(*out, *in) - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TempestRunSpec. @@ -175,7 +165,7 @@ func (in *TempestSpec) DeepCopyInto(out *TempestSpec) { if in.TempestRun != nil { in, out := &in.TempestRun, &out.TempestRun *out = new(TempestRunSpec) - (*in).DeepCopyInto(*out) + **out = **in } if in.TempestconfRun != nil { in, out := &in.TempestconfRun, &out.TempestconfRun diff --git a/config/crd/bases/test.openstack.org_tempests.yaml b/config/crd/bases/test.openstack.org_tempests.yaml index 01f71c16..191dddb5 100644 --- a/config/crd/bases/test.openstack.org_tempests.yaml +++ b/config/crd/bases/test.openstack.org_tempests.yaml @@ -112,25 +112,34 @@ spec: tempestRun: description: TempestSpec TempestRun parts properties: - allowedTests: - default: - - tempest.api.identity.v3 - description: AllowedTests - items: - type: string - type: array concurrency: default: -1 description: Concurrency is the Default concurrency format: int64 type: integer - skippedTests: - description: SkippedTests - items: - type: string - type: array + excludeList: + default: "" + description: ExcludeList + type: string + includeList: + default: tempest.api.identity.v3 + description: IncludeList + type: string + parallel: + default: true + description: Run tests in parallel + type: boolean + serial: + default: false + description: Serial run + type: boolean + smoke: + default: false + description: Smoke tests + type: boolean workerFile: - description: WorkerFile is the detailed concurry spec file + default: "" + description: WorkerFile is the detailed concurrency spec file type: string type: object tempestconfRun: @@ -210,7 +219,7 @@ spec: description: Output file type: string overrides: - default: "" + default: identity.v3_endpoint_type public description: Override options type: string profile: diff --git a/config/samples/test_v1beta1_tempest.yaml b/config/samples/test_v1beta1_tempest.yaml index 9e37e42f..de773703 100644 --- a/config/samples/test_v1beta1_tempest.yaml +++ b/config/samples/test_v1beta1_tempest.yaml @@ -7,10 +7,23 @@ metadata: spec: containerImage: quay.io/podified-antelope-centos9/openstack-tempest:current-podified tempestRun: - allowedTests: - - tempest.api.identity.v3.* + # NOTE: All parameters have default values (use only when you want to override + # the default behaviour) + includeList: | # <-- Use | to preserve \n + tempest.api.identity.v3.* concurrency: 8 - pythonTempestconfRun: + # excludeList: + # - tempest.api.identity.v3.* + # workerFile: | # <-- use | to preserver \n + # - worker: + # - tempest.api.* + # - neutron_tempest_tests + # - worker: + # - tempest.scenario.* + # smoke: false + # serial: false + # parallel: true + tempestconfRun: # NOTE: All parameters have default values (use only when you want to override # the default behaviour) # create: true diff --git a/controllers/tempest_controller.go b/controllers/tempest_controller.go index 965ea949..82bff502 100644 --- a/controllers/tempest_controller.go +++ b/controllers/tempest_controller.go @@ -22,12 +22,6 @@ import ( "strconv" "time" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "github.com/go-logr/logr" "github.com/openstack-k8s-operators/lib-common/modules/common" "github.com/openstack-k8s-operators/lib-common/modules/common/condition" @@ -44,6 +38,11 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" k8s_errors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) // TempestReconciler reconciles a Tempest object @@ -391,61 +390,96 @@ func getDefaultInt(variable int64) string { } } -// generateServiceConfigMaps - create create configmaps which hold scripts and service configuration -// TODO add DefaultConfigOverwrite -func (r *TempestReconciler) generateServiceConfigMaps( - ctx context.Context, - h *helper.Helper, - instance *testv1beta1.Tempest, -) error { - // Create/update configmaps from templates - cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(tempest.ServiceName), map[string]string{}) +func setTempestConfigVars(envVars map[string]string, + customData map[string]string, + tempestRun *testv1beta1.TempestRunSpec) { + + testOperatorDir := "/etc/test_operator/" + if tempestRun == nil { + includeListFile := "include.txt" + customData[includeListFile] = "tempest.api.identity.v3" + envVars["TEMPEST_INCLUDE_LIST"] = testOperatorDir + includeListFile + envVars["TEMPEST_PARALLEL"] = "true" + return + } - templateParameters := make(map[string]interface{}) - customData := make(map[string]string) - envVars := make(map[string]string) + // Files + if len(tempestRun.WorkerFile) != 0 { + workerFile := "worker_file.yaml" + customData[workerFile] = tempestRun.WorkerFile + envVars["TEMPEST_WORKER_FILE"] = testOperatorDir + workerFile + } - /* Tempest */ - if len(instance.Spec.TempestRun.WorkerFile) != 0 { - customData["worker_file.yaml"] = instance.Spec.TempestRun.WorkerFile + if len(tempestRun.IncludeList) != 0 { + includeListFile := "include.txt" + customData[includeListFile] = tempestRun.IncludeList + envVars["TEMPEST_INCLUDE_LIST"] = testOperatorDir + includeListFile } - templateParameters["AllowedTests"] = instance.Spec.TempestRun.AllowedTests - templateParameters["SkippedTests"] = instance.Spec.TempestRun.SkippedTests + if len(tempestRun.ExcludeList) != 0 { + excludeListFile := "exclude.txt" + customData[excludeListFile] = tempestRun.ExcludeList + envVars["TEMPEST_EXCLUDE_LIST"] = testOperatorDir + excludeListFile + } + + // Bool + tempestBoolEnvVars := make(map[string]bool) + tempestBoolEnvVars = map[string]bool{ + "TEMPEST_SERIAL": tempestRun.Serial, + "TEMPEST_PARALLEL": tempestRun.Parallel, + "TEMPEST_SMOKE": tempestRun.Smoke, + } + + for key, value := range tempestBoolEnvVars { + envVars[key] = getDefaultBool(value) + } + + // Int + envVars["TEMPEST_CONCURRENCY"] = getDefaultInt(tempestRun.Concurrency) +} + +func setTempestconfConfigVars(envVars map[string]string, + customData map[string]string, + tempestconfRun *testv1beta1.TempestconfRunSpec) { + + if tempestconfRun == nil { + envVars["TEMPESTCONF_CREATE"] = "true" + envVars["TEMPESTCONF_OVERRIDES"] = "identity.v3_endpoint_type public" + return + } - /* tempestconf - start */ // Files - testOperatorDir := "./etc/test_operator/" - if len(instance.Spec.TempestconfRun.DeployerInput) != 0 { + testOperatorDir := "/etc/test_operator/" + if len(tempestconfRun.DeployerInput) != 0 { deployerInputFile := "deployer_input.yaml" - customData[deployerInputFile] = instance.Spec.TempestconfRun.DeployerInput + customData[deployerInputFile] = tempestconfRun.DeployerInput envVars["TEMPESTCONF_DEPLOYER_INPUT"] = testOperatorDir + deployerInputFile } - if len(instance.Spec.TempestconfRun.TestAccounts) != 0 { + if len(tempestconfRun.TestAccounts) != 0 { accountsFile := "accounts.yaml" - customData[accountsFile] = instance.Spec.TempestconfRun.TestAccounts + customData[accountsFile] = tempestconfRun.TestAccounts envVars["TEMPESTCONF_TEST_ACCOUNTS"] = testOperatorDir + accountsFile } - if len(instance.Spec.TempestconfRun.Profile) != 0 { + if len(tempestconfRun.Profile) != 0 { profileFile := "profile.yaml" - customData[profileFile] = instance.Spec.TempestconfRun.Profile + customData[profileFile] = tempestconfRun.Profile envVars["TEMPESTCONF_PROFILE"] = testOperatorDir + profileFile } // Bool tempestconfBoolEnvVars := make(map[string]bool) tempestconfBoolEnvVars = map[string]bool{ - "TEMPESTCONF_CREATE": instance.Spec.TempestconfRun.Create, - "TEMPESTCONF_COLLECT_TIMING": instance.Spec.TempestconfRun.CollectTiming, - "TEMPESTCONF_INSECURE": instance.Spec.TempestconfRun.Insecure, - "TEMPESTCONF_NO_DEFAULT_DEPLOYER": instance.Spec.TempestconfRun.NoDefaultDeployer, - "TEMPESTCONF_DEBUG": instance.Spec.TempestconfRun.Debug, - "TEMPESTCONF_VERBOSE": instance.Spec.TempestconfRun.Verbose, - "TEMPESTCONF_NON_ADMIN": instance.Spec.TempestconfRun.NonAdmin, - "TEMPESTCONF_RETRY_IMAGE": instance.Spec.TempestconfRun.RetryImage, - "TEMPESTCONF_CONVERT_TO_RAW": instance.Spec.TempestconfRun.ConvertToRaw, + "TEMPESTCONF_CREATE": tempestconfRun.Create, + "TEMPESTCONF_COLLECT_TIMING": tempestconfRun.CollectTiming, + "TEMPESTCONF_INSECURE": tempestconfRun.Insecure, + "TEMPESTCONF_NO_DEFAULT_DEPLOYER": tempestconfRun.NoDefaultDeployer, + "TEMPESTCONF_DEBUG": tempestconfRun.Debug, + "TEMPESTCONF_VERBOSE": tempestconfRun.Verbose, + "TEMPESTCONF_NON_ADMIN": tempestconfRun.NonAdmin, + "TEMPESTCONF_RETRY_IMAGE": tempestconfRun.RetryImage, + "TEMPESTCONF_CONVERT_TO_RAW": tempestconfRun.ConvertToRaw, } for key, value := range tempestconfBoolEnvVars { @@ -455,9 +489,9 @@ func (r *TempestReconciler) generateServiceConfigMaps( // Int tempestconfIntEnvVars := make(map[string]int64) tempestconfIntEnvVars = map[string]int64{ - "TEMPESTCONF_TIMEOUT": instance.Spec.TempestconfRun.Timeout, - "TEMPESTCONF_FLAVOR_MIN_MEM": instance.Spec.TempestconfRun.FlavorMinMem, - "TEMPESTCONF_FLAVOR_MIN_DISK": instance.Spec.TempestconfRun.FlavorMinDisk, + "TEMPESTCONF_TIMEOUT": tempestconfRun.Timeout, + "TEMPESTCONF_FLAVOR_MIN_MEM": tempestconfRun.FlavorMinMem, + "TEMPESTCONF_FLAVOR_MIN_DISK": tempestconfRun.FlavorMinDisk, } for key, value := range tempestconfIntEnvVars { @@ -465,15 +499,33 @@ func (r *TempestReconciler) generateServiceConfigMaps( } // String - envVars["TEMPESTCONF_OUT"] = instance.Spec.TempestconfRun.Out - envVars["TEMPESTCONF_CREATE_ACCOUNTS_FILE"] = instance.Spec.TempestconfRun.CreateAccountsFile - envVars["TEMPESTCONF_GENERATE_PROFILE"] = instance.Spec.TempestconfRun.GenerateProfile - envVars["TEMPESTCONF_IMAGE_DISK_FORMAT"] = instance.Spec.TempestconfRun.ImageDiskFormat - envVars["TEMPESTCONF_IMAGE"] = instance.Spec.TempestconfRun.Image - envVars["TEMPESTCONF_NETWORK_ID"] = instance.Spec.TempestconfRun.NetworkID - envVars["TEMPESTCONF_APPEND"] = instance.Spec.TempestconfRun.Append - envVars["TEMPESTCONF_REMOVE"] = instance.Spec.TempestconfRun.Remove - envVars["TEMPESTCONF_OVERRIDES"] = instance.Spec.TempestconfRun.Overrides + envVars["TEMPESTCONF_OUT"] = tempestconfRun.Out + envVars["TEMPESTCONF_CREATE_ACCOUNTS_FILE"] = tempestconfRun.CreateAccountsFile + envVars["TEMPESTCONF_GENERATE_PROFILE"] = tempestconfRun.GenerateProfile + envVars["TEMPESTCONF_IMAGE_DISK_FORMAT"] = tempestconfRun.ImageDiskFormat + envVars["TEMPESTCONF_IMAGE"] = tempestconfRun.Image + envVars["TEMPESTCONF_NETWORK_ID"] = tempestconfRun.NetworkID + envVars["TEMPESTCONF_APPEND"] = tempestconfRun.Append + envVars["TEMPESTCONF_REMOVE"] = tempestconfRun.Remove + envVars["TEMPESTCONF_OVERRIDES"] = tempestconfRun.Overrides +} + +// generateServiceConfigMaps - create create configmaps which hold scripts and service configuration +// TODO add DefaultConfigOverwrite +func (r *TempestReconciler) generateServiceConfigMaps( + ctx context.Context, + h *helper.Helper, + instance *testv1beta1.Tempest, +) error { + // Create/update configmaps from template + cmLabels := labels.GetLabels(instance, labels.GetGroupLabel(tempest.ServiceName), map[string]string{}) + + templateParameters := make(map[string]interface{}) + customData := make(map[string]string) + envVars := make(map[string]string) + + setTempestConfigVars(envVars, customData, instance.Spec.TempestRun) + setTempestconfConfigVars(envVars, customData, instance.Spec.TempestconfRun) /* Tempestconf - end */ cms := []util.Template{ @@ -489,7 +541,6 @@ func (r *TempestReconciler) generateServiceConfigMaps( { Name: fmt.Sprintf("%s-config-data", instance.Name), Namespace: instance.Namespace, - Type: util.TemplateTypeConfig, InstanceType: instance.Kind, Labels: cmLabels, ConfigOptions: templateParameters, @@ -499,7 +550,6 @@ func (r *TempestReconciler) generateServiceConfigMaps( { Name: fmt.Sprintf("%s-env-vars", instance.Name), Namespace: instance.Namespace, - Type: util.TemplateTypeConfig, InstanceType: instance.Kind, Labels: cmLabels, ConfigOptions: templateParameters, diff --git a/docs/source/samples/tempest-config.yaml b/docs/source/samples/tempest-config.yaml index 810f8854..6a46d373 100644 --- a/docs/source/samples/tempest-config.yaml +++ b/docs/source/samples/tempest-config.yaml @@ -5,7 +5,29 @@ metadata: data: include.txt: | tempest.api.identity.v3 + # exclude.txt: | + # tempest.api.identity.v3 + # worker_file.yaml: | + # - worker: + # - tempest.api.* + # - neutron_tempest_tests + # - worker: + # - tempest.scenario.* + # TEMPEST env variables: + # ---------------------- + # NOTE: All parameters have default values (use only when you want to override + # the default behaviour) + TEMPEST_INCLUDE_LIST: "/var/lib/tempest/include.txt" + # TEMPEST_EXCLUDE_LIST: "/var/lib/tempest/exclude.txt" + # TEMPEST_WORKER_FILE: "/var/lib/tempest/worker_file.yaml" + # TEMPEST_CONCURRENCY: 8 + # TEMPEST_SMOKE: true + # TEMPEST_PARALLEL: true + # TEMPEST_SERIAL: true + + # TEMPESTCONF env variables: + # -------------------------- # NOTE: All parameters have default values (use only when you want to override # the default behaviour) # TEMPESTCONF_CREATE: "true" diff --git a/docs/source/samples/tempest-deployment.yaml b/docs/source/samples/tempest-deployment.yaml index c51e247f..81cbea45 100644 --- a/docs/source/samples/tempest-deployment.yaml +++ b/docs/source/samples/tempest-deployment.yaml @@ -47,14 +47,14 @@ spec: volumeMounts: - mountPath: "/var/lib/tempest/external_files/" name: tempest-workdir + - mountPath: "/var/lib/tempest/include.txt" + name: tempest-config + subPath: include.txt - mountPath: "/etc/openstack" name: pre-install - mountPath: "/etc/openstack/clouds.yaml" name: clouds-config subPath: clouds.yaml - - mountPath: "/var/lib/tempest/external_files/include.txt" - name: tempest-config - subPath: include.txt - mountPath: "/etc/openstack/secure.yaml" name: cloud-passwd subPath: secure.yaml