diff --git a/.github/workflows/build_daily.yaml b/.github/workflows/build_daily.yaml index 51e0243a0d6..630ca6df47b 100644 --- a/.github/workflows/build_daily.yaml +++ b/.github/workflows/build_daily.yaml @@ -88,43 +88,6 @@ jobs: steps: ${{ toJson(steps) }} channel: '#contour-ci-notifications' if: ${{ failure() && github.ref == 'refs/heads/main' }} - e2e-gateway-reconcile-controller: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - persist-credentials: false - - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 - with: - # * Module download cache - # * Build cache (Linux) - path: | - ~/go/pkg/mod - ~/.cache/go-build - key: ${{ runner.os }}-${{ github.job }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-${{ github.job }}-go- - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 - with: - go-version: ${{ env.GO_VERSION }} - cache: false - - name: add deps to path - run: | - ./hack/actions/install-kubernetes-toolchain.sh $GITHUB_WORKSPACE/bin - echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH - - name: e2e tests - env: - CONTOUR_E2E_IMAGE: ghcr.io/projectcontour/contour:main - CONTOUR_E2E_PACKAGE_FOCUS: ./test/e2e/gateway - CONTOUR_E2E_GATEWAY_RECONCILE_MODE: controller - run: | - make setup-kind-cluster run-e2e cleanup-kind - - uses: act10ns/slack@ed1309ab9862e57e9e583e51c7889486b9a00b0f # v2.0.0 - with: - status: ${{ job.status }} - steps: ${{ toJson(steps) }} - channel: '#contour-ci-notifications' - if: ${{ failure() && github.ref == 'refs/heads/main' }} e2e-ipv6: runs-on: ubuntu-latest steps: diff --git a/.mockery.yaml b/.mockery.yaml index 982d25ec923..6aaf094048d 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -5,11 +5,6 @@ outpkg: "mocks" dir: '{{trimPrefix .PackagePath "github.com/projectcontour/contour/" }}/mocks' disable-version-string: True packages: - sigs.k8s.io/controller-runtime/pkg/manager: - config: - dir: "internal/controller/mocks" - interfaces: - Manager: github.com/projectcontour/contour/internal/debug: interfaces: DagBuilder: diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index ff2d73c4590..f7b896bc693 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -154,23 +154,9 @@ type XDSServerConfig struct { // GatewayConfig holds the config for Gateway API controllers. type GatewayConfig struct { - // ControllerName is used to determine whether Contour should reconcile a - // GatewayClass. The string takes the form of "projectcontour.io//contour". - // If unset, the gatewayclass controller will not be started. - // Exactly one of ControllerName or GatewayRef must be set. - // - // Deprecated: users should use GatewayRef, or the Gateway provisioner, - // in place of this field. This field will be removed in a future release. - // +optional - ControllerName string `json:"controllerName,omitempty"` - - // GatewayRef defines a specific Gateway that this Contour - // instance corresponds to. If set, Contour will reconcile - // only this gateway, and will not reconcile any gateway - // classes. - // Exactly one of ControllerName or GatewayRef must be set. - // +optional - GatewayRef *NamespacedName `json:"gatewayRef,omitempty"` + // GatewayRef defines the specific Gateway that this Contour + // instance corresponds to. + GatewayRef NamespacedName `json:"gatewayRef"` } // TLS holds TLS file config details. diff --git a/apis/projectcontour/v1alpha1/contourconfig_helpers.go b/apis/projectcontour/v1alpha1/contourconfig_helpers.go index 0af381adfbc..babadc5bc09 100644 --- a/apis/projectcontour/v1alpha1/contourconfig_helpers.go +++ b/apis/projectcontour/v1alpha1/contourconfig_helpers.go @@ -238,18 +238,10 @@ func (f FeatureFlags) IsEndpointSliceEnabled() bool { return slices.Contains(f, featureFlagUseEndpointSlices) } -// Validate ensures that exactly one of ControllerName or GatewayRef are specified. +// Validate ensures that GatewayRef namespace/name is specified. func (g *GatewayConfig) Validate() error { - if g == nil { - return nil - } - - if len(g.ControllerName) > 0 && g.GatewayRef != nil { - return fmt.Errorf("invalid gateway configuration: exactly one of controller name or gateway ref must be specified") - } - - if len(g.ControllerName) == 0 && g.GatewayRef == nil { - return fmt.Errorf("invalid gateway configuration: exactly one of controller name or gateway ref must be specified") + if g != nil && (g.GatewayRef.Namespace == "" || g.GatewayRef.Name == "") { + return fmt.Errorf("invalid gateway configuration: gateway ref namespace and name must be specified") } return nil diff --git a/apis/projectcontour/v1alpha1/contourconfig_helpers_test.go b/apis/projectcontour/v1alpha1/contourconfig_helpers_test.go index d0ea033aea3..c9b7279c2f6 100644 --- a/apis/projectcontour/v1alpha1/contourconfig_helpers_test.go +++ b/apis/projectcontour/v1alpha1/contourconfig_helpers_test.go @@ -168,15 +168,15 @@ func TestContourConfigurationSpecValidate(t *testing.T) { Gateway: &contour_v1alpha1.GatewayConfig{}, } - c.Gateway.ControllerName = "foo" + c.Gateway.GatewayRef = contour_v1alpha1.NamespacedName{Namespace: "ns", Name: "name"} require.NoError(t, c.Validate()) - c.Gateway.ControllerName = "" - c.Gateway.GatewayRef = &contour_v1alpha1.NamespacedName{Namespace: "ns", Name: "name"} - require.NoError(t, c.Validate()) + // empty namespace is not allowed + c.Gateway.GatewayRef = contour_v1alpha1.NamespacedName{Name: "name"} + require.Error(t, c.Validate()) - c.Gateway.ControllerName = "foo" - c.Gateway.GatewayRef = &contour_v1alpha1.NamespacedName{Namespace: "ns", Name: "name"} + // empty name is not allowed + c.Gateway.GatewayRef = contour_v1alpha1.NamespacedName{Namespace: "ns"} require.Error(t, c.Validate()) }) diff --git a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go index 9e64b85c778..eaa1576bfce 100644 --- a/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go +++ b/apis/projectcontour/v1alpha1/zz_generated.deepcopy.go @@ -884,11 +884,7 @@ func (in FeatureFlags) DeepCopy() FeatureFlags { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayConfig) DeepCopyInto(out *GatewayConfig) { *out = *in - if in.GatewayRef != nil { - in, out := &in.GatewayRef, &out.GatewayRef - *out = new(NamespacedName) - **out = **in - } + out.GatewayRef = in.GatewayRef } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayConfig. diff --git a/changelogs/unreleased/6145-skriss-deprecation.md b/changelogs/unreleased/6145-skriss-deprecation.md new file mode 100644 index 00000000000..168e7666284 --- /dev/null +++ b/changelogs/unreleased/6145-skriss-deprecation.md @@ -0,0 +1,4 @@ +## Configuring Contour with a GatewayClass controller name is no longer supported + +Contour can no longer be configured with a GatewayClass controller name (gateway.controllerName in the config file or ContourConfiguration CRD), as the config field has been removed. +Instead, either use a specific Gateway reference (gateway.gatewayRef), or use the Gateway provisioner. diff --git a/cmd/contour/ingressstatus.go b/cmd/contour/ingressstatus.go index 2204f4c2a22..975fc047181 100644 --- a/cmd/contour/ingressstatus.go +++ b/cmd/contour/ingressstatus.go @@ -49,13 +49,12 @@ import ( // 5. If the worker is stopped, the informer continues but no further // status updates are made. type loadBalancerStatusWriter struct { - log logrus.FieldLogger - cache cache.Cache - lbStatus chan core_v1.LoadBalancerStatus - statusUpdater k8s.StatusUpdater - ingressClassNames []string - gatewayControllerName string - gatewayRef *types.NamespacedName + log logrus.FieldLogger + cache cache.Cache + lbStatus chan core_v1.LoadBalancerStatus + statusUpdater k8s.StatusUpdater + ingressClassNames []string + gatewayRef *types.NamespacedName } func (isw *loadBalancerStatusWriter) NeedLeaderElection() bool { @@ -73,11 +72,10 @@ func (isw *loadBalancerStatusWriter) Start(ctx context.Context) error { return log }(), - Cache: isw.cache, - IngressClassNames: isw.ingressClassNames, - GatewayControllerName: isw.gatewayControllerName, - GatewayRef: isw.gatewayRef, - StatusUpdater: isw.statusUpdater, + Cache: isw.cache, + IngressClassNames: isw.ingressClassNames, + GatewayRef: isw.gatewayRef, + StatusUpdater: isw.statusUpdater, } // Create informers for the types that need load balancer @@ -88,9 +86,9 @@ func (isw *loadBalancerStatusWriter) Start(ctx context.Context) error { &networking_v1.Ingress{}, } - // Only create Gateway informer if a controller or specific gateway was provided, + // Only create Gateway informer if a gateway was provided, // otherwise the API may not exist in the cluster. - if len(isw.gatewayControllerName) > 0 || isw.gatewayRef != nil { + if isw.gatewayRef != nil { resources = append(resources, &gatewayapi_v1.Gateway{}) } @@ -139,9 +137,9 @@ func (isw *loadBalancerStatusWriter) Start(ctx context.Context) error { } } - // Only list Gateways if a controller or specific gateway was configured, + // Only list Gateways if a gateway was configured, // otherwise the API may not exist in the cluster. - if len(isw.gatewayControllerName) > 0 || isw.gatewayRef != nil { + if isw.gatewayRef != nil { var gatewayList gatewayapi_v1.GatewayList if err := isw.cache.List(context.Background(), &gatewayList); err != nil { isw.log.WithError(err).WithField("kind", "Gateway").Error("failed to list objects") diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 1b6142f32f5..4d5bb85ea66 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -43,6 +43,7 @@ import ( controller_runtime_metrics "sigs.k8s.io/controller-runtime/pkg/metrics" controller_runtime_metrics_server "sigs.k8s.io/controller-runtime/pkg/metrics/server" gatewayapi_v1 "sigs.k8s.io/gateway-api/apis/v1" + gatewayapi_v1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gatewayapi_v1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" contour_v1 "github.com/projectcontour/contour/apis/projectcontour/v1" @@ -50,7 +51,6 @@ import ( "github.com/projectcontour/contour/internal/annotation" "github.com/projectcontour/contour/internal/contour" "github.com/projectcontour/contour/internal/contourconfig" - "github.com/projectcontour/contour/internal/controller" "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/debug" envoy_v3 "github.com/projectcontour/contour/internal/envoy/v3" @@ -547,29 +547,18 @@ func (s *Server) doServe() error { return err } - var gatewayControllerName string var gatewayRef *types.NamespacedName if contourConfiguration.Gateway != nil { - // nolint:staticcheck - gatewayControllerName = contourConfiguration.Gateway.ControllerName - - if len(gatewayControllerName) > 0 { - s.log.Warnf("DEPRECATED: gateway.controllerName is deprecated and will be removed in a future release. Use gateway.gatewayRef or the Gateway provisioner instead.") - } - - if contourConfiguration.Gateway.GatewayRef != nil { - gatewayRef = &types.NamespacedName{ - Namespace: contourConfiguration.Gateway.GatewayRef.Namespace, - Name: contourConfiguration.Gateway.GatewayRef.Name, - } + gatewayRef = &types.NamespacedName{ + Namespace: contourConfiguration.Gateway.GatewayRef.Namespace, + Name: contourConfiguration.Gateway.GatewayRef.Name, } } builder := s.getDAGBuilder(dagBuilderConfig{ ingressClassNames: ingressClassNames, rootNamespaces: contourConfiguration.HTTPProxy.RootNamespaces, - gatewayControllerName: gatewayControllerName, gatewayRef: gatewayRef, disablePermitInsecure: *contourConfiguration.HTTPProxy.DisablePermitInsecure, enableExternalNameService: *contourConfiguration.EnableExternalNameService, @@ -653,7 +642,7 @@ func (s *Server) doServe() error { } // Inform on Gateway API resources. - needsNotification := s.setupGatewayAPI(contourConfiguration, s.mgr, eventHandler, sh) + s.setupGatewayAPI(contourConfiguration, eventHandler) // Inform on secrets, filtering by root namespaces. var handler cache.ResourceEventHandler = eventHandler @@ -706,13 +695,12 @@ func (s *Server) doServe() error { // Set up ingress load balancer status writer. lbsw := &loadBalancerStatusWriter{ - log: s.log.WithField("context", "loadBalancerStatusWriter"), - cache: s.mgr.GetCache(), - lbStatus: make(chan core_v1.LoadBalancerStatus, 1), - ingressClassNames: ingressClassNames, - gatewayControllerName: gatewayControllerName, - gatewayRef: gatewayRef, - statusUpdater: sh.Writer(), + log: s.log.WithField("context", "loadBalancerStatusWriter"), + cache: s.mgr.GetCache(), + lbStatus: make(chan core_v1.LoadBalancerStatus, 1), + ingressClassNames: ingressClassNames, + gatewayRef: gatewayRef, + statusUpdater: sh.Writer(), } if err := s.mgr.Add(lbsw); err != nil { return err @@ -756,10 +744,7 @@ func (s *Server) doServe() error { } notifier := &leadership.Notifier{ - ToNotify: append([]leadership.NeedLeaderElectionNotification{ - contourHandler, - observer, - }, needsNotification...), + ToNotify: []leadership.NeedLeaderElectionNotification{contourHandler, observer}, } if err := s.mgr.Add(notifier); err != nil { return err @@ -1027,126 +1012,43 @@ func (s *Server) setupHealth(healthConfig contour_v1alpha1.HealthConfig, return nil } -func (s *Server) setupGatewayAPI(contourConfiguration contour_v1alpha1.ContourConfigurationSpec, - mgr manager.Manager, eventHandler *contour.EventRecorder, sh *k8s.StatusUpdateHandler, -) []leadership.NeedLeaderElectionNotification { - needLeadershipNotification := []leadership.NeedLeaderElectionNotification{} - - // Check if GatewayAPI is configured. - // nolint:staticcheck - if contourConfiguration.Gateway != nil && (contourConfiguration.Gateway.GatewayRef != nil || len(contourConfiguration.Gateway.ControllerName) > 0) { - switch { - // If a specific gateway was specified, we don't need to run the - // GatewayClass and Gateway controllers to determine which gateway - // to process, we just need informers to get events. - case contourConfiguration.Gateway.GatewayRef != nil: - // Inform on GatewayClasses. - if err := s.informOnResource(&gatewayapi_v1.GatewayClass{}, eventHandler); err != nil { - s.log.WithError(err).WithField("resource", "gatewayclasses").Fatal("failed to create informer") - } - - // Inform on Gateways. - if err := s.informOnResource(&gatewayapi_v1.Gateway{}, eventHandler); err != nil { - s.log.WithError(err).WithField("resource", "gateways").Fatal("failed to create informer") - } - // Otherwise, run the GatewayClass and Gateway controllers to determine - // the appropriate gateway class and gateway to process. - default: - // Create and register the gatewayclass controller with the manager. - // nolint:staticcheck - gatewayClassControllerName := contourConfiguration.Gateway.ControllerName - gwClass, err := controller.RegisterGatewayClassController( - s.log.WithField("context", "gatewayclass-controller"), - mgr, - eventHandler, - sh.Writer(), - gatewayClassControllerName, - ) - if err != nil { - s.log.WithError(err).Fatal("failed to create gatewayclass-controller") - } - needLeadershipNotification = append(needLeadershipNotification, gwClass) - - // Create and register the NewGatewayController controller with the manager. - gw, err := controller.RegisterGatewayController( - s.log.WithField("context", "gateway-controller"), - mgr, - eventHandler, - sh.Writer(), - gatewayClassControllerName, - ) - if err != nil { - s.log.WithError(err).Fatal("failed to create gateway-controller") - } - needLeadershipNotification = append(needLeadershipNotification, gw) - } - - // Some features may be disabled. - features := map[string]struct{}{ - "tlsroutes": {}, - "grpcroutes": {}, - "tcproutes": {}, - "backendtlspolicies": {}, - } - for _, f := range s.ctx.disabledFeatures { - delete(features, f) - } - - // Create and register the HTTPRoute controller with the manager. - if err := controller.RegisterHTTPRouteController(s.log.WithField("context", "httproute-controller"), mgr, eventHandler); err != nil { - s.log.WithError(err).Fatal("failed to create httproute-controller") - } - - // Create and register the TLSRoute controller with the manager, if enabled. - if _, enabled := features["tlsroutes"]; enabled { - if err := controller.RegisterTLSRouteController(s.log.WithField("context", "tlsroute-controller"), mgr, eventHandler); err != nil { - s.log.WithError(err).Fatal("failed to create tlsroute-controller") - } +func (s *Server) setupGatewayAPI(contourConfiguration contour_v1alpha1.ContourConfigurationSpec, eventHandler *contour.EventRecorder) { + // Watch resources for Gateway API if enabled. + if contourConfiguration.Gateway != nil { + resources := map[string]client.Object{ + "gatewayclasses": &gatewayapi_v1.GatewayClass{}, + "gateways": &gatewayapi_v1.Gateway{}, + "httproutes": &gatewayapi_v1.HTTPRoute{}, + "referencegrants": &gatewayapi_v1beta1.ReferenceGrant{}, + "namespaces": &core_v1.Namespace{}, + "tlsroutes": &gatewayapi_v1alpha2.TLSRoute{}, + "grpcroutes": &gatewayapi_v1alpha2.GRPCRoute{}, + "tcproutes": &gatewayapi_v1alpha2.TCPRoute{}, + "backendtlspolicies": &gatewayapi_v1alpha2.BackendTLSPolicy{}, + "configmaps": &core_v1.ConfigMap{}, } - // Create and register the GRPCRoute controller with the manager, if enabled. - if _, enabled := features["grpcroutes"]; enabled { - if err := controller.RegisterGRPCRouteController(s.log.WithField("context", "grpcroute-controller"), mgr, eventHandler); err != nil { - s.log.WithError(err).Fatal("failed to create grpcroute-controller") - } - } + for _, disabled := range s.ctx.disabledFeatures { + delete(resources, disabled) - // Create and register the TCPRoute controller with the manager. - if _, enabled := features["tcproutes"]; enabled { - if err := controller.RegisterTCPRouteController(s.log.WithField("context", "tcproute-controller"), mgr, eventHandler); err != nil { - s.log.WithError(err).Fatal("failed to create tcproute-controller") + if disabled == "backendtlspolicies" { + // ConfigMaps are only watched because they're + // used by BackendTLSPolicies. + delete(resources, "configmaps") } } - // Create and register the BackendTLSPolicy controller with the manager. - if _, enabled := features["backendtlspolicies"]; enabled { - // Inform on ConfigMap if BackendTLSPolicy is enabled - if err := s.informOnResource(&core_v1.ConfigMap{}, eventHandler); err != nil { - s.log.WithError(err).WithField("resource", "configmaps").Fatal("failed to create informer") + for name, obj := range resources { + if err := s.informOnResource(obj, eventHandler); err != nil { + s.log.WithError(err).WithField("resource", name).Fatal("failed to create informer") } - - if err := controller.RegisterBackendTLSPolicyController(s.log.WithField("context", "backendtlspolicy-controller"), mgr, eventHandler); err != nil { - s.log.WithError(err).Fatal("failed to create backendtlspolicy-controller") - } - } - - // Inform on ReferenceGrants. - if err := s.informOnResource(&gatewayapi_v1beta1.ReferenceGrant{}, eventHandler); err != nil { - s.log.WithError(err).WithField("resource", "referencegrants").Fatal("failed to create informer") - } - - // Inform on Namespaces. - if err := s.informOnResource(&core_v1.Namespace{}, eventHandler); err != nil { - s.log.WithError(err).WithField("resource", "namespaces").Fatal("failed to create informer") } } - return needLeadershipNotification } type dagBuilderConfig struct { ingressClassNames []string rootNamespaces []string - gatewayControllerName string gatewayRef *types.NamespacedName disablePermitInsecure bool enableExternalNameService bool @@ -1266,7 +1168,7 @@ func (s *Server) getDAGBuilder(dbc dagBuilderConfig) *dag.Builder { }, } - if len(dbc.gatewayControllerName) > 0 || dbc.gatewayRef != nil { + if dbc.gatewayRef != nil { dagProcessors = append(dagProcessors, &dag.GatewayAPIProcessor{ EnableExternalNameService: dbc.enableExternalNameService, FieldLogger: s.log.WithField("context", "GatewayAPIProcessor"), diff --git a/cmd/contour/serve_test.go b/cmd/contour/serve_test.go index 13e6bd4d7b3..53113608ece 100644 --- a/cmd/contour/serve_test.go +++ b/cmd/contour/serve_test.go @@ -133,7 +133,7 @@ func TestGetDAGBuilder(t *testing.T) { log: logrus.StandardLogger(), } got := serve.getDAGBuilder(dagBuilderConfig{ - gatewayControllerName: "projectcontour.io/gateway-controller", + gatewayRef: &types.NamespacedName{Namespace: "projectcontour", Name: "contour"}, rootNamespaces: []string{}, dnsLookupFamily: contour_v1alpha1.AutoClusterDNSFamily, globalCircuitBreakerDefaults: &g, diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index d0c11af843b..3fccce59512 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -296,15 +296,10 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co var gatewayConfig *contour_v1alpha1.GatewayConfig if ctx.Config.GatewayConfig != nil { gatewayConfig = &contour_v1alpha1.GatewayConfig{ - // nolint:staticcheck - ControllerName: ctx.Config.GatewayConfig.ControllerName, - } - - if ctx.Config.GatewayConfig.GatewayRef != nil { - gatewayConfig.GatewayRef = &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: ctx.Config.GatewayConfig.GatewayRef.Namespace, Name: ctx.Config.GatewayConfig.GatewayRef.Name, - } + }, } } diff --git a/cmd/contour/servecontext_test.go b/cmd/contour/servecontext_test.go index af4c03f3ff3..67c1da51d94 100644 --- a/cmd/contour/servecontext_test.go +++ b/cmd/contour/servecontext_test.go @@ -563,24 +563,10 @@ func TestConvertServeContext(t *testing.T) { return cfg }, }, - "gatewayapi - controller": { + "gatewayapi": { getServeContext: func(ctx *serveContext) *serveContext { ctx.Config.GatewayConfig = &config.GatewayParameters{ - ControllerName: "projectcontour.io/gateway-controller", - } - return ctx - }, - getContourConfiguration: func(cfg contour_v1alpha1.ContourConfigurationSpec) contour_v1alpha1.ContourConfigurationSpec { - cfg.Gateway = &contour_v1alpha1.GatewayConfig{ - ControllerName: "projectcontour.io/gateway-controller", - } - return cfg - }, - }, - "gatewayapi - specific gateway": { - getServeContext: func(ctx *serveContext) *serveContext { - ctx.Config.GatewayConfig = &config.GatewayParameters{ - GatewayRef: &config.NamespacedName{ + GatewayRef: config.NamespacedName{ Namespace: "gateway-namespace", Name: "gateway-name", }, @@ -589,7 +575,7 @@ func TestConvertServeContext(t *testing.T) { }, getContourConfiguration: func(cfg contour_v1alpha1.ContourConfigurationSpec) contour_v1alpha1.ContourConfigurationSpec { cfg.Gateway = &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "gateway-namespace", Name: "gateway-name", }, diff --git a/examples/contour/01-contour-config.yaml b/examples/contour/01-contour-config.yaml index 59b89005e15..a2273e9f33a 100644 --- a/examples/contour/01-contour-config.yaml +++ b/examples/contour/01-contour-config.yaml @@ -13,7 +13,8 @@ data: # # Specify the Gateway API configuration. # gateway: - # controllerName: projectcontour.io/gateway-controller + # namespace: projectcontour + # name: contour # # should contour expect to be running inside a k8s cluster # incluster: true diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index 6695ac9b884..e722f3952f5 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -611,22 +611,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -636,6 +624,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- @@ -4306,22 +4296,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -4331,6 +4309,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- diff --git a/examples/gateway/03-gatewayclass.yaml b/examples/gateway/01-gatewayclass.yaml similarity index 100% rename from examples/gateway/03-gatewayclass.yaml rename to examples/gateway/01-gatewayclass.yaml diff --git a/examples/gateway/04-gateway.yaml b/examples/gateway/02-gateway.yaml similarity index 100% rename from examples/gateway/04-gateway.yaml rename to examples/gateway/02-gateway.yaml diff --git a/examples/gateway/03-contour-config.yaml b/examples/gateway/03-contour-config.yaml new file mode 100644 index 00000000000..996af388836 --- /dev/null +++ b/examples/gateway/03-contour-config.yaml @@ -0,0 +1,12 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: contour + namespace: projectcontour +data: + contour.yaml: | + gateway: + gatewayRef: + name: contour + namespace: projectcontour diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 790f7744634..8e55222cf8b 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -46,7 +46,8 @@ data: # # Specify the Gateway API configuration. # gateway: - # controllerName: projectcontour.io/gateway-controller + # namespace: projectcontour + # name: contour # # should contour expect to be running inside a k8s cluster # incluster: true @@ -830,22 +831,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -855,6 +844,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- @@ -4525,22 +4516,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -4550,6 +4529,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index 79a2d1a5830..46a3eea4987 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -622,22 +622,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -647,6 +635,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- @@ -4317,22 +4307,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -4342,6 +4320,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index 48672da8e17..2489a481d34 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -3,7 +3,6 @@ # # Generated from: # examples/contour/00-common.yaml -# examples/contour/01-contour-config.yaml # examples/contour/01-crds.yaml # examples/contour/02-job-certgen.yaml # examples/contour/02-rbac.yaml @@ -13,8 +12,9 @@ # examples/contour/03-contour.yaml # examples/contour/03-envoy.yaml # examples/gateway/00-crds.yaml -# examples/gateway/03-gatewayclass.yaml -# examples/gateway/04-gateway.yaml +# examples/gateway/01-gatewayclass.yaml +# examples/gateway/02-gateway.yaml +# examples/gateway/03-contour-config.yaml --- apiVersion: v1 @@ -34,192 +34,6 @@ metadata: name: envoy namespace: projectcontour ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: contour - namespace: projectcontour -data: - contour.yaml: | - # - # server: - # determine which XDS Server implementation to utilize in Contour. - # xds-server-type: contour - # - # Specify the Gateway API configuration. - gateway: - controllerName: projectcontour.io/gateway-controller - # - # should contour expect to be running inside a k8s cluster - # incluster: true - # - # path to kubeconfig (if not running inside a k8s cluster) - # kubeconfig: /path/to/.kube/config - # - # Disable RFC-compliant behavior to strip "Content-Length" header if - # "Tranfer-Encoding: chunked" is also set. - # disableAllowChunkedLength: false - # - # Disable Envoy's non-standard merge_slashes path transformation option - # that strips duplicate slashes from request URLs. - # disableMergeSlashes: false - # - # Disable HTTPProxy permitInsecure field - disablePermitInsecure: false - tls: - # minimum TLS version that Contour will negotiate - # minimum-protocol-version: "1.2" - # TLS ciphers to be supported by Envoy TLS listeners when negotiating - # TLS 1.2. - # cipher-suites: - # - '[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]' - # - '[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]' - # - 'ECDHE-ECDSA-AES256-GCM-SHA384' - # - 'ECDHE-RSA-AES256-GCM-SHA384' - # Defines the Kubernetes name/namespace matching a secret to use - # as the fallback certificate when requests which don't match the - # SNI defined for a vhost. - fallback-certificate: - # name: fallback-secret-name - # namespace: projectcontour - envoy-client-certificate: - # name: envoy-client-cert-secret-name - # namespace: projectcontour - #### - # ExternalName Services are disabled by default due to CVE-2021-XXXXX - # You can re-enable them by setting this setting to `true`. - # This is not recommended without understanding the security implications. - # Please see the advisory at https://github.com/projectcontour/contour/security/advisories/GHSA-5ph6-qq5x-7jwc for the details. - # enableExternalNameService: false - ## - # Address to be placed in status.loadbalancer field of Ingress objects. - # May be either a literal IP address or a host name. - # The value will be placed directly into the relevant field inside the status.loadBalancer struct. - # ingress-status-address: local.projectcontour.io - ### Logging options - # Default setting - accesslog-format: envoy - # The default access log format is defined by Envoy but it can be customized by setting following variable. - # accesslog-format-string: "...\n" - # To enable JSON logging in Envoy - # accesslog-format: json - # accesslog-level: info - # The default fields that will be logged are specified below. - # To customise this list, just add or remove entries. - # The canonical list is available at - # https://godoc.org/github.com/projectcontour/contour/internal/envoy#JSONFields - # json-fields: - # - "@timestamp" - # - "authority" - # - "bytes_received" - # - "bytes_sent" - # - "downstream_local_address" - # - "downstream_remote_address" - # - "duration" - # - "method" - # - "path" - # - "protocol" - # - "request_id" - # - "requested_server_name" - # - "response_code" - # - "response_flags" - # - "uber_trace_id" - # - "upstream_cluster" - # - "upstream_host" - # - "upstream_local_address" - # - "upstream_service_time" - # - "user_agent" - # - "x_forwarded_for" - # - "grpc_status" - # - "grpc_status_number" - # - # default-http-versions: - # - "HTTP/2" - # - "HTTP/1.1" - # - # The following shows the default proxy timeout settings. - # timeouts: - # request-timeout: infinity - # connection-idle-timeout: 60s - # stream-idle-timeout: 5m - # max-connection-duration: infinity - # delayed-close-timeout: 1s - # connection-shutdown-grace-period: 5s - # connect-timeout: 2s - # - # Envoy cluster settings. - # cluster: - # configure the cluster dns lookup family - # valid options are: auto (default), v4, v6 - # dns-lookup-family: auto - # - # Envoy network settings. - # network: - # Configure the number of additional ingress proxy hops from the - # right side of the x-forwarded-for HTTP header to trust. - # num-trusted-hops: 0 - # Configure the port used to access the Envoy Admin interface. - # admin-port: 9001 - # - # Configure an optional global rate limit service. - # rateLimitService: - # Identifies the extension service defining the rate limit service, - # formatted as /. - # extensionService: projectcontour/ratelimit - # Defines the rate limit domain to pass to the rate limit service. - # Acts as a container for a set of rate limit definitions within - # the RLS. - # domain: contour - # Defines whether to allow requests to proceed when the rate limit - # service fails to respond with a valid rate limit decision within - # the timeout defined on the extension service. - # failOpen: false - # Defines whether to include the X-RateLimit headers X-RateLimit-Limit, - # X-RateLimit-Remaining, and X-RateLimit-Reset (as defined by the IETF - # Internet-Draft linked below), on responses to clients when the Rate - # Limit Service is consulted for a request. - # ref. https://tools.ietf.org/id/draft-polli-ratelimit-headers-03.html - # enableXRateLimitHeaders: false - # Defines whether to translate status code 429 to grpc code RESOURCE_EXHAUSTED - # instead of the default UNAVAILABLE - # enableResourceExhaustedCode: false - # - # Global Policy settings. - # policy: - # # Default headers to set on all requests (unless set/removed on the HTTPProxy object itself) - # request-headers: - # set: - # # example: the hostname of the Envoy instance that proxied the request - # X-Envoy-Hostname: %HOSTNAME% - # # example: add a l5d-dst-override header to instruct Linkerd what service the request is destined for - # l5d-dst-override: %CONTOUR_SERVICE_NAME%.%CONTOUR_NAMESPACE%.svc.cluster.local:%CONTOUR_SERVICE_PORT% - # # default headers to set on all responses (unless set/removed on the HTTPProxy object itself) - # response-headers: - # set: - # # example: Envoy flags that provide additional details about the response or connection - # X-Envoy-Response-Flags: %RESPONSE_FLAGS% - # - # metrics: - # contour: - # address: 0.0.0.0 - # port: 8000 - # server-certificate-path: /path/to/server-cert.pem - # server-key-path: /path/to/server-private-key.pem - # ca-certificate-path: /path/to/root-ca-for-client-validation.pem - # envoy: - # address: 0.0.0.0 - # port: 8002 - # server-certificate-path: /path/to/server-cert.pem - # server-key-path: /path/to/server-private-key.pem - # ca-certificate-path: /path/to/root-ca-for-client-validation.pem - # - # listener: - # connection-balancer: exact - # socket-options: - # tos: 64 - # traffic-class: 64 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -833,22 +647,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -858,6 +660,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- @@ -4528,22 +4332,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -4553,6 +4345,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- @@ -21064,3 +20858,16 @@ spec: allowedRoutes: namespaces: from: All + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: contour + namespace: projectcontour +data: + contour.yaml: | + gateway: + gatewayRef: + name: contour + namespace: projectcontour diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index e2ab3f43ff3..aa7c4c33bbe 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -46,7 +46,8 @@ data: # # Specify the Gateway API configuration. # gateway: - # controllerName: projectcontour.io/gateway-controller + # namespace: projectcontour + # name: contour # # should contour expect to be running inside a k8s cluster # incluster: true @@ -830,22 +831,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -855,6 +844,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- @@ -4525,22 +4516,10 @@ spec: Gateway contains parameters for the gateway-api Gateway that Contour is configured to serve traffic. properties: - controllerName: - description: |- - ControllerName is used to determine whether Contour should reconcile a - GatewayClass. The string takes the form of "projectcontour.io//contour". - If unset, the gatewayclass controller will not be started. - Exactly one of ControllerName or GatewayRef must be set. - Deprecated: users should use GatewayRef, or the Gateway provisioner, - in place of this field. This field will be removed in a future release. - type: string gatewayRef: description: |- - GatewayRef defines a specific Gateway that this Contour - instance corresponds to. If set, Contour will reconcile - only this gateway, and will not reconcile any gateway - classes. - Exactly one of ControllerName or GatewayRef must be set. + GatewayRef defines the specific Gateway that this Contour + instance corresponds to. properties: name: type: string @@ -4550,6 +4529,8 @@ spec: - name - namespace type: object + required: + - gatewayRef type: object globalExtAuth: description: |- diff --git a/hack/generate-gateway-deployment.sh b/hack/generate-gateway-deployment.sh index 75314dea05c..227c2941999 100755 --- a/hack/generate-gateway-deployment.sh +++ b/hack/generate-gateway-deployment.sh @@ -20,6 +20,9 @@ EOF for f in "examples/contour/"*.yaml "examples/gateway/"*.yaml ; do case $f in + examples/contour/01-contour-config.yaml) + # skip + ;; */03-envoy-deployment.yaml) # skip ;; @@ -38,7 +41,7 @@ for y in "${REPO}/examples/contour/"*.yaml ; do # skip ;; */01-contour-config.yaml) - sed 's|# gateway:|gateway:|g ; s|# controllerName: projectcontour.io/gateway-controller| controllerName: projectcontour.io/gateway-controller|g' < "$y" + # skip ;; *) cat $y @@ -48,14 +51,14 @@ done for y in "${REPO}/examples/gateway/"*.yaml ; do echo # Ensure we have at least one newline between joined fragments. - + # Since the Gateway YAMLs are pulled from the Gateway API repo, the manifests do not start with "---". case $y in - */00-crds.yaml) + */00-crds.yaml) echo "---" ;; esac - + cat "$y" done diff --git a/internal/contourconfig/contourconfiguration_test.go b/internal/contourconfig/contourconfiguration_test.go index a93bd3d8941..f78e21ab0a7 100644 --- a/internal/contourconfig/contourconfiguration_test.go +++ b/internal/contourconfig/contourconfiguration_test.go @@ -136,8 +136,7 @@ func TestOverlayOnDefaults(t *testing.T) { }, }, Gateway: &contour_v1alpha1.GatewayConfig{ - ControllerName: "gatewaycontroller", - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "gatewaynamespace", Name: "gatewayname", }, diff --git a/internal/controller/backendtlspolicy.go b/internal/controller/backendtlspolicy.go deleted file mode 100644 index 68365934189..00000000000 --- a/internal/controller/backendtlspolicy.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright Project Contour 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 controller - -import ( - "context" - - "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gatewayapi_v1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" -) - -type backendTLSPolicyReconciler struct { - client client.Client - eventHandler cache.ResourceEventHandler - logrus.FieldLogger -} - -// RegisterBackendTLSPolicyController creates the backendtlspolicy controller from mgr. The controller will be pre-configured -// to watch for BackendTLSPolicy objects across all namespaces. -func RegisterBackendTLSPolicyController(log logrus.FieldLogger, mgr manager.Manager, eventHandler cache.ResourceEventHandler) error { - r := &backendTLSPolicyReconciler{ - client: mgr.GetClient(), - eventHandler: eventHandler, - FieldLogger: log, - } - c, err := controller.NewUnmanaged("backendtlspolicy-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - if err := mgr.Add(&noLeaderElectionController{c}); err != nil { - return err - } - - return c.Watch(source.Kind(mgr.GetCache(), &gatewayapi_v1alpha2.BackendTLSPolicy{}), &handler.EnqueueRequestForObject{}) -} - -func (r *backendTLSPolicyReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - // Fetch the BackendTLSPolicy from the cache. - backendTLSPolicy := &gatewayapi_v1alpha2.BackendTLSPolicy{} - err := r.client.Get(ctx, request.NamespacedName, backendTLSPolicy) - if errors.IsNotFound(err) { - r.eventHandler.OnDelete(&gatewayapi_v1alpha2.BackendTLSPolicy{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: request.Name, - Namespace: request.Namespace, - }, - }) - return reconcile.Result{}, nil - } - - // Pass the new changed object off to the eventHandler. - r.eventHandler.OnAdd(backendTLSPolicy, false) - - return reconcile.Result{}, nil -} diff --git a/internal/controller/controller.go b/internal/controller/controller.go deleted file mode 100644 index a9d572c8e69..00000000000 --- a/internal/controller/controller.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright Project Contour 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 controller - -import "sigs.k8s.io/controller-runtime/pkg/controller" - -// Wrapper for that ensures controller-runtime Controllers -// are run by controller-runtime Manager, regardless of -// leader-election status. Controllers can be created as -// unmanaged and manually registered with a Manager using -// this wrapper, otherwise they will only be run when their -// Manager is elected leader. -type noLeaderElectionController struct { - controller.Controller -} - -func (*noLeaderElectionController) NeedLeaderElection() bool { - return false -} diff --git a/internal/controller/controller_test.go b/internal/controller/controller_test.go deleted file mode 100644 index c8f21117505..00000000000 --- a/internal/controller/controller_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright Project Contour 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 controller_test - -import ( - "testing" - - logr_testing "github.com/go-logr/logr/testing" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "sigs.k8s.io/controller-runtime/pkg/config" - "sigs.k8s.io/controller-runtime/pkg/manager" - - "github.com/projectcontour/contour/internal/controller" - "github.com/projectcontour/contour/internal/controller/mocks" - "github.com/projectcontour/contour/internal/fixture" -) - -func TestRegisterControllers(t *testing.T) { - tests := map[string]func(*mocks.Manager) error{ - "gateway controller": func(mockManager *mocks.Manager) error { - _, err := controller.RegisterGatewayController(fixture.NewTestLogger(t), mockManager, nil, nil, "some-controller") - return err - }, - "gatewayclass controller": func(mockManager *mocks.Manager) error { - _, err := controller.RegisterGatewayClassController(fixture.NewTestLogger(t), mockManager, nil, nil, "some-gateway") - return err - }, - "httproute controller": func(mockManager *mocks.Manager) error { - return controller.RegisterHTTPRouteController(fixture.NewTestLogger(t), mockManager, nil) - }, - "tlsroute controller": func(mockManager *mocks.Manager) error { - return controller.RegisterTLSRouteController(fixture.NewTestLogger(t), mockManager, nil) - }, - "grpcroute controller": func(mockManager *mocks.Manager) error { - return controller.RegisterGRPCRouteController(fixture.NewTestLogger(t), mockManager, nil) - }, - "backendtlspolicy controller": func(mockManager *mocks.Manager) error { - return controller.RegisterBackendTLSPolicyController(fixture.NewTestLogger(t), mockManager, nil) - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - mockManager := &mocks.Manager{} - - // TODO: see if there is a way we can automatically ignore these. - mockManager.On("GetClient").Return(nil).Maybe() - mockManager.On("GetLogger").Return(logr_testing.NewTestLogger(t)).Maybe() - mockManager.On("SetFields", mock.Anything).Return(nil).Maybe() - mockManager.On("Elected").Return(nil).Maybe() - // This type is deprecated and will be removed in future versions of - // controller-runtime. - mockManager.On("GetControllerOptions").Return(config.Controller{}).Maybe() - mockManager.On("GetCache").Return(nil).Maybe() - - mockManager.On("Add", mock.MatchedBy(func(r manager.LeaderElectionRunnable) bool { - return r.NeedLeaderElection() == false - })).Return(nil).Once() - - require.NoError(t, test(mockManager)) - - require.True(t, mockManager.AssertExpectations(t)) - }) - } -} diff --git a/internal/controller/gateway.go b/internal/controller/gateway.go deleted file mode 100644 index 7200dd5b64c..00000000000 --- a/internal/controller/gateway.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright Project Contour 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 controller - -import ( - "context" - "fmt" - "time" - - "github.com/sirupsen/logrus" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gatewayapi_v1 "sigs.k8s.io/gateway-api/apis/v1" - - "github.com/projectcontour/contour/internal/k8s" - "github.com/projectcontour/contour/internal/leadership" -) - -type gatewayReconciler struct { - client client.Client - eventHandler cache.ResourceEventHandler - statusUpdater k8s.StatusUpdater - log logrus.FieldLogger - // gatewayClassControllerName is the configured controller of managed gatewayclasses. - gatewayClassControllerName gatewayapi_v1.GatewayController - eventSource chan event.GenericEvent -} - -// RegisterGatewayController creates the gateway controller from mgr. The controller will be pre-configured -// to watch for Gateway objects across all namespaces and reconcile those that match class. -func RegisterGatewayController( - log logrus.FieldLogger, - mgr manager.Manager, - eventHandler cache.ResourceEventHandler, - statusUpdater k8s.StatusUpdater, - gatewayClassControllerName string, -) (leadership.NeedLeaderElectionNotification, error) { - r := &gatewayReconciler{ - log: log, - client: mgr.GetClient(), - eventHandler: eventHandler, - statusUpdater: statusUpdater, - gatewayClassControllerName: gatewayapi_v1.GatewayController(gatewayClassControllerName), - // Set up a source.Channel that will trigger reconciles - // for all GatewayClasses when this Contour process is - // elected leader, to ensure that their statuses are up - // to date. - eventSource: make(chan event.GenericEvent), - } - c, err := controller.NewUnmanaged("gateway-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return nil, err - } - if err := mgr.Add(&noLeaderElectionController{c}); err != nil { - return nil, err - } - - if err := c.Watch( - source.Kind(mgr.GetCache(), &gatewayapi_v1.Gateway{}), - &handler.EnqueueRequestForObject{}, - predicate.NewPredicateFuncs(r.hasMatchingController), - ); err != nil { - return nil, err - } - - // Watch GatewayClasses and reconcile their associated Gateways - // to handle changes in the GatewayClasses' "Accepted" conditions. - if err := c.Watch( - source.Kind(mgr.GetCache(), &gatewayapi_v1.GatewayClass{}), - handler.EnqueueRequestsFromMapFunc(r.mapGatewayClassToGateways), - predicate.NewPredicateFuncs(r.gatewayClassHasMatchingController), - ); err != nil { - return nil, err - } - - // Set up a source.Channel that will trigger reconciles - // for all Gateways when this Contour process is - // elected leader, to ensure that their statuses are up - // to date. - if err := c.Watch( - &source.Channel{Source: r.eventSource}, - &handler.EnqueueRequestForObject{}, - predicate.NewPredicateFuncs(r.hasMatchingController), - ); err != nil { - return nil, err - } - - return r, nil -} - -func (r *gatewayReconciler) OnElectedLeader() { - r.log.Info("elected leader, triggering reconciles for all gateways") - - var gateways gatewayapi_v1.GatewayList - if err := r.client.List(context.Background(), &gateways); err != nil { - r.log.WithError(err).Error("error listing gateways") - return - } - - for i := range gateways.Items { - r.eventSource <- event.GenericEvent{Object: &gateways.Items[i]} - } -} - -func (r *gatewayReconciler) mapGatewayClassToGateways(ctx context.Context, gatewayClass client.Object) []reconcile.Request { - var gateways gatewayapi_v1.GatewayList - if err := r.client.List(ctx, &gateways); err != nil { - r.log.WithError(err).Error("error listing gateways") - return nil - } - - var reconciles []reconcile.Request - for _, gw := range gateways.Items { - if string(gw.Spec.GatewayClassName) == gatewayClass.GetName() { - reconciles = append(reconciles, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: gw.Namespace, - Name: gw.Name, - }, - }) - } - } - - return reconciles -} - -// hasMatchingController returns true if the provided object is a Gateway -// using a GatewayClass with a Spec.Controller string matching this Contour's -// controller string, or false otherwise. -func (r *gatewayReconciler) hasMatchingController(obj client.Object) bool { - log := r.log.WithFields(logrus.Fields{ - "namespace": obj.GetNamespace(), - "name": obj.GetName(), - }) - - gw, ok := obj.(*gatewayapi_v1.Gateway) - if !ok { - log.Debugf("unexpected object type %T, bypassing reconciliation.", obj) - return false - } - - gc := &gatewayapi_v1.GatewayClass{} - if err := r.client.Get(context.Background(), types.NamespacedName{Name: string(gw.Spec.GatewayClassName)}, gc); err != nil { - log.WithError(err).Errorf("failed to get gatewayclass %s", gw.Spec.GatewayClassName) - return false - } - if gc.Spec.ControllerName != r.gatewayClassControllerName { - log.Debugf("gateway's class controller is not %s; bypassing reconciliation", r.gatewayClassControllerName) - return false - } - - return true -} - -func (r *gatewayReconciler) gatewayClassHasMatchingController(obj client.Object) bool { - gc, ok := obj.(*gatewayapi_v1.GatewayClass) - if !ok { - r.log.Infof("expected GatewayClass, got %T", obj) - return false - } - - return gc.Spec.ControllerName == r.gatewayClassControllerName -} - -// Reconcile finds all the Gateways for the GatewayClass with an "Accepted: true" condition. -// It passes the oldest such Gateway to the DAG for processing, and sets an "Accepted: false" -// condition on all other Gateways for the accepted GatewayClass. -func (r *gatewayReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - r.log.WithField("namespace", request.Namespace).WithField("name", request.Name).Info("reconciling gateway") - - var gatewayClasses gatewayapi_v1.GatewayClassList - if err := r.client.List(ctx, &gatewayClasses); err != nil { - return reconcile.Result{}, fmt.Errorf("error listing gateway classes") - } - - // Find the GatewayClass for this controller with Accepted=true. - var acceptedGatewayClass *gatewayapi_v1.GatewayClass - for i := range gatewayClasses.Items { - gatewayClass := &gatewayClasses.Items[i] - - if gatewayClass.Spec.ControllerName != r.gatewayClassControllerName { - continue - } - if !isAccepted(gatewayClass) { - continue - } - - acceptedGatewayClass = gatewayClass - break - } - - if acceptedGatewayClass == nil { - r.log.Info("No accepted gateway class found") - r.eventHandler.OnDelete(&gatewayapi_v1.Gateway{ - ObjectMeta: meta_v1.ObjectMeta{ - Namespace: request.Namespace, - Name: request.Name, - }, - }) - return reconcile.Result{}, nil - } - - var allGateways gatewayapi_v1.GatewayList - if err := r.client.List(ctx, &allGateways); err != nil { - return reconcile.Result{}, fmt.Errorf("error listing gateways") - } - - // Get all the Gateways for the Accepted=true GatewayClass. - var gatewaysForClass []*gatewayapi_v1.Gateway - for i := range allGateways.Items { - if string(allGateways.Items[i].Spec.GatewayClassName) == acceptedGatewayClass.Name { - gatewaysForClass = append(gatewaysForClass, &allGateways.Items[i]) - } - } - - if len(gatewaysForClass) == 0 { - r.log.Info("No gateways found for accepted gateway class") - r.eventHandler.OnDelete(&gatewayapi_v1.Gateway{ - ObjectMeta: meta_v1.ObjectMeta{ - Namespace: request.Namespace, - Name: request.Name, - }, - }) - return reconcile.Result{}, nil - } - - // Find the oldest Gateway, using alphabetical order - // as a tiebreaker. - var oldest *gatewayapi_v1.Gateway - for _, gw := range gatewaysForClass { - switch { - case oldest == nil: - oldest = gw - case gw.CreationTimestamp.Before(&oldest.CreationTimestamp): - oldest = gw - case gw.CreationTimestamp.Equal(&oldest.CreationTimestamp): - if fmt.Sprintf("%s/%s", gw.Namespace, gw.Name) < fmt.Sprintf("%s/%s", oldest.Namespace, oldest.Name) { - oldest = gw - } - } - } - - // Set the "Accepted" condition to false for all gateways - // except the oldest. The oldest will have its status set - // by the DAG processor, so don't set it here. - for _, gw := range gatewaysForClass { - if gw == oldest { - continue - } - - if r.statusUpdater != nil { - r.statusUpdater.Send(k8s.StatusUpdate{ - NamespacedName: k8s.NamespacedNameOf(gw), - Resource: &gatewayapi_v1.Gateway{}, - Mutator: k8s.StatusMutatorFunc(func(obj client.Object) client.Object { - gw, ok := obj.(*gatewayapi_v1.Gateway) - if !ok { - panic(fmt.Sprintf("unsupported object type %T", obj)) - } - - return setGatewayNotAccepted(gw.DeepCopy()) - }), - }) - } else { - // this branch makes testing easier by not going through the StatusUpdater. - gwCopy := setGatewayNotAccepted(gw.DeepCopy()) - if err := r.client.Status().Update(ctx, gwCopy); err != nil { - r.log.WithError(err).Error("error updating gateway status") - return reconcile.Result{}, fmt.Errorf("error updating status of gateway %s/%s: %v", gw.Namespace, gw.Name, err) - } - } - } - - // TODO: Ensure the gateway by creating manage infrastructure, i.e. the Envoy service. - // xref: https://github.com/projectcontour/contour/issues/3545 - - r.log.WithField("namespace", oldest.Namespace).WithField("name", oldest.Name).Info("assigning gateway to DAG") - r.eventHandler.OnAdd(oldest, false) - return reconcile.Result{}, nil -} - -func isAccepted(gatewayClass *gatewayapi_v1.GatewayClass) bool { - for _, cond := range gatewayClass.Status.Conditions { - if cond.Type == string(gatewayapi_v1.GatewayClassConditionStatusAccepted) && cond.Status == meta_v1.ConditionTrue { - return true - } - } - - return false -} - -func setGatewayNotAccepted(gateway *gatewayapi_v1.Gateway) *gatewayapi_v1.Gateway { - newCond := meta_v1.Condition{ - Type: string(gatewayapi_v1.GatewayConditionAccepted), - Status: meta_v1.ConditionFalse, - Reason: "OlderGatewayExists", - Message: "An older Gateway exists for the accepted GatewayClass", - LastTransitionTime: meta_v1.NewTime(time.Now()), - ObservedGeneration: gateway.Generation, - } - - for i := range gateway.Status.Conditions { - cond := &gateway.Status.Conditions[i] - - if cond.Type != string(gatewayapi_v1.GatewayConditionAccepted) { - continue - } - - // Update only if something has changed. - if cond.Status != newCond.Status || cond.Reason != newCond.Reason || cond.Message != newCond.Message { - cond.Status = newCond.Status - cond.Reason = newCond.Reason - cond.Message = newCond.Message - cond.LastTransitionTime = newCond.LastTransitionTime - cond.ObservedGeneration = newCond.ObservedGeneration - } - - return gateway - } - - gateway.Status.Conditions = append(gateway.Status.Conditions, newCond) - return gateway -} diff --git a/internal/controller/gatewayclass.go b/internal/controller/gatewayclass.go deleted file mode 100644 index 460b043671b..00000000000 --- a/internal/controller/gatewayclass.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright Project Contour 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 controller - -import ( - "context" - "fmt" - - "github.com/sirupsen/logrus" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/event" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/predicate" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gatewayapi_v1 "sigs.k8s.io/gateway-api/apis/v1" - - "github.com/projectcontour/contour/internal/k8s" - "github.com/projectcontour/contour/internal/leadership" - "github.com/projectcontour/contour/internal/status" -) - -type gatewayClassReconciler struct { - client client.Client - eventHandler cache.ResourceEventHandler - statusUpdater k8s.StatusUpdater - log logrus.FieldLogger - controller gatewayapi_v1.GatewayController - eventSource chan event.GenericEvent -} - -// RegisterGatewayClassController creates the gatewayclass controller. The controller -// will be pre-configured to watch for cluster-scoped GatewayClass objects with -// a controller field that matches name. -func RegisterGatewayClassController( - log logrus.FieldLogger, - mgr manager.Manager, - eventHandler cache.ResourceEventHandler, - statusUpdater k8s.StatusUpdater, - name string, -) (leadership.NeedLeaderElectionNotification, error) { - r := &gatewayClassReconciler{ - client: mgr.GetClient(), - eventHandler: eventHandler, - statusUpdater: statusUpdater, - log: log, - controller: gatewayapi_v1.GatewayController(name), - // Set up a source.Channel that will trigger reconciles - // for all GatewayClasses when this Contour process is - // elected leader, to ensure that their statuses are up - // to date. - eventSource: make(chan event.GenericEvent), - } - - c, err := controller.NewUnmanaged("gatewayclass-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return nil, err - } - if err := mgr.Add(&noLeaderElectionController{c}); err != nil { - return nil, err - } - - // Only enqueue GatewayClass objects that match name. - if err := c.Watch( - source.Kind(mgr.GetCache(), &gatewayapi_v1.GatewayClass{}), - &handler.EnqueueRequestForObject{}, - predicate.NewPredicateFuncs(r.hasMatchingController), - ); err != nil { - return nil, err - } - - if err := c.Watch( - &source.Channel{Source: r.eventSource}, - &handler.EnqueueRequestForObject{}, - predicate.NewPredicateFuncs(r.hasMatchingController), - ); err != nil { - return nil, err - } - - return r, nil -} - -func (r *gatewayClassReconciler) OnElectedLeader() { - r.log.Info("elected leader, triggering reconciles for all gatewayclasses") - - var gatewayClasses gatewayapi_v1.GatewayClassList - if err := r.client.List(context.Background(), &gatewayClasses); err != nil { - r.log.WithError(err).Error("error listing gatewayclasses") - return - } - - for i := range gatewayClasses.Items { - r.eventSource <- event.GenericEvent{Object: &gatewayClasses.Items[i]} - } -} - -// hasMatchingController returns true if the provided object is a GatewayClass -// with a Spec.Controller string matching this Contour's controller string, -// or false otherwise. -func (r *gatewayClassReconciler) hasMatchingController(obj client.Object) bool { - log := r.log.WithFields(logrus.Fields{ - "name": obj.GetName(), - }) - - gc, ok := obj.(*gatewayapi_v1.GatewayClass) - if !ok { - log.Debugf("unexpected object type %T, bypassing reconciliation.", obj) - return false - } - - if gc.Spec.ControllerName == r.controller { - log.Debug("enqueueing gatewayclass") - return true - } - - log.Debugf("controller is not %s; bypassing reconciliation", r.controller) - return false -} - -func (r *gatewayClassReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - r.log.WithField("name", request.Name).Info("reconciling gatewayclass") - - var gatewayClasses gatewayapi_v1.GatewayClassList - if err := r.client.List(ctx, &gatewayClasses); err != nil { - return reconcile.Result{}, fmt.Errorf("error listing gatewayclasses: %w", err) - } - - var controlledClasses controlledClasses - - for i := range gatewayClasses.Items { - // avoid loop pointer issues - gc := gatewayClasses.Items[i] - - if gc.Spec.ControllerName != r.controller { - // different controller, ignore. - continue - } - - controlledClasses.add(&gc) - } - - // no controlled gatewayclasses, trigger a delete - if controlledClasses.len() == 0 { - r.log.WithField("name", request.Name).Info("failed to find gatewayclass") - - r.eventHandler.OnDelete(&gatewayapi_v1.GatewayClass{ - ObjectMeta: meta_v1.ObjectMeta{ - Namespace: request.Namespace, - Name: request.Name, - }, - }) - return reconcile.Result{}, nil - } - - updater := func(gc *gatewayapi_v1.GatewayClass, accepted bool) error { - if r.statusUpdater != nil { - r.statusUpdater.Send(k8s.StatusUpdate{ - NamespacedName: types.NamespacedName{Name: gc.Name}, - Resource: &gatewayapi_v1.GatewayClass{}, - Mutator: k8s.StatusMutatorFunc(func(obj client.Object) client.Object { - gwc, ok := obj.(*gatewayapi_v1.GatewayClass) - if !ok { - panic(fmt.Sprintf("unsupported object type %T", obj)) - } - - return status.SetGatewayClassAccepted(gwc.DeepCopy(), accepted) - }), - }) - } else { - // this branch makes testing easier by not going through the StatusUpdater. - gcCopy := status.SetGatewayClassAccepted(gc.DeepCopy(), accepted) - - if err := r.client.Status().Update(ctx, gcCopy); err != nil { - return fmt.Errorf("error updating status of gateway class %s: %v", gcCopy.Name, err) - } - } - return nil - } - - for _, gc := range controlledClasses.notAcceptedClasses() { - if err := updater(gc, false); err != nil { - return reconcile.Result{}, err - } - } - - if err := updater(controlledClasses.acceptedClass(), true); err != nil { - return reconcile.Result{}, err - } - - r.eventHandler.OnAdd(controlledClasses.acceptedClass(), false) - - return reconcile.Result{}, nil -} - -// controlledClasses helps organize a list of GatewayClasses -// with the same controller string. -type controlledClasses struct { - allClasses []*gatewayapi_v1.GatewayClass - oldestClass *gatewayapi_v1.GatewayClass -} - -func (cc *controlledClasses) len() int { - return len(cc.allClasses) -} - -func (cc *controlledClasses) add(class *gatewayapi_v1.GatewayClass) { - cc.allClasses = append(cc.allClasses, class) - - switch { - case cc.oldestClass == nil: - cc.oldestClass = class - case class.CreationTimestamp.Time.Before(cc.oldestClass.CreationTimestamp.Time): - cc.oldestClass = class - case class.CreationTimestamp.Time.Equal(cc.oldestClass.CreationTimestamp.Time) && class.Name < cc.oldestClass.Name: - // tie-breaker: first one in alphabetical order is considered oldest/accepted - cc.oldestClass = class - } -} - -func (cc *controlledClasses) acceptedClass() *gatewayapi_v1.GatewayClass { - return cc.oldestClass -} - -func (cc *controlledClasses) notAcceptedClasses() []*gatewayapi_v1.GatewayClass { - var res []*gatewayapi_v1.GatewayClass - for _, gc := range cc.allClasses { - // skip the oldest one since it will be accepted. - if gc.Name != cc.oldestClass.Name { - res = append(res, gc) - } - } - - return res -} diff --git a/internal/controller/grpcroute.go b/internal/controller/grpcroute.go deleted file mode 100644 index 1f48924771c..00000000000 --- a/internal/controller/grpcroute.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright Project Contour 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 controller - -import ( - "context" - - "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gatewayapi_v1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" -) - -type grpcRouteReconciler struct { - client client.Client - eventHandler cache.ResourceEventHandler - logrus.FieldLogger -} - -// RegisterGRPCRouteController creates the grpcroute controller from mgr. The controller will be pre-configured -// to watch for GRPCRoute objects across all namespaces. -func RegisterGRPCRouteController(log logrus.FieldLogger, mgr manager.Manager, eventHandler cache.ResourceEventHandler) error { - r := &grpcRouteReconciler{ - client: mgr.GetClient(), - eventHandler: eventHandler, - FieldLogger: log, - } - c, err := controller.NewUnmanaged("grpcroute-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - if err := mgr.Add(&noLeaderElectionController{c}); err != nil { - return err - } - - return c.Watch(source.Kind(mgr.GetCache(), &gatewayapi_v1alpha2.GRPCRoute{}), &handler.EnqueueRequestForObject{}) -} - -func (r *grpcRouteReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - // Fetch the GRPCRoute from the cache. - grpcRoute := &gatewayapi_v1alpha2.GRPCRoute{} - err := r.client.Get(ctx, request.NamespacedName, grpcRoute) - if errors.IsNotFound(err) { - r.eventHandler.OnDelete(&gatewayapi_v1alpha2.GRPCRoute{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: request.Name, - Namespace: request.Namespace, - }, - }) - return reconcile.Result{}, nil - } - - // Pass the new changed object off to the eventHandler. - r.eventHandler.OnAdd(grpcRoute, false) - - return reconcile.Result{}, nil -} diff --git a/internal/controller/httproute.go b/internal/controller/httproute.go deleted file mode 100644 index b5fa12afb05..00000000000 --- a/internal/controller/httproute.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright Project Contour 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 controller - -import ( - "context" - - "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gatewayapi_v1 "sigs.k8s.io/gateway-api/apis/v1" -) - -type httpRouteReconciler struct { - client client.Client - eventHandler cache.ResourceEventHandler - logrus.FieldLogger -} - -// RegisterHTTPRouteController creates the httproute controller from mgr. The controller will be pre-configured -// to watch for HTTPRoute objects across all namespaces. -func RegisterHTTPRouteController(log logrus.FieldLogger, mgr manager.Manager, eventHandler cache.ResourceEventHandler) error { - r := &httpRouteReconciler{ - client: mgr.GetClient(), - eventHandler: eventHandler, - FieldLogger: log, - } - c, err := controller.NewUnmanaged("httproute-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - if err := mgr.Add(&noLeaderElectionController{c}); err != nil { - return err - } - - return c.Watch(source.Kind(mgr.GetCache(), &gatewayapi_v1.HTTPRoute{}), &handler.EnqueueRequestForObject{}) -} - -func (r *httpRouteReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - // Fetch the HTTPRoute from the cache. - httpRoute := &gatewayapi_v1.HTTPRoute{} - err := r.client.Get(ctx, request.NamespacedName, httpRoute) - if errors.IsNotFound(err) { - r.eventHandler.OnDelete(&gatewayapi_v1.HTTPRoute{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: request.Name, - Namespace: request.Namespace, - }, - }) - return reconcile.Result{}, nil - } - - // Pass the new changed object off to the eventHandler. - r.eventHandler.OnAdd(httpRoute, false) - - return reconcile.Result{}, nil -} diff --git a/internal/controller/mocks/manager.go b/internal/controller/mocks/manager.go deleted file mode 100644 index ac7467283c1..00000000000 --- a/internal/controller/mocks/manager.go +++ /dev/null @@ -1,379 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mocks - -import ( - cache "sigs.k8s.io/controller-runtime/pkg/cache" - client "sigs.k8s.io/controller-runtime/pkg/client" - - config "sigs.k8s.io/controller-runtime/pkg/config" - - context "context" - - healthz "sigs.k8s.io/controller-runtime/pkg/healthz" - - http "net/http" - - logr "github.com/go-logr/logr" - - manager "sigs.k8s.io/controller-runtime/pkg/manager" - - meta "k8s.io/apimachinery/pkg/api/meta" - - mock "github.com/stretchr/testify/mock" - - record "k8s.io/client-go/tools/record" - - rest "k8s.io/client-go/rest" - - runtime "k8s.io/apimachinery/pkg/runtime" - - webhook "sigs.k8s.io/controller-runtime/pkg/webhook" -) - -// Manager is an autogenerated mock type for the Manager type -type Manager struct { - mock.Mock -} - -// Add provides a mock function with given fields: _a0 -func (_m *Manager) Add(_a0 manager.Runnable) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for Add") - } - - var r0 error - if rf, ok := ret.Get(0).(func(manager.Runnable) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AddHealthzCheck provides a mock function with given fields: name, check -func (_m *Manager) AddHealthzCheck(name string, check healthz.Checker) error { - ret := _m.Called(name, check) - - if len(ret) == 0 { - panic("no return value specified for AddHealthzCheck") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, healthz.Checker) error); ok { - r0 = rf(name, check) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// AddReadyzCheck provides a mock function with given fields: name, check -func (_m *Manager) AddReadyzCheck(name string, check healthz.Checker) error { - ret := _m.Called(name, check) - - if len(ret) == 0 { - panic("no return value specified for AddReadyzCheck") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, healthz.Checker) error); ok { - r0 = rf(name, check) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// Elected provides a mock function with given fields: -func (_m *Manager) Elected() <-chan struct{} { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Elected") - } - - var r0 <-chan struct{} - if rf, ok := ret.Get(0).(func() <-chan struct{}); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(<-chan struct{}) - } - } - - return r0 -} - -// GetAPIReader provides a mock function with given fields: -func (_m *Manager) GetAPIReader() client.Reader { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetAPIReader") - } - - var r0 client.Reader - if rf, ok := ret.Get(0).(func() client.Reader); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(client.Reader) - } - } - - return r0 -} - -// GetCache provides a mock function with given fields: -func (_m *Manager) GetCache() cache.Cache { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetCache") - } - - var r0 cache.Cache - if rf, ok := ret.Get(0).(func() cache.Cache); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(cache.Cache) - } - } - - return r0 -} - -// GetClient provides a mock function with given fields: -func (_m *Manager) GetClient() client.Client { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetClient") - } - - var r0 client.Client - if rf, ok := ret.Get(0).(func() client.Client); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(client.Client) - } - } - - return r0 -} - -// GetConfig provides a mock function with given fields: -func (_m *Manager) GetConfig() *rest.Config { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetConfig") - } - - var r0 *rest.Config - if rf, ok := ret.Get(0).(func() *rest.Config); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*rest.Config) - } - } - - return r0 -} - -// GetControllerOptions provides a mock function with given fields: -func (_m *Manager) GetControllerOptions() config.Controller { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetControllerOptions") - } - - var r0 config.Controller - if rf, ok := ret.Get(0).(func() config.Controller); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(config.Controller) - } - - return r0 -} - -// GetEventRecorderFor provides a mock function with given fields: name -func (_m *Manager) GetEventRecorderFor(name string) record.EventRecorder { - ret := _m.Called(name) - - if len(ret) == 0 { - panic("no return value specified for GetEventRecorderFor") - } - - var r0 record.EventRecorder - if rf, ok := ret.Get(0).(func(string) record.EventRecorder); ok { - r0 = rf(name) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(record.EventRecorder) - } - } - - return r0 -} - -// GetFieldIndexer provides a mock function with given fields: -func (_m *Manager) GetFieldIndexer() client.FieldIndexer { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetFieldIndexer") - } - - var r0 client.FieldIndexer - if rf, ok := ret.Get(0).(func() client.FieldIndexer); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(client.FieldIndexer) - } - } - - return r0 -} - -// GetHTTPClient provides a mock function with given fields: -func (_m *Manager) GetHTTPClient() *http.Client { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetHTTPClient") - } - - var r0 *http.Client - if rf, ok := ret.Get(0).(func() *http.Client); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*http.Client) - } - } - - return r0 -} - -// GetLogger provides a mock function with given fields: -func (_m *Manager) GetLogger() logr.Logger { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetLogger") - } - - var r0 logr.Logger - if rf, ok := ret.Get(0).(func() logr.Logger); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(logr.Logger) - } - - return r0 -} - -// GetRESTMapper provides a mock function with given fields: -func (_m *Manager) GetRESTMapper() meta.RESTMapper { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetRESTMapper") - } - - var r0 meta.RESTMapper - if rf, ok := ret.Get(0).(func() meta.RESTMapper); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(meta.RESTMapper) - } - } - - return r0 -} - -// GetScheme provides a mock function with given fields: -func (_m *Manager) GetScheme() *runtime.Scheme { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetScheme") - } - - var r0 *runtime.Scheme - if rf, ok := ret.Get(0).(func() *runtime.Scheme); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*runtime.Scheme) - } - } - - return r0 -} - -// GetWebhookServer provides a mock function with given fields: -func (_m *Manager) GetWebhookServer() webhook.Server { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetWebhookServer") - } - - var r0 webhook.Server - if rf, ok := ret.Get(0).(func() webhook.Server); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(webhook.Server) - } - } - - return r0 -} - -// Start provides a mock function with given fields: ctx -func (_m *Manager) Start(ctx context.Context) error { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for Start") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(ctx) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewManager(t interface { - mock.TestingT - Cleanup(func()) -}) *Manager { - mock := &Manager{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/internal/controller/tcproute.go b/internal/controller/tcproute.go deleted file mode 100644 index 42a05a6d7d7..00000000000 --- a/internal/controller/tcproute.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright Project Contour 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 controller - -import ( - "context" - - "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gatewayapi_v1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" -) - -type tcpRouteReconciler struct { - client client.Client - eventHandler cache.ResourceEventHandler - logrus.FieldLogger -} - -// RegisterTCPRouteController creates the tcproute controller from mgr. The controller will be pre-configured -// to watch for TCPRoute objects across all namespaces. -func RegisterTCPRouteController(log logrus.FieldLogger, mgr manager.Manager, eventHandler cache.ResourceEventHandler) error { - r := &tcpRouteReconciler{ - client: mgr.GetClient(), - eventHandler: eventHandler, - FieldLogger: log, - } - c, err := controller.NewUnmanaged("tcproute-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - if err := mgr.Add(&noLeaderElectionController{c}); err != nil { - return err - } - - return c.Watch(source.Kind(mgr.GetCache(), &gatewayapi_v1alpha2.TCPRoute{}), &handler.EnqueueRequestForObject{}) -} - -func (r *tcpRouteReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - // Fetch the TCPRoute from the cache. - tcpRoute := &gatewayapi_v1alpha2.TCPRoute{} - err := r.client.Get(ctx, request.NamespacedName, tcpRoute) - if errors.IsNotFound(err) { - r.eventHandler.OnDelete(&gatewayapi_v1alpha2.TCPRoute{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: request.Name, - Namespace: request.Namespace, - }, - }) - return reconcile.Result{}, nil - } - - // Pass the new changed object off to the eventHandler. - r.eventHandler.OnAdd(tcpRoute, false) - - return reconcile.Result{}, nil -} diff --git a/internal/controller/tlsroute.go b/internal/controller/tlsroute.go deleted file mode 100644 index 7793d1191d2..00000000000 --- a/internal/controller/tlsroute.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright Project Contour 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 controller - -import ( - "context" - - "github.com/sirupsen/logrus" - "k8s.io/apimachinery/pkg/api/errors" - meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/tools/cache" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/manager" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - "sigs.k8s.io/controller-runtime/pkg/source" - gatewayapi_v1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" -) - -type tlsRouteReconciler struct { - client client.Client - eventHandler cache.ResourceEventHandler - logrus.FieldLogger -} - -// RegisterTLSRouteController creates the tlsroute controller from mgr. The controller will be pre-configured -// to watch for TLSRoute objects across all namespaces. -func RegisterTLSRouteController(log logrus.FieldLogger, mgr manager.Manager, eventHandler cache.ResourceEventHandler) error { - r := &tlsRouteReconciler{ - client: mgr.GetClient(), - eventHandler: eventHandler, - FieldLogger: log, - } - c, err := controller.NewUnmanaged("tlsroute-controller", mgr, controller.Options{Reconciler: r}) - if err != nil { - return err - } - if err := mgr.Add(&noLeaderElectionController{c}); err != nil { - return err - } - - return c.Watch(source.Kind(mgr.GetCache(), &gatewayapi_v1alpha2.TLSRoute{}), &handler.EnqueueRequestForObject{}) -} - -func (r *tlsRouteReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) { - // Fetch the TLSRoute from the cache. - tlsroute := &gatewayapi_v1alpha2.TLSRoute{} - err := r.client.Get(ctx, request.NamespacedName, tlsroute) - if errors.IsNotFound(err) { - r.eventHandler.OnDelete(&gatewayapi_v1alpha2.TLSRoute{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: request.Name, - Namespace: request.Namespace, - }, - }) - return reconcile.Result{}, nil - } - - // Pass the new changed object off to the eventHandler. - r.eventHandler.OnAdd(tlsroute, false) - - return reconcile.Result{}, nil -} diff --git a/internal/k8s/statusaddress.go b/internal/k8s/statusaddress.go index a3521463068..7c30d1913d3 100644 --- a/internal/k8s/statusaddress.go +++ b/internal/k8s/statusaddress.go @@ -14,7 +14,6 @@ package k8s import ( - "context" "fmt" "sync" @@ -39,13 +38,12 @@ import ( // Note that this is intended to handle updating the status.loadBalancer struct only, // not more general status updates. That's a job for the StatusUpdater. type StatusAddressUpdater struct { - Logger logrus.FieldLogger - Cache cache.Cache - LBStatus core_v1.LoadBalancerStatus - IngressClassNames []string - GatewayControllerName string - GatewayRef *types.NamespacedName - StatusUpdater StatusUpdater + Logger logrus.FieldLogger + Cache cache.Cache + LBStatus core_v1.LoadBalancerStatus + IngressClassNames []string + GatewayRef *types.NamespacedName + StatusUpdater StatusUpdater // mu guards the LBStatus field, which can be updated dynamically. mu sync.Mutex @@ -133,10 +131,9 @@ func (s *StatusAddressUpdater) OnAdd(obj any, _ bool) { )) case *gatewayapi_v1.Gateway: - switch { - // Specific Gateway configured: check if the added Gateway - // matches. - case s.GatewayRef != nil: + if s.GatewayRef != nil { + // Specific Gateway configured: check if the added Gateway + // matches. if NamespacedNameOf(o) != *s.GatewayRef { s.Logger. WithField("name", o.Name). @@ -144,28 +141,6 @@ func (s *StatusAddressUpdater) OnAdd(obj any, _ bool) { Debug("Gateway is not for this Contour, not setting address") return } - // Otherwise, check if the added Gateway's class is controlled - // by us. - default: - gc := &gatewayapi_v1.GatewayClass{} - if err := s.Cache.Get(context.Background(), client.ObjectKey{Name: string(o.Spec.GatewayClassName)}, gc); err != nil { - s.Logger. - WithField("name", o.Name). - WithField("namespace", o.Namespace). - WithField("gatewayclass-name", o.Spec.GatewayClassName). - WithError(err). - Error("error getting gateway class for gateway") - return - } - if string(gc.Spec.ControllerName) != s.GatewayControllerName { - s.Logger. - WithField("name", o.Name). - WithField("namespace", o.Namespace). - WithField("gatewayclass-name", o.Spec.GatewayClassName). - WithField("gatewayclass-controller-name", gc.Spec.ControllerName). - Debug("Gateway's class is not controlled by this Contour, not setting address") - return - } } s.StatusUpdater.Send(NewStatusUpdate( diff --git a/internal/k8s/statusaddress_test.go b/internal/k8s/statusaddress_test.go index 3b59e643384..7988c20b4cb 100644 --- a/internal/k8s/statusaddress_test.go +++ b/internal/k8s/statusaddress_test.go @@ -374,15 +374,14 @@ func TestStatusAddressUpdater_Gateway(t *testing.T) { } testCases := map[string]struct { - status core_v1.LoadBalancerStatus - gatewayClassControllerName string - gatewayRef *types.NamespacedName - preop *gatewayapi_v1.Gateway - postop *gatewayapi_v1.Gateway + status core_v1.LoadBalancerStatus + gatewayRef *types.NamespacedName + preop *gatewayapi_v1.Gateway + postop *gatewayapi_v1.Gateway }{ "happy path (IP)": { - status: ipLBStatus, - gatewayClassControllerName: "projectcontour.io/contour", + status: ipLBStatus, + gatewayRef: &types.NamespacedName{Namespace: "projectcontour", Name: "contour-gateway"}, preop: &gatewayapi_v1.Gateway{ ObjectMeta: meta_v1.ObjectMeta{ Namespace: "projectcontour", @@ -429,8 +428,8 @@ func TestStatusAddressUpdater_Gateway(t *testing.T) { }, }, "happy path (hostname)": { - status: hostnameLBStatus, - gatewayClassControllerName: "projectcontour.io/contour", + status: hostnameLBStatus, + gatewayRef: &types.NamespacedName{Namespace: "projectcontour", Name: "contour-gateway"}, preop: &gatewayapi_v1.Gateway{ ObjectMeta: meta_v1.ObjectMeta{ Namespace: "projectcontour", @@ -472,44 +471,6 @@ func TestStatusAddressUpdater_Gateway(t *testing.T) { }, }, }, - "Gateway not controlled by this Contour": { - status: ipLBStatus, - gatewayClassControllerName: "projectcontour.io/some-other-controller", - preop: &gatewayapi_v1.Gateway{ - ObjectMeta: meta_v1.ObjectMeta{ - Namespace: "projectcontour", - Name: "contour-gateway", - }, - Spec: gatewayapi_v1.GatewaySpec{ - GatewayClassName: gatewayapi_v1.ObjectName("contour-gatewayclass"), - }, - Status: gatewayapi_v1.GatewayStatus{ - Conditions: []meta_v1.Condition{ - { - Type: string(gatewayapi_v1.GatewayConditionProgrammed), - Status: meta_v1.ConditionTrue, - }, - }, - }, - }, - postop: &gatewayapi_v1.Gateway{ - ObjectMeta: meta_v1.ObjectMeta{ - Namespace: "projectcontour", - Name: "contour-gateway", - }, - Spec: gatewayapi_v1.GatewaySpec{ - GatewayClassName: gatewayapi_v1.ObjectName("contour-gatewayclass"), - }, - Status: gatewayapi_v1.GatewayStatus{ - Conditions: []meta_v1.Condition{ - { - Type: string(gatewayapi_v1.GatewayConditionProgrammed), - Status: meta_v1.ConditionTrue, - }, - }, - }, - }, - }, "Specific gateway configured, gateway does not match": { status: ipLBStatus, gatewayRef: &types.NamespacedName{Namespace: "projectcontour", Name: "contour-gateway"}, @@ -548,54 +509,6 @@ func TestStatusAddressUpdater_Gateway(t *testing.T) { }, }, }, - "Specific gateway configured, gateway matches": { - status: ipLBStatus, - gatewayRef: &types.NamespacedName{Namespace: "projectcontour", Name: "contour-gateway"}, - preop: &gatewayapi_v1.Gateway{ - ObjectMeta: meta_v1.ObjectMeta{ - Namespace: "projectcontour", - Name: "contour-gateway", - }, - Spec: gatewayapi_v1.GatewaySpec{ - GatewayClassName: gatewayapi_v1.ObjectName("contour-gatewayclass"), - }, - Status: gatewayapi_v1.GatewayStatus{ - Conditions: []meta_v1.Condition{ - { - Type: string(gatewayapi_v1.GatewayConditionProgrammed), - Status: meta_v1.ConditionTrue, - }, - }, - }, - }, - postop: &gatewayapi_v1.Gateway{ - ObjectMeta: meta_v1.ObjectMeta{ - Namespace: "projectcontour", - Name: "contour-gateway", - }, - Spec: gatewayapi_v1.GatewaySpec{ - GatewayClassName: gatewayapi_v1.ObjectName("contour-gatewayclass"), - }, - Status: gatewayapi_v1.GatewayStatus{ - Conditions: []meta_v1.Condition{ - { - Type: string(gatewayapi_v1.GatewayConditionProgrammed), - Status: meta_v1.ConditionTrue, - }, - }, - Addresses: []gatewayapi_v1.GatewayStatusAddress{ - { - Type: ref.To(gatewayapi_v1.IPAddressType), - Value: ipLBStatus.Ingress[0].IP, - }, - { - Type: ref.To(gatewayapi_v1.IPAddressType), - Value: ipLBStatus.Ingress[1].IP, - }, - }, - }, - }, - }, } for name, tc := range testCases { @@ -606,22 +519,14 @@ func TestStatusAddressUpdater_Gateway(t *testing.T) { mockCache := &mocks.Cache{} mockCache. On("Get", mock.Anything, client.ObjectKey{Name: string(tc.preop.Spec.GatewayClassName)}, mock.Anything). - Run(func(args mock.Arguments) { - // The cache's Get function takes a pointer to a struct and updates it - // with the data from the API server; this simulates that behavior by - // updating the struct pointed to by the third argument with the fields - // we care about. See Run's godoc for more info. - args[2].(*gatewayapi_v1.GatewayClass).Spec.ControllerName = gatewayapi_v1.GatewayController(tc.gatewayClassControllerName) - }). Return(nil) isu := StatusAddressUpdater{ - Logger: log, - GatewayControllerName: "projectcontour.io/contour", - GatewayRef: tc.gatewayRef, - Cache: mockCache, - LBStatus: tc.status, - StatusUpdater: &suc, + Logger: log, + GatewayRef: tc.gatewayRef, + Cache: mockCache, + LBStatus: tc.status, + StatusUpdater: &suc, } isu.OnAdd(tc.preop, false) @@ -637,22 +542,14 @@ func TestStatusAddressUpdater_Gateway(t *testing.T) { mockCache := &mocks.Cache{} mockCache. On("Get", mock.Anything, client.ObjectKey{Name: string(tc.preop.Spec.GatewayClassName)}, mock.Anything). - Run(func(args mock.Arguments) { - // The cache's Get function takes a pointer to a struct and updates it - // with the data from the API server; this simulates that behavior by - // updating the struct pointed to by the third argument with the fields - // we care about. See Run's godoc for more info. - args[2].(*gatewayapi_v1.GatewayClass).Spec.ControllerName = gatewayapi_v1.GatewayController(tc.gatewayClassControllerName) - }). Return(nil) isu := StatusAddressUpdater{ - Logger: log, - GatewayControllerName: "projectcontour.io/contour", - GatewayRef: tc.gatewayRef, - Cache: mockCache, - LBStatus: tc.status, - StatusUpdater: &suc, + Logger: log, + GatewayRef: tc.gatewayRef, + Cache: mockCache, + LBStatus: tc.status, + StatusUpdater: &suc, } isu.OnUpdate(tc.preop, tc.preop) diff --git a/internal/provisioner/controller/gateway_test.go b/internal/provisioner/controller/gateway_test.go index baf160da86c..c95f9a59238 100644 --- a/internal/provisioner/controller/gateway_test.go +++ b/internal/provisioner/controller/gateway_test.go @@ -335,7 +335,7 @@ func TestGatewayReconcile(t *testing.T) { want := contour_v1alpha1.ContourConfigurationSpec{ EnableExternalNameService: ref.To(true), Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: gw.Name, Name: gw.Name, }, @@ -367,8 +367,7 @@ func TestGatewayReconcile(t *testing.T) { Spec: contour_v1alpha1.ContourDeploymentSpec{ RuntimeSettings: &contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - ControllerName: "some-controller", - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "some-other-namespace", Name: "some-other-gateway", }, @@ -403,7 +402,7 @@ func TestGatewayReconcile(t *testing.T) { want := contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: gw.Name, Name: gw.Name, }, @@ -458,7 +457,7 @@ func TestGatewayReconcile(t *testing.T) { want := contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: gw.Name, Name: gw.Name, }, diff --git a/internal/provisioner/objects/contourconfig/contourconfig.go b/internal/provisioner/objects/contourconfig/contourconfig.go index 3da243a5266..b2f7b99a97c 100644 --- a/internal/provisioner/objects/contourconfig/contourconfig.go +++ b/internal/provisioner/objects/contourconfig/contourconfig.go @@ -60,7 +60,7 @@ func EnsureContourConfig(ctx context.Context, cli client.Client, contour *model. func setGatewayConfig(config *contour_v1alpha1.ContourConfiguration, contour *model.Contour) { config.Spec.Gateway = &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: contour.Namespace, Name: contour.Name, }, diff --git a/internal/provisioner/objects/contourconfig/contourconfig_test.go b/internal/provisioner/objects/contourconfig/contourconfig_test.go index 30946fe540a..b6e41f581ab 100644 --- a/internal/provisioner/objects/contourconfig/contourconfig_test.go +++ b/internal/provisioner/objects/contourconfig/contourconfig_test.go @@ -44,7 +44,7 @@ func TestEnsureContourConfig(t *testing.T) { }, want: contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "contour-namespace-1", Name: "contour-1", }, @@ -71,7 +71,7 @@ func TestEnsureContourConfig(t *testing.T) { }, Spec: contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "contour-namespace-1", Name: "contour-1", }, @@ -86,7 +86,7 @@ func TestEnsureContourConfig(t *testing.T) { }, want: contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "contour-namespace-1", Name: "contour-1", }, @@ -113,7 +113,7 @@ func TestEnsureContourConfig(t *testing.T) { }, Spec: contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "some-other-namespace", Name: "some-other-contour", }, @@ -128,7 +128,7 @@ func TestEnsureContourConfig(t *testing.T) { }, want: contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "contour-namespace-1", Name: "contour-1", }, @@ -155,7 +155,7 @@ func TestEnsureContourConfig(t *testing.T) { }, Spec: contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "contour-namespace-1", Name: "contour-1", }, @@ -177,7 +177,7 @@ func TestEnsureContourConfig(t *testing.T) { }, want: contour_v1alpha1.ContourConfigurationSpec{ Gateway: &contour_v1alpha1.GatewayConfig{ - GatewayRef: &contour_v1alpha1.NamespacedName{ + GatewayRef: contour_v1alpha1.NamespacedName{ Namespace: "contour-namespace-1", Name: "contour-1", }, diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index 539970a591c..a79158549eb 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -47,18 +47,10 @@ func (s ServerType) Validate() error { } } -// Validate the GatewayConfig. +// Validate ensures that GatewayRef namespace/name is specified. func (g *GatewayParameters) Validate() error { - if g == nil { - return nil - } - - if len(g.ControllerName) == 0 && g.GatewayRef == nil { - return fmt.Errorf("invalid Gateway parameters specified: exactly one of controller name or gateway ref must be provided") - } - - if len(g.ControllerName) > 0 && g.GatewayRef != nil { - return fmt.Errorf("invalid Gateway parameters specified: exactly one of controller name or gateway ref must be provided") + if g != nil && (g.GatewayRef.Namespace == "" || g.GatewayRef.Name == "") { + return fmt.Errorf("invalid Gateway parameters specified: gateway ref namespace and name must be provided") } return nil @@ -255,21 +247,9 @@ type ServerParameters struct { // GatewayParameters holds the configuration for Gateway API controllers. type GatewayParameters struct { - // ControllerName is used to determine whether Contour should reconcile a - // GatewayClass. The string takes the form of "projectcontour.io//contour". - // If unset, the gatewayclass controller will not be started. - // Exactly one of ControllerName or GatewayRef must be set. - // - // Deprecated: users should use GatewayRef, or the Gateway provisioner, - // in place of this field. This field will be removed in a future release. - ControllerName string `yaml:"controllerName,omitempty"` - - // GatewayRef defines a specific Gateway that this Contour - // instance corresponds to. If set, Contour will reconcile - // only this gateway, and will not reconcile any gateway - // classes. - // Exactly one of ControllerName or GatewayRef must be set. - GatewayRef *NamespacedName `yaml:"gatewayRef,omitempty"` + // GatewayRef defines the specific Gateway that this Contour + // instance corresponds to. + GatewayRef NamespacedName `yaml:"gatewayRef"` } // TimeoutParameters holds various configurable proxy timeout values. diff --git a/pkg/config/parameters_test.go b/pkg/config/parameters_test.go index 3e275286a8f..8341906daff 100644 --- a/pkg/config/parameters_test.go +++ b/pkg/config/parameters_test.go @@ -193,9 +193,17 @@ func TestValidateGatewayParameters(t *testing.T) { var gw *GatewayParameters require.NoError(t, gw.Validate()) - // ControllerName is required. - gw = &GatewayParameters{ControllerName: "controller"} + // Namespace and name are required + gw = &GatewayParameters{GatewayRef: NamespacedName{Namespace: "foo", Name: "bar"}} require.NoError(t, gw.Validate()) + + // Namespace is required + gw = &GatewayParameters{GatewayRef: NamespacedName{Name: "bar"}} + require.Error(t, gw.Validate()) + + // Name is required + gw = &GatewayParameters{GatewayRef: NamespacedName{Namespace: "foo"}} + require.Error(t, gw.Validate()) } func TestValidateHTTPVersionType(t *testing.T) { diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index 522e89d16a8..82e03f685da 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -7656,24 +7656,6 @@

