Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions apix/config/v1alpha1/bodybasedroutingconfig_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
Copyright 2025 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha1

import (
"encoding/json"
"fmt"
"strings"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +kubebuilder:object:root=true

// BodyBasedRoutingConfig is the Schema for the bodybasedroutingconfigs API.
// It defines the plugins and request/response pipelines for the BBR component.
type BodyBasedRoutingConfig struct {
metav1.TypeMeta `json:",inline"`

// +required
// +kubebuilder:validation:Required
// Plugins is the list of plugins that will be instantiated.
Plugins []PluginSpec `json:"plugins"`

// +optional
// Request is the ordered list of plugins to execute on the request path.
// Plugins are executed in the order they appear in this list.
// Each referenced plugin must implement the RequestProcessor interface.
Request []BBRPluginRef `json:"request,omitempty"`

// +optional
// Response is the ordered list of plugins to execute on the response path.
// Plugins are executed in the order they appear in this list.
// Each referenced plugin must implement the ResponseProcessor interface.
Response []BBRPluginRef `json:"response,omitempty"`
}

func (cfg BodyBasedRoutingConfig) String() string {
var parts []string
if len(cfg.Plugins) > 0 {
parts = append(parts, fmt.Sprintf("Plugins: %v", cfg.Plugins))
}
if len(cfg.Request) > 0 {
parts = append(parts, fmt.Sprintf("Request: %v", cfg.Request))
}
if len(cfg.Response) > 0 {
parts = append(parts, fmt.Sprintf("Response: %v", cfg.Response))
}
return "{" + strings.Join(parts, ", ") + "}"
}

// BBRPluginRef references a plugin defined in the Plugins section
// for use in request or response pipelines.
type BBRPluginRef struct {
// +required
// +kubebuilder:validation:Required
// PluginRef specifies a particular Plugin instance to be used in this
// pipeline step. The reference is to the name of an entry of the Plugins
// defined in the configuration's Plugins section.
PluginRef string `json:"pluginRef"`

// +optional
// Parameters are optional runtime parameters for this pipeline step.
// The plugin is responsible for parsing these parameters.
Parameters json.RawMessage `json:"parameters,omitempty"`
}

func (ref BBRPluginRef) String() string {
var parts []string
parts = append(parts, "PluginRef: "+ref.PluginRef)
if len(ref.Parameters) > 0 {
parts = append(parts, "Parameters: "+string(ref.Parameters))
}
return "{" + strings.Join(parts, ", ") + "}"
}
1 change: 1 addition & 0 deletions apix/config/v1alpha1/endpointpickerconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ func (ps PluginSpec) String() string {
// SchedulingProfile contains the information to create a SchedulingProfile
// entry to be used by the scheduler.
type SchedulingProfile struct {
// +required
// +kubebuilder:validation:Required
// Name specifies the name of this SchedulingProfile
Name string `json:"name"`
Expand Down
65 changes: 65 additions & 0 deletions apix/config/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apix/config/v1alpha1/zz_generated.register.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion conformance/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ require (
golang.org/x/sys v0.41.0 // indirect
golang.org/x/term v0.40.0 // indirect
golang.org/x/text v0.34.0 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/time v0.15.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect
google.golang.org/grpc v1.79.3 // indirect
gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions conformance/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM=
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
Expand Down
70 changes: 70 additions & 0 deletions pkg/bbr/config/loader/configloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
Copyright 2025 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package loader

import (
"fmt"

"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"

configapi "sigs.k8s.io/gateway-api-inference-extension/apix/config/v1alpha1"
)

var scheme = runtime.NewScheme()

func init() {
utilruntime.Must(configapi.Install(scheme))
}

// LoadRawConfig parses the raw configuration bytes and applies initial defaults.
// It does not instantiate plugins.
// If configBytes is empty, a default configuration is returned.
func LoadRawConfig(configBytes []byte, logger logr.Logger) (*configapi.BodyBasedRoutingConfig, error) {
var rawConfig *configapi.BodyBasedRoutingConfig
var err error
if len(configBytes) != 0 {
rawConfig, err = decodeRawConfig(configBytes)
if err != nil {
return nil, err
}
logger.Info("Loaded raw configuration", "config", rawConfig.String())
} else {
logger.Info("A configuration wasn't specified. A default one is being used.")
rawConfig = loadDefaultConfig()
logger.Info("Default raw configuration used", "config", rawConfig.String())
}

applyStaticDefaults(rawConfig)

if err := validateConfig(rawConfig); err != nil {
return nil, fmt.Errorf("configuration validation failed: %w", err)
}

return rawConfig, nil
}

func decodeRawConfig(configBytes []byte) (*configapi.BodyBasedRoutingConfig, error) {
cfg := &configapi.BodyBasedRoutingConfig{}
codecs := serializer.NewCodecFactory(scheme, serializer.EnableStrict)
if err := runtime.DecodeInto(codecs.UniversalDecoder(), configBytes, cfg); err != nil {
return nil, fmt.Errorf("failed to decode configuration JSON/YAML: %w", err)
}
return cfg, nil
}
Loading
Loading