From 8a261276b6055b3acea30b714dac2a56941353f2 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Sun, 23 Jun 2024 13:41:56 +0800 Subject: [PATCH 01/13] chore: add metrics_collector_config in tune function. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- .../v1beta1/kubeflow/katib/api/katib_client.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py index 7988dbaa898..9c1593f31ee 100644 --- a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py +++ b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py @@ -186,6 +186,7 @@ def tune( retain_trials: bool = False, packages_to_install: List[str] = None, pip_index_url: str = "https://pypi.org/simple", + metrics_collector_config: Dict[str, Any] = {"kind": "StdOut"}, ): """Create HyperParameter Tuning Katib Experiment from the objective function. @@ -248,6 +249,8 @@ def tune( to the base image packages. These packages are installed before executing the objective function. pip_index_url: The PyPI url from which to install Python packages. + metrics_collector_config: Specify the config of metrics collector, + for example, `metrics_collector_config = {"kind": "Push"}`. Raises: ValueError: Function arguments have incorrect type or value. @@ -380,6 +383,19 @@ def tune( f"Incorrect value for env_per_trial: {env_per_trial}" ) + # Add metrics collector to the Katib Experiment. + # Up to now, We only support parameter `kind`, of which default value is `StdOut`, to specify the kind of metrics collector. + experiment.spec.metrics_collector = models.V1beta1MetricsCollectorSpec( + collector=models.V1beta1CollectorSpec(kind=metrics_collector_config["kind"]) + ) + if metrics_collector_config["kind"] == "Push": + trial_params.append( + models.V1beta1TrialParameterSpec(name="trialName", reference="${{trialSpec.Name}}") + ) + env.append( + client.V1EnvVar(name="KATIB_TRIAL_NAME", value="${{trialParameters.trialName}}") + ) + # Create Trial specification. trial_spec = client.V1Job( api_version="batch/v1", From 67b4af61457d14aa9326ee3cedee0ff6ecd12599 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Sun, 23 Jun 2024 13:52:09 +0800 Subject: [PATCH 02/13] rebase: rebase feat/new-param-tune to master. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- pkg/apis/controller/common/v1beta1/common_types.go | 4 ++-- pkg/webhook/v1beta1/experiment/validator/validator.go | 4 ++-- pkg/webhook/v1beta1/pod/inject_webhook.go | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/apis/controller/common/v1beta1/common_types.go b/pkg/apis/controller/common/v1beta1/common_types.go index 8722e8a474d..251f8887042 100644 --- a/pkg/apis/controller/common/v1beta1/common_types.go +++ b/pkg/apis/controller/common/v1beta1/common_types.go @@ -220,8 +220,8 @@ const ( CustomCollector CollectorKind = "Custom" // When model training source code persists metrics into persistent layer - // directly, metricsCollector isn't in need, and its kind is "noneCollector" - NoneCollector CollectorKind = "None" + // directly, sidecar container isn't in need, and its kind is "pushCollector" + PushCollector CollectorKind = "Push" MetricsVolume = "metrics-volume" ) diff --git a/pkg/webhook/v1beta1/experiment/validator/validator.go b/pkg/webhook/v1beta1/experiment/validator/validator.go index aeabbc0f463..cf865fe529e 100644 --- a/pkg/webhook/v1beta1/experiment/validator/validator.go +++ b/pkg/webhook/v1beta1/experiment/validator/validator.go @@ -488,8 +488,8 @@ func (g *DefaultValidator) validateMetricsCollector(inst *experimentsv1beta1.Exp } // TODO(hougangliu): log warning message if some field will not be used for the metricsCollector kind switch mcKind { - case commonapiv1beta1.NoneCollector, commonapiv1beta1.StdOutCollector: - return allErrs + case commonapiv1beta1.PushCollector, commonapiv1beta1.StdOutCollector: + return nil case commonapiv1beta1.FileCollector: if mcSpec.Source == nil || mcSpec.Source.FileSystemPath == nil || mcSpec.Source.FileSystemPath.Kind != commonapiv1beta1.FileKind || !filepath.IsAbs(mcSpec.Source.FileSystemPath.Path) { diff --git a/pkg/webhook/v1beta1/pod/inject_webhook.go b/pkg/webhook/v1beta1/pod/inject_webhook.go index f48b4b96a07..e7ab14029bb 100644 --- a/pkg/webhook/v1beta1/pod/inject_webhook.go +++ b/pkg/webhook/v1beta1/pod/inject_webhook.go @@ -147,8 +147,8 @@ func (s *SidecarInjector) Mutate(pod *v1.Pod, namespace string) (*v1.Pod, error) return mutatedPod, nil } - // If Metrics Collector in None, skip the mutation. - if trial.Spec.MetricsCollector.Collector.Kind == common.NoneCollector { + // If Metrics Collector is Push, skip the mutation. + if trial.Spec.MetricsCollector.Collector.Kind == common.PushCollector { return mutatedPod, nil } From 2db6fcd56f5fede7d9b40eb5db80649384554821 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Mon, 24 Jun 2024 23:09:18 +0800 Subject: [PATCH 03/13] chore: add metrics collector kind list in comment. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- sdk/python/v1beta1/kubeflow/katib/api/katib_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py index 9c1593f31ee..b153fe3f9a6 100644 --- a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py +++ b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py @@ -251,6 +251,7 @@ def tune( pip_index_url: The PyPI url from which to install Python packages. metrics_collector_config: Specify the config of metrics collector, for example, `metrics_collector_config = {"kind": "Push"}`. + Currently, we only support `StdOut` and `Push` metrics collector. Raises: ValueError: Function arguments have incorrect type or value. From 02e124b10145e5c67819e7ccf0ebc509254b1a20 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Sat, 6 Jul 2024 05:04:38 +0000 Subject: [PATCH 04/13] fix: always pass Trial name to the training container. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- .../v1beta1/kubeflow/katib/api/katib_client.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py index b153fe3f9a6..55aeca58987 100644 --- a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py +++ b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py @@ -190,6 +190,8 @@ def tune( ): """Create HyperParameter Tuning Katib Experiment from the objective function. + Katib always passes Trial name as env variable `KATIB_TRIAL_NAME` to the training container. + Args: name: Name for the Experiment. objective: Objective function that Katib uses to train the model. @@ -389,13 +391,14 @@ def tune( experiment.spec.metrics_collector = models.V1beta1MetricsCollectorSpec( collector=models.V1beta1CollectorSpec(kind=metrics_collector_config["kind"]) ) - if metrics_collector_config["kind"] == "Push": - trial_params.append( - models.V1beta1TrialParameterSpec(name="trialName", reference="${{trialSpec.Name}}") - ) - env.append( - client.V1EnvVar(name="KATIB_TRIAL_NAME", value="${{trialParameters.trialName}}") - ) + + # Pass Trial name as env variable `KATIB_TRIAL_NAME` to the training containers. + trial_params.append( + models.V1beta1TrialParameterSpec(name="trialName", reference="${{trialSpec.Name}}") + ) + env.append( + client.V1EnvVar(name="KATIB_TRIAL_NAME", value="${{trialParameters.trialName}}") + ) # Create Trial specification. trial_spec = client.V1Job( From b1cd440f5a3d26293f81c67f107709e6f7175ce3 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Wed, 10 Jul 2024 08:24:56 +0000 Subject: [PATCH 05/13] fix: delete passing env variable logics in katib_client.py Signed-off-by: Electronic-Waste <2690692950@qq.com> --- sdk/python/v1beta1/kubeflow/katib/api/katib_client.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py index 55aeca58987..398e73ef908 100644 --- a/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py +++ b/sdk/python/v1beta1/kubeflow/katib/api/katib_client.py @@ -190,8 +190,6 @@ def tune( ): """Create HyperParameter Tuning Katib Experiment from the objective function. - Katib always passes Trial name as env variable `KATIB_TRIAL_NAME` to the training container. - Args: name: Name for the Experiment. objective: Objective function that Katib uses to train the model. @@ -392,14 +390,6 @@ def tune( collector=models.V1beta1CollectorSpec(kind=metrics_collector_config["kind"]) ) - # Pass Trial name as env variable `KATIB_TRIAL_NAME` to the training containers. - trial_params.append( - models.V1beta1TrialParameterSpec(name="trialName", reference="${{trialSpec.Name}}") - ) - env.append( - client.V1EnvVar(name="KATIB_TRIAL_NAME", value="${{trialParameters.trialName}}") - ) - # Create Trial specification. trial_spec = client.V1Job( api_version="batch/v1", From 828cbfd43a8adbcbf12d4dc909ba618c06872fc9 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Fri, 12 Jul 2024 03:39:12 +0000 Subject: [PATCH 06/13] fix: passing env variable KATIB_TRIAL_NAME in the webhook of pod. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- pkg/controller.v1beta1/consts/const.go | 3 +++ pkg/webhook/v1beta1/pod/inject_webhook.go | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/pkg/controller.v1beta1/consts/const.go b/pkg/controller.v1beta1/consts/const.go index b59fb4f4bc6..2cffe30cde3 100644 --- a/pkg/controller.v1beta1/consts/const.go +++ b/pkg/controller.v1beta1/consts/const.go @@ -60,6 +60,9 @@ const ( // resources list which can be used as trial template ConfigTrialResources = "trial-resources" + // EnvTrialName is the env variable of Trial name + EnvTrialName = "KATIB_TRIAL_NAME" + // LabelExperimentName is the label of experiment name. LabelExperimentName = "katib.kubeflow.org/experiment" // LabelSuggestionName is the label of suggestion name. diff --git a/pkg/webhook/v1beta1/pod/inject_webhook.go b/pkg/webhook/v1beta1/pod/inject_webhook.go index e7ab14029bb..db01fca5d44 100644 --- a/pkg/webhook/v1beta1/pod/inject_webhook.go +++ b/pkg/webhook/v1beta1/pod/inject_webhook.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "net/http" "path/filepath" "strconv" @@ -140,6 +141,25 @@ func (s *SidecarInjector) Mutate(pod *v1.Pod, namespace string) (*v1.Pod, error) // Add Katib Trial labels to the Pod metadata. mutatePodMetadata(mutatedPod, trial) + + // Pass env variable KATIB_TRIAL_NAME to training containers using fieldPath. + for idx := range mutatedPod.Spec.Containers { + if mutatedPod.Spec.Containers[idx].Env == nil { + mutatedPod.Spec.Containers[idx].Env = []v1.EnvVar{} + } + mutatedPod.Spec.Containers[idx].Env = append( + mutatedPod.Spec.Containers[idx].Env, + v1.EnvVar{ + Name: consts.EnvTrialName, + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: fmt.Sprintf("metadata.labels['%s']", consts.LabelTrialName), + }, + }, + }, + ) + } + // Do the following mutation only for the Primary pod. // If PrimaryPodLabel is not set we mutate all pods which are related to Trial job. // Otherwise, mutate pod only with the appropriate labels. From a0c8749057dae231fe308606c208e35b0b317d9a Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Fri, 12 Jul 2024 15:17:21 +0000 Subject: [PATCH 07/13] fix: pass env variable KATIB_TRIAL_NAME only to the primary container. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- pkg/webhook/v1beta1/pod/inject_webhook.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pkg/webhook/v1beta1/pod/inject_webhook.go b/pkg/webhook/v1beta1/pod/inject_webhook.go index db01fca5d44..6cba7a2647b 100644 --- a/pkg/webhook/v1beta1/pod/inject_webhook.go +++ b/pkg/webhook/v1beta1/pod/inject_webhook.go @@ -141,14 +141,14 @@ func (s *SidecarInjector) Mutate(pod *v1.Pod, namespace string) (*v1.Pod, error) // Add Katib Trial labels to the Pod metadata. mutatePodMetadata(mutatedPod, trial) - - // Pass env variable KATIB_TRIAL_NAME to training containers using fieldPath. - for idx := range mutatedPod.Spec.Containers { - if mutatedPod.Spec.Containers[idx].Env == nil { - mutatedPod.Spec.Containers[idx].Env = []v1.EnvVar{} + // Pass env variable KATIB_TRIAL_NAME to the primary container using fieldPath. + index := getPrimaryContainerIndex(mutatedPod.Spec.Containers, trial.Spec.PrimaryContainerName) + if index >= 0 { + if mutatedPod.Spec.Containers[index].Env == nil { + mutatedPod.Spec.Containers[index].Env = []v1.EnvVar{} } - mutatedPod.Spec.Containers[idx].Env = append( - mutatedPod.Spec.Containers[idx].Env, + mutatedPod.Spec.Containers[index].Env = append( + mutatedPod.Spec.Containers[index].Env, v1.EnvVar{ Name: consts.EnvTrialName, ValueFrom: &v1.EnvVarSource{ @@ -158,6 +158,9 @@ func (s *SidecarInjector) Mutate(pod *v1.Pod, namespace string) (*v1.Pod, error) }, }, ) + } else { + return nil, fmt.Errorf("Unable to find primary container %v in mutated pod containers %v", + trial.Spec.PrimaryContainerName, pod.Spec.Containers) } // Do the following mutation only for the Primary pod. From e73826f1d891acbe3cce8bb5d63227e3287329c0 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Fri, 12 Jul 2024 15:20:40 +0000 Subject: [PATCH 08/13] chore: add report_metrics in post_gen.py. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- hack/gen-python-sdk/post_gen.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hack/gen-python-sdk/post_gen.py b/hack/gen-python-sdk/post_gen.py index b61021edeab..a0d1649d205 100644 --- a/hack/gen-python-sdk/post_gen.py +++ b/hack/gen-python-sdk/post_gen.py @@ -41,6 +41,8 @@ def _rewrite_helper(input_file, output_file, rewrite_rules): if (output_file == "sdk/python/v1beta1/kubeflow/katib/__init__.py"): lines.append("# Import Katib API client.\n") lines.append("from kubeflow.katib.api.katib_client import KatibClient\n") + lines.append("# Import Katib report metrics functions") + lines.append("from kubeflow.katib.api.report_metrics import report_metrics") lines.append("# Import Katib helper functions.\n") lines.append("import kubeflow.katib.api.search as search\n") lines.append("# Import Katib helper constants.\n") From 93df4a9479ff568d0ba152f4eda24b5be2038c60 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Fri, 12 Jul 2024 15:27:37 +0000 Subject: [PATCH 09/13] fix: change nil error to allErrs(deleted by accident). Signed-off-by: Electronic-Waste <2690692950@qq.com> --- pkg/webhook/v1beta1/experiment/validator/validator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/webhook/v1beta1/experiment/validator/validator.go b/pkg/webhook/v1beta1/experiment/validator/validator.go index cf865fe529e..56bde4b0621 100644 --- a/pkg/webhook/v1beta1/experiment/validator/validator.go +++ b/pkg/webhook/v1beta1/experiment/validator/validator.go @@ -489,7 +489,7 @@ func (g *DefaultValidator) validateMetricsCollector(inst *experimentsv1beta1.Exp // TODO(hougangliu): log warning message if some field will not be used for the metricsCollector kind switch mcKind { case commonapiv1beta1.PushCollector, commonapiv1beta1.StdOutCollector: - return nil + return allErrs case commonapiv1beta1.FileCollector: if mcSpec.Source == nil || mcSpec.Source.FileSystemPath == nil || mcSpec.Source.FileSystemPath.Kind != commonapiv1beta1.FileKind || !filepath.IsAbs(mcSpec.Source.FileSystemPath.Path) { From 3e83699eeabbd3e99bce1fc07d0c78f0bc971701 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Fri, 12 Jul 2024 15:35:51 +0000 Subject: [PATCH 10/13] fix: fix lint error in inject_webhook.go. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- pkg/webhook/v1beta1/pod/inject_webhook.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/webhook/v1beta1/pod/inject_webhook.go b/pkg/webhook/v1beta1/pod/inject_webhook.go index 6cba7a2647b..c96ff16cbcc 100644 --- a/pkg/webhook/v1beta1/pod/inject_webhook.go +++ b/pkg/webhook/v1beta1/pod/inject_webhook.go @@ -148,7 +148,7 @@ func (s *SidecarInjector) Mutate(pod *v1.Pod, namespace string) (*v1.Pod, error) mutatedPod.Spec.Containers[index].Env = []v1.EnvVar{} } mutatedPod.Spec.Containers[index].Env = append( - mutatedPod.Spec.Containers[index].Env, + mutatedPod.Spec.Containers[index].Env, v1.EnvVar{ Name: consts.EnvTrialName, ValueFrom: &v1.EnvVarSource{ From c6edd0a9a80b23aa4e10fee712a62d1e95d52e10 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Tue, 16 Jul 2024 08:51:47 +0000 Subject: [PATCH 11/13] fix: wrap env variables passing logics into mutatePodEnv. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- pkg/webhook/v1beta1/pod/inject_webhook.go | 26 +++++----------------- pkg/webhook/v1beta1/pod/utils.go | 27 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/pkg/webhook/v1beta1/pod/inject_webhook.go b/pkg/webhook/v1beta1/pod/inject_webhook.go index c96ff16cbcc..3932a6bbfd3 100644 --- a/pkg/webhook/v1beta1/pod/inject_webhook.go +++ b/pkg/webhook/v1beta1/pod/inject_webhook.go @@ -20,7 +20,6 @@ import ( "context" "encoding/json" "errors" - "fmt" "net/http" "path/filepath" "strconv" @@ -141,26 +140,11 @@ func (s *SidecarInjector) Mutate(pod *v1.Pod, namespace string) (*v1.Pod, error) // Add Katib Trial labels to the Pod metadata. mutatePodMetadata(mutatedPod, trial) - // Pass env variable KATIB_TRIAL_NAME to the primary container using fieldPath. - index := getPrimaryContainerIndex(mutatedPod.Spec.Containers, trial.Spec.PrimaryContainerName) - if index >= 0 { - if mutatedPod.Spec.Containers[index].Env == nil { - mutatedPod.Spec.Containers[index].Env = []v1.EnvVar{} - } - mutatedPod.Spec.Containers[index].Env = append( - mutatedPod.Spec.Containers[index].Env, - v1.EnvVar{ - Name: consts.EnvTrialName, - ValueFrom: &v1.EnvVarSource{ - FieldRef: &v1.ObjectFieldSelector{ - FieldPath: fmt.Sprintf("metadata.labels['%s']", consts.LabelTrialName), - }, - }, - }, - ) - } else { - return nil, fmt.Errorf("Unable to find primary container %v in mutated pod containers %v", - trial.Spec.PrimaryContainerName, pod.Spec.Containers) + // Add env variables to the Pod's primary container. + // We add this function because of push-based metrics collection function `report_metrics` in Python SDK. + // Currently, we only pass the Trial name as env variable `KATIB_TRIAL_NAME` to the training container. + if err := mutatePodEnv(mutatedPod, trial); err != nil { + return nil, err } // Do the following mutation only for the Primary pod. diff --git a/pkg/webhook/v1beta1/pod/utils.go b/pkg/webhook/v1beta1/pod/utils.go index 6381bf6d895..7dad82553cf 100644 --- a/pkg/webhook/v1beta1/pod/utils.go +++ b/pkg/webhook/v1beta1/pod/utils.go @@ -281,6 +281,33 @@ func mutatePodMetadata(pod *v1.Pod, trial *trialsv1beta1.Trial) { pod.Labels = podLabels } +func mutatePodEnv(pod *v1.Pod, trial *trialsv1beta1.Trial) error { + // Search for the primary container + index := getPrimaryContainerIndex(pod.Spec.Containers, trial.Spec.PrimaryContainerName) + if index >= 0 { + if pod.Spec.Containers[index].Env == nil { + pod.Spec.Containers[index].Env = []v1.EnvVar{} + } + + // Pass env variable KATIB_TRIAL_NAME to the primary container using fieldPath + pod.Spec.Containers[index].Env = append( + pod.Spec.Containers[index].Env, + v1.EnvVar{ + Name: consts.EnvTrialName, + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: fmt.Sprintf("metadata.labels['%s']", consts.LabelTrialName), + }, + }, + }, + ) + return nil + } else { + return fmt.Errorf("Unable to find primary container %v in mutated pod containers %v", + trial.Spec.PrimaryContainerName, pod.Spec.Containers) + } +} + func getSidecarContainerName(cKind common.CollectorKind) string { if cKind == common.StdOutCollector || cKind == common.FileCollector { return mccommon.MetricLoggerCollectorContainerName From 7d6a64d9547c5f759bd1910207bcaf05a4747834 Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Tue, 16 Jul 2024 11:38:18 +0000 Subject: [PATCH 12/13] chore: add unit tests for mutatePodEnv. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- .../v1beta1/pod/inject_webhook_test.go | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/pkg/webhook/v1beta1/pod/inject_webhook_test.go b/pkg/webhook/v1beta1/pod/inject_webhook_test.go index ab1646b6769..d55f83172cd 100644 --- a/pkg/webhook/v1beta1/pod/inject_webhook_test.go +++ b/pkg/webhook/v1beta1/pod/inject_webhook_test.go @@ -25,7 +25,10 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/onsi/gomega" + "google.golang.org/protobuf/testing/protocmp" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -1067,3 +1070,103 @@ func TestMutatePodMetadata(t *testing.T) { } } } + +func TestMutatePodEnv(t *testing.T) { + testcases := map[string]struct { + pod *v1.Pod + trial *trialsv1beta1.Trial + mutatedPod *v1.Pod + wantError error + }{ + "Valid case for mutating Pod's env variable": { + pod: &v1.Pod{ + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "training-container", + }, + }, + }, + }, + trial: &trialsv1beta1.Trial{ + Spec: trialsv1beta1.TrialSpec{ + PrimaryContainerName: "training-container", + }, + }, + mutatedPod: &v1.Pod{ + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "training-container", + Env: []v1.EnvVar{ + { + Name: consts.EnvTrialName, + ValueFrom: &v1.EnvVarSource{ + FieldRef: &v1.ObjectFieldSelector{ + FieldPath: fmt.Sprintf("metadata.labels['%s']", consts.LabelTrialName), + }, + }, + }, + }, + }, + }, + }, + }, + }, + "Mismatch for Pod name and primaryContainerName in Trial": { + pod: &v1.Pod{ + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "training-container", + }, + }, + }, + }, + trial: &trialsv1beta1.Trial{ + Spec: trialsv1beta1.TrialSpec{ + PrimaryContainerName: "training-containers", + }, + }, + mutatedPod: &v1.Pod{ + Spec: v1.PodSpec{ + Containers: []v1.Container{ + { + Name: "training-container", + }, + }, + }, + }, + wantError: fmt.Errorf( + "Unable to find primary container %v in mutated pod containers %v", + "training-containers", + []v1.Container{ + { + Name: "training-container", + }, + }, + ), + }, + } + + for name, testcase := range testcases { + t.Run(name, func(t *testing.T) { + err := mutatePodEnv(testcase.pod, testcase.trial) + // Compare error with expected error + if testcase.wantError != nil && err != nil { + if diff := cmp.Diff(testcase.wantError.Error(), err.Error()); len(diff) != 0 { + t.Errorf("Unexpected error (-want,+got):\n%s", diff) + } + } else if testcase.wantError != nil || err != nil { + t.Errorf( + "Unexpected error (-want,+got):\n%s", + cmp.Diff(testcase.wantError, err, cmpopts.EquateErrors()), + ) + } + // Compare Pod with expected pod after mutation + if diff := cmp.Diff(testcase.mutatedPod, testcase.pod, protocmp.Transform()); len(diff) != 0 { + t.Errorf("Unexpected mutated result (-want,+got):\n%s", diff) + } + }) + } +} From d2b0c4852bce239c4655e01520540aaee9e221ad Mon Sep 17 00:00:00 2001 From: Electronic-Waste <2690692950@qq.com> Date: Wed, 17 Jul 2024 05:30:43 +0000 Subject: [PATCH 13/13] fix: delete protocmp. Signed-off-by: Electronic-Waste <2690692950@qq.com> --- pkg/webhook/v1beta1/pod/inject_webhook_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/webhook/v1beta1/pod/inject_webhook_test.go b/pkg/webhook/v1beta1/pod/inject_webhook_test.go index d55f83172cd..4436c10e7f1 100644 --- a/pkg/webhook/v1beta1/pod/inject_webhook_test.go +++ b/pkg/webhook/v1beta1/pod/inject_webhook_test.go @@ -28,7 +28,6 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/onsi/gomega" - "google.golang.org/protobuf/testing/protocmp" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" @@ -1164,7 +1163,7 @@ func TestMutatePodEnv(t *testing.T) { ) } // Compare Pod with expected pod after mutation - if diff := cmp.Diff(testcase.mutatedPod, testcase.pod, protocmp.Transform()); len(diff) != 0 { + if diff := cmp.Diff(testcase.mutatedPod, testcase.pod); len(diff) != 0 { t.Errorf("Unexpected mutated result (-want,+got):\n%s", diff) } })