GatewayConfig -controllerName -
- -string - - - -(Optional) -

ControllerName is used to determine whether Contour should reconcile a -GatewayClass. The string takes the form of “projectcontour.io//contour”. -If unset, the gatewayclass controller will not be started. -Exactly one of ControllerName or GatewayRef must be set.

-

Deprecated: users should use GatewayRef, or the Gateway provisioner, -in place of this field. This field will be removed in a future release.

- - - - gatewayRef
@@ -7683,12 +7665,8 @@

GatewayConfig -(Optional) -

GatewayRef defines a specific Gateway that this Contour -instance corresponds to. If set, Contour will reconcile -only this gateway, and will not reconcile any gateway -classes. -Exactly one of ControllerName or GatewayRef must be set.

+

GatewayRef defines the specific Gateway that this Contour +instance corresponds to.

diff --git a/site/content/docs/main/config/gateway-api.md b/site/content/docs/main/config/gateway-api.md index af67fea4339..2fc129985cb 100644 --- a/site/content/docs/main/config/gateway-api.md +++ b/site/content/docs/main/config/gateway-api.md @@ -24,9 +24,7 @@ There are two ways to deploy Contour with Gateway API support: **static** provis In **static** provisioning, the platform operator defines a `Gateway` resource, and then manually deploys a Contour instance corresponding to that `Gateway` resource. It is up to the platform operator to ensure that all configuration matches between the `Gateway` and the Contour/Envoy resources. -With static provisioning, Contour can be configured with either a [controller name][8], or a specific gateway (see the [API documentation][7].) -If configured with a controller name, Contour will process the oldest `GatewayClass`, its oldest `Gateway`, and that `Gateway's` routes, for the given controller name. -If configured with a specific gateway, Contour will process that `Gateway` and its routes. +Contour will then process that `Gateway` and its routes. **Note:** configuring Contour with a controller name is deprecated and will be removed in a future release. Use a specific gateway reference or dynamic provisioning instead. diff --git a/site/content/docs/main/configuration.md b/site/content/docs/main/configuration.md index f145d67f09c..acc5810f278 100644 --- a/site/content/docs/main/configuration.md +++ b/site/content/docs/main/configuration.md @@ -214,8 +214,7 @@ The gateway configuration block is used to configure which gateway-api Gateway C | Field Name | Type | Default | Description | | -------------- | -------------- | ------- | ------------------------------------------------------------------------------ | -| controllerName | string | | **DEPRECATED**: Use `gatewayRef` or the Gateway provisioner instead. This field will be removed in a future release. Gateway Class controller name (i.e. projectcontour.io/gateway-controller). If set, Contour will reconcile the oldest GatewayClass, and its oldest Gateway, with this controller string. Only one of `controllerName` or `gatewayRef` must be set. | -| gatewayRef | NamespacedName | | [Gateway namespace and name](#gateway-ref). If set, Contour will reconcile this specific Gateway. Only one of `controllerName` or `gatewayRef` must be set. | +| gatewayRef | NamespacedName | | [Gateway namespace and name](#gateway-ref). | ### Gateway Ref @@ -321,7 +320,8 @@ data: # # specify the gateway-api Gateway Contour should configure # gateway: - # controllerName: projectcontour.io/gateway-controller + # namespace: projectcontour + # name: contour # # should contour expect to be running inside a k8s cluster # incluster: true diff --git a/site/content/docs/main/guides/gateway-api.md b/site/content/docs/main/guides/gateway-api.md index 0759696d3f6..4bcc3140c03 100644 --- a/site/content/docs/main/guides/gateway-api.md +++ b/site/content/docs/main/guides/gateway-api.md @@ -73,7 +73,7 @@ This command creates: - Envoy DaemonSet / Service - Contour ConfigMap -Update the Contour configmap to enable Gateway API processing by specifying a gateway controller name, and restart Contour to pick up the config change: +Update the Contour configmap to enable Gateway API processing by specifying a gateway, and restart Contour to pick up the config change: ```shell kubectl apply -f - <