From 47324f8b0f874657aa0ba3c0cf6d65db990e72d3 Mon Sep 17 00:00:00 2001 From: Kenneth Jenkins <51246568+kenjenkins@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:45:41 -0800 Subject: [PATCH] gateway: new command-line options Introduce an --experimental-gateway-api command-line flag to guard the new Gateway API code paths. Add a --gateway-class-controller-name flag to allow customizing the ControllerName used with GatewayClass objects. When Gateway API support is enabled, initialize the Gateway controllers alongside the existing IngressController and SettingsController. --- cmd/all_in_one.go | 19 +++++++++++++++++-- cmd/common.go | 4 ++++ cmd/controller.go | 14 +++++++++++++- cmd/ingress_opts.go | 25 +++++++++++++++++++++++++ controllers/config_controller.go | 11 +++++++++++ controllers/gateway/controller.go | 16 ++++++++++++++++ 6 files changed, 86 insertions(+), 3 deletions(-) diff --git a/cmd/all_in_one.go b/cmd/all_in_one.go index afc66065..6140476a 100644 --- a/cmd/all_in_one.go +++ b/cmd/all_in_one.go @@ -25,6 +25,7 @@ import ( "github.com/pomerium/pomerium/pkg/netutil" "github.com/pomerium/ingress-controller/controllers" + "github.com/pomerium/ingress-controller/controllers/gateway" "github.com/pomerium/ingress-controller/controllers/ingress" "github.com/pomerium/ingress-controller/controllers/settings" "github.com/pomerium/ingress-controller/pomerium" @@ -50,6 +51,7 @@ type allCmdOptions struct { type allCmdParam struct { settings types.NamespacedName ingressOpts []ingress.Option + gatewayConfig *gateway.ControllerConfig updateStatusFromService string dumpConfigDiff bool @@ -161,9 +163,15 @@ func (s *allCmdOptions) getParam() (*allCmdParam, error) { return nil, fmt.Errorf("options: %w", err) } + gatewayConfig, err := s.getGatewayControllerConfig() + if err != nil { + return nil, fmt.Errorf("options: %w", err) + } + p := &allCmdParam{ settings: *settings, ingressOpts: opts, + gatewayConfig: gatewayConfig, updateStatusFromService: s.UpdateStatusFromService, dumpConfigDiff: s.debugDumpConfigDiff, configControllerShutdownTimeout: s.configControllerShutdownTimeout, @@ -312,6 +320,12 @@ func (s *allCmdParam) buildController(ctx context.Context, cfg *config.Config) ( DebugDumpConfigDiff: s.dumpConfigDiff, RemoveUnreferencedCerts: false, }, + GatewayReconciler: &pomerium.DataBrokerReconciler{ + ConfigID: pomerium.GatewayControllerConfigID, + DataBrokerServiceClient: client, + DebugDumpConfigDiff: s.dumpConfigDiff, + RemoveUnreferencedCerts: false, + }, DataBrokerServiceClient: client, MgrOpts: runtime_ctrl.Options{ Scheme: scheme, @@ -320,8 +334,9 @@ func (s *allCmdParam) buildController(ctx context.Context, cfg *config.Config) ( }, LeaderElection: false, }, - IngressCtrlOpts: s.ingressOpts, - GlobalSettings: &s.settings, + IngressCtrlOpts: s.ingressOpts, + GlobalSettings: &s.settings, + GatewayControllerConfig: s.gatewayConfig, } return c, nil diff --git a/cmd/common.go b/cmd/common.go index 38b3b223..f7ad3035 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -17,6 +17,8 @@ import ( clientgoscheme "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/log/zap" + gateway_v1 "sigs.k8s.io/gateway-api/apis/v1" + gateway_v1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" icsv1 "github.com/pomerium/ingress-controller/apis/ingress/v1" ) @@ -55,6 +57,8 @@ func getScheme() (*runtime.Scheme, error) { }{ {"core", clientgoscheme.AddToScheme}, {"settings", icsv1.AddToScheme}, + {"gateway_v1", gateway_v1.Install}, + {"gateway_v1beta1", gateway_v1beta1.Install}, } { if err := apply.fn(scheme); err != nil { return nil, fmt.Errorf("%s: %w", apply.name, err) diff --git a/cmd/controller.go b/cmd/controller.go index 1189c310..c7d8a3e0 100644 --- a/cmd/controller.go +++ b/cmd/controller.go @@ -129,6 +129,11 @@ func (s *controllerCmd) buildController(ctx context.Context) (*controllers.Contr return nil, fmt.Errorf("ingress controller opts: %w", err) } + gatewayConfig, err := s.getGatewayControllerConfig() + if err != nil { + return nil, fmt.Errorf("gateway controller opts: %w", err) + } + scheme, err := getScheme() if err != nil { return nil, fmt.Errorf("get scheme: %w", err) @@ -153,13 +158,20 @@ func (s *controllerCmd) buildController(ctx context.Context) (*controllers.Contr DebugDumpConfigDiff: s.debug, RemoveUnreferencedCerts: false, }, + GatewayReconciler: &pomerium.DataBrokerReconciler{ + ConfigID: pomerium.GatewayControllerConfigID, + DataBrokerServiceClient: client, + DebugDumpConfigDiff: s.debug, + RemoveUnreferencedCerts: false, + }, DataBrokerServiceClient: client, MgrOpts: ctrl.Options{ Scheme: scheme, Metrics: metricsserver.Options{BindAddress: s.metricsAddr}, LeaderElection: false, }, - IngressCtrlOpts: opts, + IngressCtrlOpts: opts, + GatewayControllerConfig: gatewayConfig, } c.GlobalSettings, err = s.getGlobalSettings() diff --git a/cmd/ingress_opts.go b/cmd/ingress_opts.go index 15c3a40c..0810783c 100644 --- a/cmd/ingress_opts.go +++ b/cmd/ingress_opts.go @@ -8,12 +8,15 @@ import ( "k8s.io/apimachinery/pkg/types" icsv1 "github.com/pomerium/ingress-controller/apis/ingress/v1" + "github.com/pomerium/ingress-controller/controllers/gateway" "github.com/pomerium/ingress-controller/controllers/ingress" "github.com/pomerium/ingress-controller/util" ) type ingressControllerOpts struct { ClassName string `validate:"required"` + GatewayAPIEnabled bool + GatewayClassName string `validate:"required"` AnnotationPrefix string `validate:"required"` Namespaces []string UpdateStatusFromService string `` @@ -22,6 +25,8 @@ type ingressControllerOpts struct { const ( ingressClassControllerName = "name" + experimentalGatewayAPI = "experimental-gateway-api" + gatewayClassControllerName = "gateway-class-controller-name" annotationPrefix = "prefix" namespaces = "namespaces" sharedSecret = "shared-secret" @@ -31,6 +36,8 @@ const ( func (s *ingressControllerOpts) setupFlags(flags *pflag.FlagSet) { flags.StringVar(&s.ClassName, ingressClassControllerName, ingress.DefaultClassControllerName, "IngressClass controller name") + flags.BoolVar(&s.GatewayAPIEnabled, experimentalGatewayAPI, false, "experimental support for the Kubernetes Gateway API") + flags.StringVar(&s.GatewayClassName, gatewayClassControllerName, gateway.DefaultClassControllerName, "GatewayClass controller name") flags.StringVar(&s.AnnotationPrefix, annotationPrefix, ingress.DefaultAnnotationPrefix, "Ingress annotation prefix") flags.StringSliceVar(&s.Namespaces, namespaces, nil, "namespaces to watch, or none to watch all namespaces") flags.StringVar(&s.UpdateStatusFromService, updateStatusFromService, "", "update ingress status from given service status (pomerium-proxy)") @@ -74,3 +81,21 @@ func (s *ingressControllerOpts) getIngressControllerOptions() ([]ingress.Option, } return opts, nil } + +func (s *ingressControllerOpts) getGatewayControllerConfig() (*gateway.ControllerConfig, error) { + if !s.GatewayAPIEnabled { + return nil, nil + } + + cfg := &gateway.ControllerConfig{ + ControllerName: s.GatewayClassName, + } + if s.UpdateStatusFromService != "" { + name, err := util.ParseNamespacedName(s.UpdateStatusFromService) + if err != nil { + return cfg, fmt.Errorf("update status from service: %q: %w", s.UpdateStatusFromService, err) + } + cfg.ServiceName = *name + } + return cfg, nil +} diff --git a/controllers/config_controller.go b/controllers/config_controller.go index d6cf7bdc..bd282af7 100644 --- a/controllers/config_controller.go +++ b/controllers/config_controller.go @@ -15,6 +15,7 @@ import ( "github.com/pomerium/pomerium/pkg/grpc/databroker" + "github.com/pomerium/ingress-controller/controllers/gateway" "github.com/pomerium/ingress-controller/controllers/ingress" "github.com/pomerium/ingress-controller/controllers/reporter" "github.com/pomerium/ingress-controller/controllers/settings" @@ -35,11 +36,14 @@ var ( // for Ingress and Pomerium Settings CRD objects, if specified type Controller struct { pomerium.IngressReconciler + pomerium.GatewayReconciler pomerium.ConfigReconciler databroker.DataBrokerServiceClient MgrOpts runtime_ctrl.Options // IngressCtrlOpts are the ingress controller options IngressCtrlOpts []ingress.Option + // GatewayControllerConfig is the Gateway controller config + GatewayControllerConfig *gateway.ControllerConfig // GlobalSettings if provided, will also reconcile configuration options GlobalSettings *types.NamespacedName @@ -81,6 +85,13 @@ func (c *Controller) RunLeased(ctx context.Context) (err error) { log.FromContext(ctx).V(1).Info("no Pomerium CRD") } + if c.GatewayControllerConfig != nil { + err := gateway.NewControllers(ctx, mgr, c.GatewayReconciler, *c.GatewayControllerConfig) + if err != nil { + return err + } + } + c.setRunning(true) if err = mgr.Start(ctx); err != nil { return fmt.Errorf("running controller: %w", err) diff --git a/controllers/gateway/controller.go b/controllers/gateway/controller.go index b238acb4..23620f42 100644 --- a/controllers/gateway/controller.go +++ b/controllers/gateway/controller.go @@ -30,6 +30,22 @@ type ControllerConfig struct { ServiceName types.NamespacedName } +// NewControllers sets up GatewayClass and Gateway controllers. +func NewControllers( + ctx context.Context, + mgr ctrl.Manager, + pgr pomerium.GatewayReconciler, + config ControllerConfig, +) error { + if err := NewGatewayClassController(mgr, config.ControllerName); err != nil { + return fmt.Errorf("couldn't create GatewayClass controller: %w", err) + } + if err := NewGatewayController(ctx, mgr, pgr, config); err != nil { + return fmt.Errorf("create gateway controller: %w", err) + } + return nil +} + type gatewayController struct { client.Client pomerium.GatewayReconciler