Skip to content

Commit a98cd19

Browse files
committed
feat(logging): enhance L4LBConfig and LoggingConfig with improved validation rules for optionalFields
1 parent 5ec2475 commit a98cd19

File tree

5 files changed

+45
-39
lines changed

5 files changed

+45
-39
lines changed

cmd/glbc/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func main() {
192192
var l4LBConfigClient l4lbconfigclient.Interface
193193
if flags.F.ManageL4LBLogging && (flags.F.RunL4Controller || flags.F.RunL4NetLBController) {
194194
l4LBConfigCRDMeta := l4lbconfig.CRDMeta()
195+
klog.V(0).Info("Ensuring L4LBConfig CRD exists")
195196
if _, err := crdHandler.EnsureCRD(l4LBConfigCRDMeta, true); err != nil {
196197
klog.Fatalf("Failed to ensure L4LBConfig CRD: %v", err)
197198
}

docs/deploy/resources/rbac.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ rules:
4848
resources: ["nodes", "namespaces", "endpoints", "pods"]
4949
verbs: ["get", "list", "watch"]
5050
- apiGroups: ["networking.gke.io"]
51-
resources: ["managedcertificates", "frontendconfigs", "servicenetworkendpointgroups", "gcpingressparams", "serviceattachments", "gkenetworkparamsets", "networks", "gcpfirewalls"]
51+
resources: ["managedcertificates", "frontendconfigs", "servicenetworkendpointgroups", "gcpingressparams", "serviceattachments", "gkenetworkparamsets", "networks", "gcpfirewalls", "l4lbconfigs"]
5252
verbs: ["*"]
5353
- apiGroups: ["networking.gke.io"]
5454
resources: ["nodetopologies"]

pkg/apis/l4lbconfig/v1/types.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ type L4LBConfig struct {
3737
// +k8s:openapi-gen=true
3838
type L4LBConfigSpec struct {
3939
// Logging defines the telemetry and flow logging configuration for the L4 Load Balancer.
40+
// +k8s:validation:cel[0]:rule="(self.optionalMode == 'CUSTOM' && has(self.optionalFields) && size(self.optionalFields) > 0) || (self.optionalMode != 'CUSTOM' && (!has(self.optionalFields) || size(self.optionalFields) == 0))"
41+
// +k8s:validation:cel[0]:message="optionalFields can only be set when optionalMode is 'CUSTOM', and must be set when optionalMode is 'CUSTOM'"
4042
// +optional
4143
Logging *LoggingConfig `json:"logging,omitempty"`
4244
}
@@ -57,7 +59,6 @@ type L4LBConfigList struct {
5759
}
5860

5961
// LoggingConfig defines the parameters for LB logging.
60-
// +kubebuilder:validation:XValidation:rule="has(self.optionalFields) && size(self.optionalFields) > 0 ? self.optionalMode == 'CUSTOM' : true",message="optionalFields can only be set when optionalMode is 'CUSTOM'"
6162
// +k8s:openapi-gen=true
6263
type LoggingConfig struct {
6364
// Enabled allows toggling of Cloud Logging.
@@ -66,20 +67,29 @@ type LoggingConfig struct {
6667

6768
// SampleRate is the percentage of flows to log, from 0 to 1000000.
6869
// 1000000 means 100% of packets are logged.
69-
// +kubebuilder:validation:Minimum=0
70-
// +kubebuilder:validation:Maximum=1000000
70+
// +k8s:validation:maximum=1000000
71+
// +k8s:validation:minimum=0
7172
// +optional
7273
SampleRate *int32 `json:"sampleRate,omitempty"`
7374

7475
// OptionalMode defines which metadata fields to include in the logs.
7576
// Options: INCLUDE_ALL_OPTIONAL, EXCLUDE_ALL_OPTIONAL, CUSTOM.
76-
// +kubebuilder:validation:Enum=INCLUDE_ALL_OPTIONAL;EXCLUDE_ALL_OPTIONAL;CUSTOM
7777
// +optional
78-
OptionalMode string `json:"optionalMode,omitempty"`
78+
OptionalMode LoggingOptionalMode `json:"optionalMode,omitempty"`
7979

8080
// OptionalFields is a list of additional metadata fields to include.
8181
// Only valid when optionalMode is set to 'CUSTOM'.
8282
// +listType=set
8383
// +optional
8484
OptionalFields []string `json:"optionalFields,omitempty"`
8585
}
86+
87+
// +k8s:openapi-gen=true
88+
// +enum
89+
type LoggingOptionalMode string
90+
91+
const (
92+
LoggingOptionalModeIncludeAllOptional = LoggingOptionalMode("INCLUDE_ALL_OPTIONAL")
93+
LoggingOptionalModeExcludeAllOptional = LoggingOptionalMode("EXCLUDE_ALL_OPTIONAL")
94+
LoggingOptionalModeCustom = LoggingOptionalMode("CUSTOM")
95+
)

pkg/apis/l4lbconfig/v1/zz_generated.openapi.go

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/l4lbconfig/l4lbconfig.go

Lines changed: 18 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,13 @@ import (
2828
"k8s.io/ingress-gce/pkg/crd"
2929
"k8s.io/ingress-gce/pkg/flags"
3030
"k8s.io/ingress-gce/pkg/l4annotations"
31-
common "k8s.io/kube-openapi/pkg/common"
3231
)
3332

3433
var (
35-
ErrL4LBConfigDoesNotExist = errors.New("no L4LBConfig for service port exists.")
36-
ErrL4LBConfigFailedToGet = errors.New("client had error getting L4LBConfig for service.")
37-
ErrL4LBConfigInvalidMode = errors.New("invalid OptionalMode in L4LBConfig for service.")
38-
allowedOptionalModes = []interface{}{"INCLUDE_ALL_OPTIONAL", "EXCLUDE_ALL_OPTIONAL", "CUSTOM"}
34+
ErrL4LBConfigDoesNotExist = errors.New("no L4LBConfig for service port exists.")
35+
ErrL4LBConfigFailedToGet = errors.New("client had error getting L4LBConfig for service.")
36+
ErrL4LBConfigInvalidMode = errors.New("invalid OptionalMode in L4LBConfig for service.")
37+
ErrL4LBConfigInvalidSampleRate = errors.New("invalid SampleRate in L4LBConfig for service.")
3938
)
4039

4140
const (
@@ -52,6 +51,8 @@ const (
5251
minSampleRate = 0.0
5352
// defaultSampleRate is the default value for composite.BackendServiceLogConfig.SampleRate when not specified.
5453
defaultSampleRate = 1.0
54+
// maxResolvedSampleRate is the maximum allowed value for the resolved SampleRate after conversion (100% as a decimal).
55+
maxResolvedSampleRate = 1.0
5556
)
5657

5758
func CRDMeta() *crd.CRDMeta {
@@ -62,37 +63,12 @@ func CRDMeta() *crd.CRDMeta {
6263
"l4lbconfig",
6364
"l4lbconfigs",
6465
[]*crd.Version{
65-
crd.NewVersion("v1", "k8s.io/ingress-gce/pkg/apis/l4lbconfig/v1.L4LBConfig", getOpenAPIDefinitions, false),
66+
crd.NewVersion("v1", "k8s.io/ingress-gce/pkg/apis/l4lbconfig/v1.L4LBConfig", l4lbconfigv1.GetOpenAPIDefinitions, false),
6667
},
6768
)
6869
return meta
6970
}
7071

71-
func getOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition {
72-
defs := l4lbconfigv1.GetOpenAPIDefinitions(ref)
73-
74-
if def, ok := defs["k8s.io/ingress-gce/pkg/apis/l4lbconfig/v1.LoggingConfig"]; ok {
75-
// Patch SampleRate
76-
if prop, ok := def.Schema.SchemaProps.Properties["sampleRate"]; ok {
77-
min := minSampleRate
78-
max := maxSampleRate
79-
prop.SchemaProps.Minimum = &min
80-
prop.SchemaProps.Maximum = &max
81-
def.Schema.SchemaProps.Properties["sampleRate"] = prop
82-
}
83-
84-
// Patch OptionalMode (Enum)
85-
if prop, ok := def.Schema.SchemaProps.Properties["optionalMode"]; ok {
86-
prop.SchemaProps.Enum = allowedOptionalModes
87-
def.Schema.SchemaProps.Properties["optionalMode"] = prop
88-
}
89-
90-
defs["k8s.io/ingress-gce/pkg/apis/l4lbconfig/v1.LoggingConfig"] = def
91-
}
92-
93-
return defs
94-
}
95-
9672
// GetL4LBConfigForService returns the corresponding L4LBConfig for
9773
// the given Service if specified.
9874
func GetL4LBConfigForService(l4lbConfigLister cache.Store, svc *corev1.Service) (*l4lbconfigv1.L4LBConfig, error) {
@@ -152,18 +128,22 @@ func DetermineL4LoggingConfig(
152128
OptionalFields: slc.OptionalFields,
153129
}
154130

155-
resolvedConfig.OptionalMode = slc.OptionalMode
131+
resolvedConfig.OptionalMode = string(slc.OptionalMode)
156132
if resolvedConfig.OptionalMode == "" { // Set default if not specified
157133
resolvedConfig.OptionalMode = "EXCLUDE_ALL_OPTIONAL"
158134
}
159135

136+
// Double-check OptionalMode validity before proceeding with OptionalFields checks
137+
// Validation already occurs at the API level, but this serves as a safeguard against any unexpected values.
160138
switch resolvedConfig.OptionalMode {
161139
case "EXCLUDE_ALL_OPTIONAL", "INCLUDE_ALL_OPTIONAL", "CUSTOM":
162140
// Valid
163141
default:
164142
return nil, NewConditionLoggingInvalid(ErrL4LBConfigInvalidMode), ErrL4LBConfigInvalidMode
165143
}
166144

145+
// Double-check consistency between OptionalMode and OptionalFields
146+
// Validation already occurs at the API level, but this serves as a safeguard against any unexpected states.
167147
if resolvedConfig.OptionalMode != "CUSTOM" && len(resolvedConfig.OptionalFields) > 0 {
168148
return nil, NewConditionLoggingInvalid(ErrL4LBConfigInvalidMode), ErrL4LBConfigInvalidMode
169149
}
@@ -178,6 +158,12 @@ func DetermineL4LoggingConfig(
178158
resolvedConfig.SampleRate = defaultSampleRate
179159
}
180160

161+
// Doube-check SampleRate validity before returning the resolved config
162+
// Validation already occurs at the API level, but this serves as a safeguard against any unexpected values.
163+
if resolvedConfig.SampleRate < minSampleRate || resolvedConfig.SampleRate > maxResolvedSampleRate {
164+
return nil, NewConditionLoggingInvalid(ErrL4LBConfigInvalidSampleRate), ErrL4LBConfigInvalidSampleRate
165+
}
166+
181167
return resolvedConfig, NewConditionLoggingReconciled(), nil
182168
}
183169

0 commit comments

Comments
 (0)