Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

k8s gateway extensions: allow customizing translator #9471

Merged
merged 8 commits into from
Jul 24, 2024
Merged
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
6 changes: 6 additions & 0 deletions changelog/v1.18.0-beta11/custom-gwclass-translation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
changelog:
- type: NON_USER_FACING
description: >-
Allow configuring additional gatewayclasses for controller
and customizing Proxy translation based on the gateway class.
Used by GME.
stevenctl marked this conversation as resolved.
Show resolved Hide resolved
9 changes: 4 additions & 5 deletions projects/gateway2/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -41,7 +42,7 @@ const (

type GatewayConfig struct {
Mgr manager.Manager
GWClassName apiv1.ObjectName
GWClasses sets.Set[string]
Dev bool
ControllerName string
AutoProvision bool
Expand All @@ -55,7 +56,7 @@ type GatewayConfig struct {

func NewBaseGatewayController(ctx context.Context, cfg GatewayConfig) error {
log := log.FromContext(ctx)
log.V(5).Info("starting controller", "controllerName", cfg.ControllerName, "gwClassName", cfg.GWClassName)
log.V(5).Info("starting controller", "controllerName", cfg.ControllerName, "GatewayClasses", sets.List(cfg.GWClasses))

controllerBuilder := &controllerBuilder{
cfg: cfg,
Expand Down Expand Up @@ -85,7 +86,6 @@ func NewBaseGatewayController(ctx context.Context, cfg GatewayConfig) error {
controllerBuilder.addVhOptIndexes,
controllerBuilder.addGwParamsIndexes,
)

}

func run(ctx context.Context, funcs ...func(ctx context.Context) error) error {
Expand Down Expand Up @@ -179,7 +179,7 @@ func (c *controllerBuilder) watchGw(ctx context.Context) error {
For(&apiv1.Gateway{}, builder.WithPredicates(predicate.NewPredicateFuncs(func(object client.Object) bool {
// we only care about Gateways that use our GatewayClass
if gw, ok := object.(*apiv1.Gateway); ok {
return gw.Spec.GatewayClassName == c.cfg.GWClassName
return c.cfg.GWClasses.Has(string(gw.Spec.GatewayClassName))
}
return false
}), predicate.GenerationChangedPredicate{}))
Expand Down Expand Up @@ -414,7 +414,6 @@ func (r *controllerReconciler) ReconcileHttpRoutes(ctx context.Context, req ctrl
}

func (r *controllerReconciler) ReconcileReferenceGrants(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {

// reconcile all things?!
r.kick(ctx)
return ctrl.Result{}, nil
Expand Down
52 changes: 28 additions & 24 deletions projects/gateway2/controller/controller_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/solo-io/gloo/projects/gateway2/wellknown"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
Expand All @@ -38,13 +39,18 @@ var (
ctx context.Context
cancel context.CancelFunc

gatewayClassName string
gatewayControllerName string
kubeconfig string
kubeconfig string

gwClasses = sets.New(gatewayClassName, altGatewayClassName)
)

func getAssetsDir() string {
const (
gatewayClassName = "clsname"
altGatewayClassName = "clsname-alt"
gatewayControllerName = "controller/name"
)

func getAssetsDir() string {
assets := ""
if os.Getenv("KUBEBUILDER_ASSETS") == "" {
// set default if not user provided
Expand All @@ -61,9 +67,6 @@ var _ = BeforeSuite(func() {

ctx, cancel = context.WithCancel(context.TODO())

gatewayClassName = "clsname"
gatewayControllerName = "controller/name"

By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{
Expand Down Expand Up @@ -100,38 +103,38 @@ var _ = BeforeSuite(func() {
kubeconfig = generateKubeConfiguration(cfg)
mgr.GetLogger().Info("starting manager", "kubeconfig", kubeconfig)

var gatewayClassObjName api.ObjectName = api.ObjectName(gatewayClassName)

exts, err := extensions.NewK8sGatewayExtensions(ctx, extensions.K8sGatewayExtensionsFactoryParameters{
Mgr: mgr,
})
Expect(err).ToNot(HaveOccurred())
cfg := controller.GatewayConfig{
Mgr: mgr,
ControllerName: gatewayControllerName,
GWClassName: gatewayClassObjName,
GWClasses: gwClasses,
AutoProvision: true,
Kick: func(ctx context.Context) { return },
Extensions: exts,
}
err = controller.NewBaseGatewayController(ctx, cfg)
Expect(err).ToNot(HaveOccurred())

err = k8sClient.Create(ctx, &api.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Name: gatewayClassName,
},
Spec: api.GatewayClassSpec{
ControllerName: api.GatewayController(gatewayControllerName),
ParametersRef: &api.ParametersReference{
Group: api.Group(v1alpha1.GroupVersion.Group),
Kind: api.Kind("GatewayParameters"),
Name: wellknown.DefaultGatewayParametersName,
Namespace: ptr.To(api.Namespace("default")),
for class := range gwClasses {
err = k8sClient.Create(ctx, &api.GatewayClass{
ObjectMeta: metav1.ObjectMeta{
Name: class,
},
},
})
Expect(err).NotTo(HaveOccurred())
Spec: api.GatewayClassSpec{
ControllerName: api.GatewayController(gatewayControllerName),
ParametersRef: &api.ParametersReference{
Group: api.Group(v1alpha1.GroupVersion.Group),
Kind: api.Kind("GatewayParameters"),
Name: wellknown.DefaultGatewayParametersName,
stevenctl marked this conversation as resolved.
Show resolved Hide resolved
Namespace: ptr.To(api.Namespace("default")),
},
},
})
Expect(err).NotTo(HaveOccurred())
}

err = k8sClient.Create(ctx, &v1alpha1.GatewayParameters{
ObjectMeta: metav1.ObjectMeta{
Expand Down Expand Up @@ -170,6 +173,7 @@ func TestController(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controller Suite")
}

func generateKubeConfiguration(restconfig *rest.Config) string {
clusters := make(map[string]*clientcmdapi.Cluster)
authinfos := make(map[string]*clientcmdapi.AuthInfo)
Expand Down
122 changes: 63 additions & 59 deletions projects/gateway2/controller/gw_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,70 +17,74 @@ var _ = Describe("GwController", func() {
interval = time.Millisecond * 250
)

It("should add status to gateway", func() {
same := api.NamespacesFromSame
gw := api.Gateway{
ObjectMeta: metav1.ObjectMeta{
Name: "gw",
Namespace: "default",
},
Spec: api.GatewaySpec{
GatewayClassName: api.ObjectName(gatewayClassName),
Listeners: []api.Listener{{
Protocol: "HTTP",
Port: 80,
AllowedRoutes: &api.AllowedRoutes{
Namespaces: &api.RouteNamespaces{
From: &same,
DescribeTable(
"should add status to gateway",
func(gwClass string) {
same := api.NamespacesFromSame
gwName := "gw-" + gwClass
gw := api.Gateway{
ObjectMeta: metav1.ObjectMeta{
Name: gwName,
Namespace: "default",
},
Spec: api.GatewaySpec{
GatewayClassName: api.ObjectName(gwClass),
Listeners: []api.Listener{{
Protocol: "HTTP",
Port: 80,
AllowedRoutes: &api.AllowedRoutes{
Namespaces: &api.RouteNamespaces{
From: &same,
},
},
},
Name: "listener",
}},
},
}
err := k8sClient.Create(ctx, &gw)
Expect(err).NotTo(HaveOccurred())

// Wait for service to be created
var svc corev1.Service
Eventually(func() bool {
var createdServices corev1.ServiceList
err := k8sClient.List(ctx, &createdServices)
if err != nil {
return false
}
for _, svc = range createdServices.Items {
if len(svc.ObjectMeta.OwnerReferences) == 1 && svc.ObjectMeta.OwnerReferences[0].UID == gw.UID {
return true
}
Name: "listener",
}},
},
}
return false
}, timeout, interval).Should(BeTrue(), "service not created")
Expect(svc.Spec.ClusterIP).NotTo(BeEmpty())

// Need to update the status of the service
svc.Status.LoadBalancer = corev1.LoadBalancerStatus{
Ingress: []corev1.LoadBalancerIngress{{
IP: "127.0.0.1",
}},
}
Expect(k8sClient.Status().Update(ctx, &svc)).NotTo(HaveOccurred())
err := k8sClient.Create(ctx, &gw)
Expect(err).NotTo(HaveOccurred())

Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Name: "gw", Namespace: "default"}, &gw)
if err != nil {
return false
}
if len(gw.Status.Addresses) == 0 {
// Wait for service to be created
var svc corev1.Service
Eventually(func() bool {
var createdServices corev1.ServiceList
err := k8sClient.List(ctx, &createdServices)
if err != nil {
return false
}
for _, svc = range createdServices.Items {
if len(svc.ObjectMeta.OwnerReferences) == 1 && svc.ObjectMeta.OwnerReferences[0].UID == gw.UID {
return true
}
}
return false
}
return true
}, timeout, interval).Should(BeTrue())
}, timeout, interval).Should(BeTrue(), "service not created")
Expect(svc.Spec.ClusterIP).NotTo(BeEmpty())

Expect(gw.Status.Addresses).To(HaveLen(1))
Expect(*gw.Status.Addresses[0].Type).To(Equal(api.IPAddressType))
Expect(gw.Status.Addresses[0].Value).To(Equal("127.0.0.1"))
// Need to update the status of the service
svc.Status.LoadBalancer = corev1.LoadBalancerStatus{
Ingress: []corev1.LoadBalancerIngress{{
IP: "127.0.0.1",
}},
}
Expect(k8sClient.Status().Update(ctx, &svc)).NotTo(HaveOccurred())

})
Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Name: gwName, Namespace: "default"}, &gw)
if err != nil {
return false
}
if len(gw.Status.Addresses) == 0 {
return false
}
return true
}, timeout, interval).Should(BeTrue())

Expect(gw.Status.Addresses).To(HaveLen(1))
Expect(*gw.Status.Addresses[0].Type).To(Equal(api.IPAddressType))
Expect(gw.Status.Addresses[0].Value).To(Equal("127.0.0.1"))
},
Entry("default gateway class", gatewayClassName),
Entry("alternative gateway class", altGatewayClassName),
)
})
19 changes: 8 additions & 11 deletions projects/gateway2/controller/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ package controller
import (
"context"

"k8s.io/apimachinery/pkg/util/sets"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"

gatewayv1 "github.com/solo-io/gloo/projects/gateway/pkg/api/v1"
"github.com/solo-io/gloo/projects/gateway2/controller/scheme"
"github.com/solo-io/gloo/projects/gateway2/extensions"
Expand All @@ -15,11 +21,6 @@ import (
"github.com/solo-io/gloo/projects/gloo/pkg/plugins"
"github.com/solo-io/gloo/projects/gloo/pkg/servers/iosnapshot"
"github.com/solo-io/solo-kit/pkg/api/v2/reporter"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
apiv1 "sigs.k8s.io/gateway-api/apis/v1"
)

const (
Expand All @@ -28,11 +29,7 @@ const (
AutoProvision = true
)

var (
gatewayClassName = apiv1.ObjectName(wellknown.GatewayClassName)

setupLog = ctrl.Log.WithName("setup")
)
var setupLog = ctrl.Log.WithName("setup")

type StartConfig struct {
Dev bool
Expand Down Expand Up @@ -135,7 +132,7 @@ func Start(ctx context.Context, cfg StartConfig) error {

gwCfg := GatewayConfig{
Mgr: mgr,
GWClassName: gatewayClassName,
GWClasses: sets.New(append(cfg.Opts.ExtraGatewayClasses, wellknown.GatewayClassName)...),
ControllerName: wellknown.GatewayControllerName,
AutoProvision: AutoProvision,
ControlPlane: cfg.Opts.ControlPlane,
Expand Down
Loading
Loading