diff --git a/internal/experiment/trial_template.go b/internal/experiment/trial_template.go index cfe6238e..c8981227 100644 --- a/internal/experiment/trial_template.go +++ b/internal/experiment/trial_template.go @@ -20,6 +20,7 @@ import ( optimizev1beta2 "github.com/thestormforge/optimize-controller/v2/api/v1beta2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) // PopulateTrialFromTemplate creates a new trial for an experiment @@ -59,4 +60,31 @@ func PopulateTrialFromTemplate(exp *optimizev1beta2.Experiment, t *optimizev1bet if t.Namespace == "" && exp.Spec.NamespaceSelector == nil && exp.Spec.NamespaceTemplate == nil { t.Namespace = exp.Namespace } + + // Constant parameters are only part of the experiment, so they must be added here + for _, p := range exp.Spec.Parameters { + if v := ParameterConstant(p); v != nil { + t.Spec.Assignments = append(t.Spec.Assignments, optimizev1beta2.Assignment{ + Name: p.Name, + Value: *v, + }) + } + } +} + +// ParameterConstant returns the value of the supplied parameter if it is constant. +// A constant parameter has a domain which includes exactly 1 value (i.e. min==max +// for numeric, or len(values)==1 for categorical); these parameters are not processed +// on the server. +func ParameterConstant(p optimizev1beta2.Parameter) *intstr.IntOrString { + switch { + case p.Min == p.Max && len(p.Values) == 0: + v := intstr.FromInt(int(p.Max)) + return &v + case len(p.Values) == 1: + v := intstr.FromString(p.Values[0]) + return &v + default: + return nil + } } diff --git a/internal/server/common.go b/internal/server/common.go index 8f7c34a3..e9ed3a83 100644 --- a/internal/server/common.go +++ b/internal/server/common.go @@ -23,6 +23,7 @@ import ( "strings" optimizev1beta2 "github.com/thestormforge/optimize-controller/v2/api/v1beta2" + "github.com/thestormforge/optimize-controller/v2/internal/experiment" "github.com/thestormforge/optimize-go/pkg/api" experimentsv1alpha1 "github.com/thestormforge/optimize-go/pkg/api/experiments/v1alpha1" "k8s.io/apimachinery/pkg/util/intstr" @@ -52,7 +53,7 @@ func parameters(exp *optimizev1beta2.Experiment) []experimentsv1alpha1.Parameter for _, p := range exp.Spec.Parameters { // This is a special case to omit parameters client side - if p.Min == p.Max && len(p.Values) == 0 { + if experiment.ParameterConstant(p) != nil { continue } diff --git a/internal/server/server_test.go b/internal/server/server_test.go index e16cf6fa..4b67421f 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -222,7 +222,7 @@ func TestFromCluster(t *testing.T) { Parameters: []optimizev1beta2.Parameter{ {Name: "one", Min: 0, Max: 1, Baseline: &one}, {Name: "two", Min: 0, Max: 2, Baseline: &two}, - {Name: "three", Values: []string{"three"}, Baseline: &three}, + {Name: "three", Values: []string{"three", "four"}, Baseline: &three}, }, }, }, @@ -241,7 +241,7 @@ func TestFromCluster(t *testing.T) { { Type: experimentsv1alpha1.ParameterTypeCategorical, Name: "three", - Values: []string{"three"}, + Values: []string{"three", "four"}, }, }, },