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
32 changes: 30 additions & 2 deletions cmd/thv-operator/api/v1alpha1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,45 @@
package v1alpha1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// GroupVersion is group version used to register these objects.
GroupVersion = schema.GroupVersion{Group: "toolhive.stacklok.dev", Version: "v1alpha1"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
SchemeBuilder = newSchemeBuilder(GroupVersion)

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

type schemeBuilder struct {
runtime.SchemeBuilder
GroupVersion schema.GroupVersion
}

func newSchemeBuilder(groupVersion schema.GroupVersion) *schemeBuilder {
builder := &schemeBuilder{GroupVersion: groupVersion}
builder.SchemeBuilder.Register(func(scheme *runtime.Scheme) error {
metav1.AddToGroupVersion(scheme, groupVersion)
return nil
})
return builder
}

func (builder *schemeBuilder) Register(objects ...runtime.Object) *schemeBuilder {
builder.SchemeBuilder.Register(func(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(builder.GroupVersion, objects...)
return nil
})
return builder
}

func (builder *schemeBuilder) Build() (*runtime.Scheme, error) {
scheme := runtime.NewScheme()
return scheme, builder.AddToScheme(scheme)
}
32 changes: 30 additions & 2 deletions cmd/thv-operator/api/v1beta1/groupversion_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,45 @@
package v1beta1

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "toolhive.stacklok.dev", Version: "v1beta1"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
SchemeBuilder = newSchemeBuilder(GroupVersion)

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)

type schemeBuilder struct {
runtime.SchemeBuilder
GroupVersion schema.GroupVersion
}

func newSchemeBuilder(groupVersion schema.GroupVersion) *schemeBuilder {
builder := &schemeBuilder{GroupVersion: groupVersion}
builder.SchemeBuilder.Register(func(scheme *runtime.Scheme) error {
metav1.AddToGroupVersion(scheme, groupVersion)
return nil
})
return builder
}

func (builder *schemeBuilder) Register(objects ...runtime.Object) *schemeBuilder {
builder.SchemeBuilder.Register(func(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(builder.GroupVersion, objects...)
return nil
})
return builder
}

func (builder *schemeBuilder) Build() (*runtime.Scheme, error) {
scheme := runtime.NewScheme()
return scheme, builder.AddToScheme(scheme)
}
88 changes: 84 additions & 4 deletions cmd/thv-operator/internal/testutil/scheme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"

mcpv1alpha1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1alpha1"
mcpv1beta1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1beta1"
Expand All @@ -22,10 +25,63 @@ func TestNewScheme_RegistersOperatorAndBuiltinTypes(t *testing.T) {
scheme := NewScheme(t)

// Operator API versions.
assert.True(t, scheme.Recognizes(mcpv1beta1.GroupVersion.WithKind("MCPServer")),
"v1beta1 MCPServer must be registered")
assert.True(t, scheme.Recognizes(mcpv1alpha1.GroupVersion.WithKind("MCPServer")),
"v1alpha1 MCPServer must be registered")
apiVersions := []struct {
name string
groupVersion schema.GroupVersion
rootKinds []string
}{
{
name: "v1alpha1",
groupVersion: mcpv1alpha1.GroupVersion,
rootKinds: []string{
"EmbeddingServer",
"MCPAuthzConfig",
"MCPExternalAuthConfig",
"MCPGroup",
"MCPOIDCConfig",
"MCPRegistry",
"MCPRemoteProxy",
"MCPServer",
"MCPServerEntry",
"MCPTelemetryConfig",
"MCPWebhookConfig",
"MCPToolConfig",
"VirtualMCPCompositeToolDefinition",
"VirtualMCPServer",
},
},
{
name: "v1beta1",
groupVersion: mcpv1beta1.GroupVersion,
rootKinds: []string{
"EmbeddingServer",
"MCPAuthzConfig",
"MCPExternalAuthConfig",
"MCPGroup",
"MCPOIDCConfig",
"MCPRegistry",
"MCPRemoteProxy",
"MCPServer",
"MCPServerEntry",
"MCPTelemetryConfig",
"MCPToolConfig",
"VirtualMCPCompositeToolDefinition",
"VirtualMCPServer",
},
},
}
for _, apiVersion := range apiVersions {
t.Run(apiVersion.name, func(t *testing.T) {
t.Parallel()

for _, rootKind := range apiVersion.rootKinds {
for _, kind := range []string{rootKind, rootKind + "List"} {
assert.True(t, scheme.Recognizes(apiVersion.groupVersion.WithKind(kind)),
"%s %s must be registered", apiVersion.name, kind)
}
}
})
}

// Built-in Kubernetes types pulled in via client-go's scheme.
assert.True(t, scheme.Recognizes(corev1.SchemeGroupVersion.WithKind("ConfigMap")),
Expand All @@ -36,6 +92,30 @@ func TestNewScheme_RegistersOperatorAndBuiltinTypes(t *testing.T) {
"rbacv1 Role must be registered")
}

func TestSchemeBuilderBuild_RegistersTypes(t *testing.T) {
t.Parallel()

tests := []struct {
name string
groupVersion schema.GroupVersion
build func() (*runtime.Scheme, error)
}{
{"v1alpha1", mcpv1alpha1.GroupVersion, mcpv1alpha1.SchemeBuilder.Build},
{"v1beta1", mcpv1beta1.GroupVersion, mcpv1beta1.SchemeBuilder.Build},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()

scheme, err := test.build()
require.NoError(t, err)
assert.True(t, scheme.Recognizes(test.groupVersion.WithKind("MCPServer")))
assert.True(t, scheme.Recognizes(test.groupVersion.WithKind("MCPServerList")))
assert.True(t, scheme.Recognizes(test.groupVersion.WithKind("WatchEvent")))
})
}
}

func TestNewScheme_AppliesExtraAddersOnTopOfDefault(t *testing.T) {
t.Parallel()

Expand Down
9 changes: 4 additions & 5 deletions cmd/thv-operator/pkg/controllerutil/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@ import (

"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/dump"
"k8s.io/utils/dump"
"sigs.k8s.io/controller-runtime/pkg/client"

mcpv1beta1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1beta1"
)

// CalculateConfigHash calculates a hash of any configuration spec using Kubernetes utilities.
// This function uses k8s.io/apimachinery/pkg/util/dump.ForHash which is designed for
// generating consistent string representations for hashing in Kubernetes.
// This function uses k8s.io/utils/dump.ForHash, which is designed for generating
// consistent string representations for hashing in Kubernetes.
// It then applies FNV-1a hash which is commonly used in Kubernetes for fast hashing.
// See: https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/controller_utils.go
func CalculateConfigHash[T any](spec T) string {
// Use k8s.io/apimachinery/pkg/util/dump.ForHash which is designed for
// generating consistent string representations for hashing in Kubernetes
// Generate a consistent string representation for hashing in Kubernetes.
hashString := dump.ForHash(spec)

// Use FNV-1a hash which is commonly used in Kubernetes for fast hashing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -1573,7 +1575,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -1937,7 +1941,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -4129,7 +4135,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -4374,7 +4382,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -4738,7 +4748,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -348,7 +350,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -361,7 +363,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down Expand Up @@ -378,7 +380,9 @@ spec:
defaults to "ca.crt" for backwards compatibility.
properties:
key:
description: The key to select.
description: |-
The key to select from the ConfigMap's Data field.
Keys in the BinaryData field are not currently propagated to container env vars.
type: string
name:
default: ""
Expand Down
Loading
Loading