diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go index 4128c5bfdf5..099d64dedad 100644 --- a/apis/projectcontour/v1alpha1/contourconfig.go +++ b/apis/projectcontour/v1alpha1/contourconfig.go @@ -253,11 +253,15 @@ type EnvoyConfig struct { // +optional Service *NamespacedName `json:"service,omitempty"` - // Ingress holds Envoy service parameters for setting Ingress status. + // LoadBalancer specifies how Contour should set the ingress status address. + // If provided, the value can be in one of the formats: + // - hostname:: Contour will use the provided comma separated list of addresses directly. + // - service:/: Contour will use the address of the designated service. + // - ingress:/: Contour will use the address of the designated ingress. // - // Contour's default is { namespace: "projectcontour", name: "envoy" }. + // Contour's default is an empty string. // +optional - Ingress *NamespacedName `json:"ingress,omitempty"` + LoadBalancer string `json:"loadBalancer,omitempty"` // Defines the HTTP Listener for Envoy. // diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go index 2b6a0fe0f97..88d2ce69b81 100644 --- a/cmd/contour/serve.go +++ b/cmd/contour/serve.go @@ -20,6 +20,7 @@ import ( "net/http" "os" "strconv" + "strings" "time" "github.com/alecthomas/kingpin/v2" @@ -145,8 +146,6 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext) serve.Flag("envoy-service-https-port", "Kubernetes Service port for HTTPS requests.").PlaceHolder("").IntVar(&ctx.httpsPort) serve.Flag("envoy-service-name", "Name of the Envoy service to inspect for Ingress status details.").PlaceHolder("").StringVar(&ctx.Config.EnvoyServiceName) serve.Flag("envoy-service-namespace", "Envoy Service Namespace.").PlaceHolder("").StringVar(&ctx.Config.EnvoyServiceNamespace) - serve.Flag("envoy-ingress-name", "Name of the Envoy ingress to inspect for Ingress status details.").PlaceHolder("").StringVar(&ctx.Config.EnvoyIngressName) - serve.Flag("envoy-ingress-namespace", "Envoy Ingress Namespace.").PlaceHolder("").StringVar(&ctx.Config.EnvoyIngressNamespace) serve.Flag("health-address", "Address the health HTTP endpoint will bind to.").PlaceHolder("").StringVar(&ctx.healthAddr) serve.Flag("health-port", "Port the health HTTP endpoint will bind to.").PlaceHolder("").IntVar(&ctx.healthPort) @@ -169,6 +168,8 @@ func registerServe(app *kingpin.Application) (*kingpin.CmdClause, *serveContext) serve.Flag("leader-election-resource-namespace", "The namespace of the resource (Lease) leader election will lease.").Default(config.GetenvOr("CONTOUR_NAMESPACE", "projectcontour")).StringVar(&ctx.LeaderElection.Namespace) serve.Flag("leader-election-retry-period", "The interval which Contour will attempt to acquire leadership lease.").Default("2s").DurationVar(&ctx.LeaderElection.RetryPeriod) + serve.Flag("load-balancer-status", "Address to set or the source to inspect for ingress status.").PlaceHolder("").StringVar(&ctx.Config.LoadBalancerStatus) + serve.Flag("root-namespaces", "Restrict contour to searching these namespaces for root ingress routes.").PlaceHolder("").StringVar(&ctx.rootNamespaces) serve.Flag("stats-address", "Envoy /stats interface address.").PlaceHolder("").StringVar(&ctx.statsAddr) @@ -673,6 +674,42 @@ func (s *Server) doServe() error { } // Set up ingress load balancer status writer. + if err := s.setupIngressLoadBalancerStatusWriter(contourConfiguration, ingressClassNames, gatewayControllerName, gatewayRef, sh.Writer()); err != nil { + return err + } + + xdsServer := &xdsServer{ + log: s.log, + registry: s.registry, + config: *contourConfiguration.XDSServer, + snapshotHandler: snapshotHandler, + resources: resources, + initialDagBuilt: contourHandler.HasBuiltInitialDag, + } + if err := s.mgr.Add(xdsServer); err != nil { + return err + } + + notifier := &leadership.Notifier{ + ToNotify: append([]leadership.NeedLeaderElectionNotification{ + contourHandler, + observer, + }, needsNotification...), + } + if err := s.mgr.Add(notifier); err != nil { + return err + } + + // GO! + return s.mgr.Start(signals.SetupSignalHandler()) +} + +func (s *Server) setupIngressLoadBalancerStatusWriter( + contourConfiguration contour_api_v1alpha1.ContourConfigurationSpec, + ingressClassNames []string, + gatewayControllerName string, + gatewayRef *types.NamespacedName, + statusUpdater k8s.StatusUpdater) error { lbsw := &loadBalancerStatusWriter{ log: s.log.WithField("context", "loadBalancerStatusWriter"), cache: s.mgr.GetCache(), @@ -680,80 +717,119 @@ func (s *Server) doServe() error { ingressClassNames: ingressClassNames, gatewayControllerName: gatewayControllerName, gatewayRef: gatewayRef, - statusUpdater: sh.Writer(), + statusUpdater: statusUpdater, } if err := s.mgr.Add(lbsw); err != nil { return err } - // Register an informer to watch envoy's service if we haven't been given static details. + elbs := &envoyLoadBalancerStatus{} if lbAddress := contourConfiguration.Ingress.StatusAddress; len(lbAddress) > 0 { - s.log.WithField("loadbalancer-address", lbAddress).Info("Using supplied information for Ingress status") - lbsw.lbStatus <- parseStatusFlag(lbAddress) + elbs.Kind = "hostname" + elbs.FQDNs = lbAddress + } else if contourConfiguration.Envoy.LoadBalancer != "" { + status, err := parseEnvoyLoadBalancerStatus(contourConfiguration.Envoy.LoadBalancer) + if err != nil { + return err + } + elbs = status } else { + elbs.Kind = "service" + elbs.Namespace = contourConfiguration.Envoy.Service.Namespace + elbs.Name = contourConfiguration.Envoy.Service.Name + } + switch strings.ToLower(elbs.Kind) { + case "hostname": + s.log.WithField("loadbalancer-fqdns", lbAddress).Info("Using supplied hostname for Ingress status") + lbsw.lbStatus <- parseStatusFlag(elbs.FQDNs) + case "service": + // Register an informer to watch supplied service serviceHandler := &k8s.ServiceStatusLoadBalancerWatcher{ - ServiceName: contourConfiguration.Envoy.Service.Name, + ServiceName: elbs.Name, LBStatus: lbsw.lbStatus, Log: s.log.WithField("context", "serviceStatusLoadBalancerWatcher"), } var handler cache.ResourceEventHandler = serviceHandler - if contourConfiguration.Envoy.Service.Namespace != "" { - handler = k8s.NewNamespaceFilter([]string{contourConfiguration.Envoy.Service.Namespace}, handler) + if elbs.Namespace != "" { + handler = k8s.NewNamespaceFilter([]string{elbs.Namespace}, handler) } if err := s.informOnResource(&corev1.Service{}, handler); err != nil { - s.log.WithError(err).WithField("resource", "services").Fatal("failed to create informer") + s.log.WithError(err).WithField("resource", "services").Fatal("failed to create services informer") } - + s.log.Infof("Watching %s for Ingress status", elbs) + case "ingress": + // Register an informer to watch supplied ingress ingressHandler := &k8s.IngressStatusLoadBalancerWatcher{ - ServiceName: contourConfiguration.Envoy.Service.Name, + IngressName: elbs.Name, LBStatus: lbsw.lbStatus, Log: s.log.WithField("context", "ingressStatusLoadBalancerWatcher"), } - var ingressEventHandler cache.ResourceEventHandler = ingressHandler - if contourConfiguration.Envoy.Ingress.Namespace != "" { - handler = k8s.NewNamespaceFilter([]string{contourConfiguration.Envoy.Ingress.Namespace}, handler) + var handler cache.ResourceEventHandler = ingressHandler + if elbs.Namespace != "" { + handler = k8s.NewNamespaceFilter([]string{elbs.Namespace}, handler) } - if err := informOnResource(&networking_v1.Ingress{}, ingressEventHandler, s.mgr.GetCache()); err != nil { + if err := s.informOnResource(&networking_v1.Ingress{}, handler); err != nil { s.log.WithError(err).WithField("resource", "ingresses").Fatal("failed to create ingresses informer") } + s.log.Infof("Watching %s for Ingress status", elbs) + default: + return fmt.Errorf("unsupported ingress kind: %s", elbs.Kind) + } - s.log.WithField("envoy-service-name", contourConfiguration.Envoy.Service.Name). - WithField("envoy-service-namespace", contourConfiguration.Envoy.Service.Namespace). - Info("Watching Service for Ingress status") + return nil +} - s.log.WithField("envoy-ingress-name", contourConfiguration.Envoy.Ingress.Name). - WithField("envoy-ingress-namespace", contourConfiguration.Envoy.Ingress.Namespace). - Info("Watching Ingress for Ingress status") - } +type envoyLoadBalancerStatus struct { + Kind string + FQDNs string + config.NamespacedName +} - xdsServer := &xdsServer{ - log: s.log, - registry: s.registry, - config: *contourConfiguration.XDSServer, - snapshotHandler: snapshotHandler, - resources: resources, - initialDagBuilt: contourHandler.HasBuiltInitialDag, +func (elbs *envoyLoadBalancerStatus) String() string { + if elbs.Kind == "hostname" { + return fmt.Sprintf("%s:%s", elbs.Kind, elbs.FQDNs) } - if err := s.mgr.Add(xdsServer); err != nil { - return err + return fmt.Sprintf("%s:%s/%s", elbs.Kind, elbs.Namespace, elbs.Name) +} + +func parseEnvoyLoadBalancerStatus(s string) (*envoyLoadBalancerStatus, error) { + parts := strings.SplitN(s, ":", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid load-balancer-status: %s", s) } - notifier := &leadership.Notifier{ - ToNotify: append([]leadership.NeedLeaderElectionNotification{ - contourHandler, - observer, - }, needsNotification...), + if parts[1] == "" { + return nil, fmt.Errorf("invalid load-balancer-status: empty object reference") } - if err := s.mgr.Add(notifier); err != nil { - return err + + elbs := envoyLoadBalancerStatus{} + + elbs.Kind = strings.ToLower(parts[0]) + switch elbs.Kind { + case "ingress", "service": + parts = strings.Split(parts[1], "/") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid load-balancer-status: %s is not in the format of /", s) + } + + if parts[0] == "" || parts[1] == "" { + return nil, fmt.Errorf("invalid load-balancer-status: or is empty") + } + elbs.Namespace = parts[0] + elbs.Name = parts[1] + case "hostname": + elbs.FQDNs = parts[1] + case "": + return nil, fmt.Errorf("invalid load-balancer-status: kind is empty") + default: + return nil, fmt.Errorf("invalid load-balancer-status: unsupported kind: %s", elbs.Kind) } - // GO! - return s.mgr.Start(signals.SetupSignalHandler()) + return &elbs, nil } func (s *Server) getExtensionSvcConfig(name string, namespace string) (xdscache_v3.ExtensionServiceConfig, error) { diff --git a/cmd/contour/serve_test.go b/cmd/contour/serve_test.go index 8f6ac4234b1..c4d5ae08719 100644 --- a/cmd/contour/serve_test.go +++ b/cmd/contour/serve_test.go @@ -19,6 +19,7 @@ import ( contour_api_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" "github.com/projectcontour/contour/internal/dag" "github.com/projectcontour/contour/internal/ref" + "github.com/projectcontour/contour/pkg/config" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -217,3 +218,109 @@ func mustGetIngressProcessor(t *testing.T, builder *dag.Builder) *dag.IngressPro require.FailNow(t, "IngressProcessor not found in list of DAG builder's processors") return nil } + +func TestParseEnvoyLoadBalancerStatus(t *testing.T) { + + tests := []struct { + name string + status string + want envoyLoadBalancerStatus + }{ + { + name: "Service", + status: "service:namespace-1/name-1", + want: envoyLoadBalancerStatus{ + Kind: "service", + NamespacedName: config.NamespacedName{ + Name: "name-1", + Namespace: "namespace-1", + }, + }, + }, + { + name: "Ingress", + status: "ingress:namespace-1/name-1", + want: envoyLoadBalancerStatus{ + Kind: "ingress", + NamespacedName: config.NamespacedName{ + Name: "name-1", + Namespace: "namespace-1", + }, + }, + }, + { + name: "hostname", + status: "hostname:example.com", + want: envoyLoadBalancerStatus{ + Kind: "hostname", + FQDNs: "example.com", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r, err := parseEnvoyLoadBalancerStatus(tt.status) + assert.NoError(t, err) + assert.Equal(t, tt.want, *r) + }) + } + + tests2 := []struct { + name string + status string + error string + }{ + { + name: "Empty", + status: "", + error: "invalid", + }, + { + name: "No kind", + status: ":n", + error: "kind is empty", + }, + { + name: "Invalid kind", + status: "test:n", + error: "unsupported kind", + }, + { + name: "No reference", + status: "service:", + error: "empty object reference", + }, + { + name: "No colon", + status: "service", + error: "invalid", + }, + { + name: "No slash", + status: "service:name-1", + error: "not in the format", + }, + { + name: "starts with slash", + status: "service:/name-1", + error: "is empty", + }, + { + name: "ends with slash", + status: "service:name-1/", + error: "is empty", + }, + { + name: "two many slashes", + status: "service:name/x/y", + error: "not in the format", + }, + } + for _, tt := range tests2 { + t.Run(tt.name, func(t *testing.T) { + _, err := parseEnvoyLoadBalancerStatus(tt.status) + assert.Error(t, err) + assert.Contains(t, err.Error(), tt.error) + }) + } +} diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go index 067dd23de48..74172381c17 100644 --- a/cmd/contour/servecontext.go +++ b/cmd/contour/servecontext.go @@ -544,10 +544,6 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_api_v1alpha Name: ctx.Config.EnvoyServiceName, Namespace: ctx.Config.EnvoyServiceNamespace, }, - Ingress: &contour_api_v1alpha1.NamespacedName{ - Name: ctx.Config.EnvoyIngressName, - Namespace: ctx.Config.EnvoyIngressNamespace, - }, HTTPListener: &contour_api_v1alpha1.EnvoyListener{ Address: ctx.httpAddr, Port: ctx.httpPort, @@ -581,6 +577,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_api_v1alpha XffNumTrustedHops: &ctx.Config.Network.XffNumTrustedHops, EnvoyAdminPort: &ctx.Config.Network.EnvoyAdminPort, }, + LoadBalancer: ctx.Config.LoadBalancerStatus, }, Gateway: gatewayConfig, HTTPProxy: &contour_api_v1alpha1.HTTPProxyConfig{ diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml index 783ff7574f5..ca98279331f 100644 --- a/examples/contour/01-crds.yaml +++ b/examples/contour/01-crds.yaml @@ -320,6 +320,15 @@ spec: default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set the + ingress status address. If provided, the value can be in one + of the formats: - hostname:: Contour will use the + provided comma separated list of addresses directly. - service:/: + Contour will use the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. \n Contour's + default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: @@ -3797,6 +3806,16 @@ spec: Contour's default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set + the ingress status address. If provided, the value can be + in one of the formats: - hostname:: Contour + will use the provided comma separated list of addresses + directly. - service:/: Contour will use + the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. + \n Contour's default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: diff --git a/examples/render/contour-deployment.yaml b/examples/render/contour-deployment.yaml index 2020135a384..582b344f78e 100644 --- a/examples/render/contour-deployment.yaml +++ b/examples/render/contour-deployment.yaml @@ -539,6 +539,15 @@ spec: default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set the + ingress status address. If provided, the value can be in one + of the formats: - hostname:: Contour will use the + provided comma separated list of addresses directly. - service:/: + Contour will use the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. \n Contour's + default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: @@ -4016,6 +4025,16 @@ spec: Contour's default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set + the ingress status address. If provided, the value can be + in one of the formats: - hostname:: Contour + will use the provided comma separated list of addresses + directly. - service:/: Contour will use + the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. + \n Contour's default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: diff --git a/examples/render/contour-gateway-provisioner.yaml b/examples/render/contour-gateway-provisioner.yaml index f0065dfc379..7c4d78cf41b 100644 --- a/examples/render/contour-gateway-provisioner.yaml +++ b/examples/render/contour-gateway-provisioner.yaml @@ -331,6 +331,15 @@ spec: default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set the + ingress status address. If provided, the value can be in one + of the formats: - hostname:: Contour will use the + provided comma separated list of addresses directly. - service:/: + Contour will use the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. \n Contour's + default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: @@ -3808,6 +3817,16 @@ spec: Contour's default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set + the ingress status address. If provided, the value can be + in one of the formats: - hostname:: Contour + will use the provided comma separated list of addresses + directly. - service:/: Contour will use + the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. + \n Contour's default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: diff --git a/examples/render/contour-gateway.yaml b/examples/render/contour-gateway.yaml index f4a9db215f3..818c81ffd6e 100644 --- a/examples/render/contour-gateway.yaml +++ b/examples/render/contour-gateway.yaml @@ -542,6 +542,15 @@ spec: default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set the + ingress status address. If provided, the value can be in one + of the formats: - hostname:: Contour will use the + provided comma separated list of addresses directly. - service:/: + Contour will use the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. \n Contour's + default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: @@ -4019,6 +4028,16 @@ spec: Contour's default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set + the ingress status address. If provided, the value can be + in one of the formats: - hostname:: Contour + will use the provided comma separated list of addresses + directly. - service:/: Contour will use + the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. + \n Contour's default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: diff --git a/examples/render/contour.yaml b/examples/render/contour.yaml index 3f24568201b..c13757c9e95 100644 --- a/examples/render/contour.yaml +++ b/examples/render/contour.yaml @@ -539,6 +539,15 @@ spec: default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set the + ingress status address. If provided, the value can be in one + of the formats: - hostname:: Contour will use the + provided comma separated list of addresses directly. - service:/: + Contour will use the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. \n Contour's + default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: @@ -4016,6 +4025,16 @@ spec: Contour's default is false." type: boolean type: object + loadBalancer: + description: "LoadBalancer specifies how Contour should set + the ingress status address. If provided, the value can be + in one of the formats: - hostname:: Contour + will use the provided comma separated list of addresses + directly. - service:/: Contour will use + the address of the designated service. - ingress:/: + Contour will use the address of the designated ingress. + \n Contour's default is an empty string." + type: string logging: description: Logging defines how Envoy's logs can be configured. properties: diff --git a/internal/k8s/statusaddress.go b/internal/k8s/statusaddress.go index 9078b860f5e..d0e4b2cb975 100644 --- a/internal/k8s/statusaddress.go +++ b/internal/k8s/statusaddress.go @@ -308,17 +308,39 @@ func lbStatusToGatewayAddresses(lbs v1.LoadBalancerStatus) []gatewayapi_v1.Gatew return addrs } +func networkingToCoreLBStatus(lbs networking_v1.IngressLoadBalancerStatus) v1.LoadBalancerStatus { + ingress := make([]v1.LoadBalancerIngress, len(lbs.Ingress)) + for i, ing := range lbs.Ingress { + ports := make([]v1.PortStatus, len(ing.Ports)) + for j, ps := range ing.Ports { + ports[j] = v1.PortStatus{ + Port: ps.Port, + Protocol: ps.Protocol, + Error: ps.Error, + } + } + ingress[i] = v1.LoadBalancerIngress{ + IP: ing.IP, + Hostname: ing.Hostname, + Ports: ports, + } + } + return v1.LoadBalancerStatus{ + Ingress: ingress, + } +} + // IngressStatusLoadBalancerWatcher implements ResourceEventHandler and // watches for changes to the status.loadbalancer field // Note that we specifically *don't* inspect inside the struct, as sending empty values // is desirable to clear the status. type IngressStatusLoadBalancerWatcher struct { IngressName string - LBStatus chan networking_v1.IngressLoadBalancerStatus + LBStatus chan v1.LoadBalancerStatus Log logrus.FieldLogger } -func (s *IngressStatusLoadBalancerWatcher) OnAdd(obj interface{}) { +func (s *IngressStatusLoadBalancerWatcher) OnAdd(obj any, _ bool) { ingress, ok := obj.(*networking_v1.Ingress) if !ok { // not a service @@ -334,7 +356,7 @@ func (s *IngressStatusLoadBalancerWatcher) OnAdd(obj interface{}) { s.notify(ingress.Status.LoadBalancer) } -func (s *IngressStatusLoadBalancerWatcher) OnUpdate(oldObj, newObj interface{}) { +func (s *IngressStatusLoadBalancerWatcher) OnUpdate(_, newObj any) { ingress, ok := newObj.(*networking_v1.Ingress) if !ok { // not a service @@ -350,7 +372,7 @@ func (s *IngressStatusLoadBalancerWatcher) OnUpdate(oldObj, newObj interface{}) s.notify(ingress.Status.LoadBalancer) } -func (s *IngressStatusLoadBalancerWatcher) OnDelete(obj interface{}) { +func (s *IngressStatusLoadBalancerWatcher) OnDelete(obj any) { ingress, ok := obj.(*networking_v1.Ingress) if !ok { // not a service @@ -365,5 +387,5 @@ func (s *IngressStatusLoadBalancerWatcher) OnDelete(obj interface{}) { } func (s *IngressStatusLoadBalancerWatcher) notify(lbstatus networking_v1.IngressLoadBalancerStatus) { - s.LBStatus <- lbstatus + s.LBStatus <- networkingToCoreLBStatus(lbstatus) } diff --git a/internal/provisioner/controller/gateway_test.go b/internal/provisioner/controller/gateway_test.go index a8ba99c9d4e..4d9a4755556 100644 --- a/internal/provisioner/controller/gateway_test.go +++ b/internal/provisioner/controller/gateway_test.go @@ -15,6 +15,7 @@ package controller import ( "context" + "fmt" "testing" contourv1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" @@ -347,6 +348,7 @@ func TestGatewayReconcile(t *testing.T) { Namespace: gw.Namespace, Name: "envoy-" + gw.Name, }, + LoadBalancer: fmt.Sprintf("service:%s/envoy-%s", gw.Namespace, gw.Name), Metrics: &contourv1alpha1.MetricsConfig{ Port: 8003, }, @@ -412,6 +414,7 @@ func TestGatewayReconcile(t *testing.T) { Namespace: gw.Namespace, Name: "envoy-" + gw.Name, }, + LoadBalancer: fmt.Sprintf("service:%s/envoy-%s", gw.Namespace, gw.Name), }, } @@ -467,6 +470,7 @@ func TestGatewayReconcile(t *testing.T) { Namespace: gw.Namespace, Name: "envoy-" + gw.Name, }, + LoadBalancer: fmt.Sprintf("service:%s/envoy-%s", gw.Namespace, gw.Name), }, } diff --git a/internal/provisioner/objects/contourconfig/contourconfig.go b/internal/provisioner/objects/contourconfig/contourconfig.go index 14bf5a864ef..ee19e3b63a4 100644 --- a/internal/provisioner/objects/contourconfig/contourconfig.go +++ b/internal/provisioner/objects/contourconfig/contourconfig.go @@ -15,6 +15,7 @@ package contourconfig import ( "context" + "fmt" contour_api_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1" "github.com/projectcontour/contour/internal/provisioner/model" @@ -72,10 +73,7 @@ func setGatewayConfig(config *contour_api_v1alpha1.ContourConfiguration, contour Namespace: contour.Namespace, Name: contour.EnvoyServiceName(), } - config.Spec.Envoy.Ingress = &contour_api_v1alpha1.NamespacedName{ - Namespace: contour.Namespace, - Name: contour.EnvoyIngressName(), - } + config.Spec.Envoy.LoadBalancer = fmt.Sprintf("service:%s/%s", contour.Namespace, contour.EnvoyServiceName()) } // EnsureContourConfigDeleted deletes a ContourConfig for the provided contour, if the configured owner labels exist. diff --git a/internal/provisioner/objects/contourconfig/contourconfig_test.go b/internal/provisioner/objects/contourconfig/contourconfig_test.go index 6f5487076da..0078e7f107a 100644 --- a/internal/provisioner/objects/contourconfig/contourconfig_test.go +++ b/internal/provisioner/objects/contourconfig/contourconfig_test.go @@ -53,6 +53,7 @@ func TestEnsureContourConfig(t *testing.T) { Namespace: "contour-namespace-1", Name: "envoy-contour-1", }, + LoadBalancer: "service:contour-namespace-1/envoy-contour-1", }, }, }, @@ -80,6 +81,7 @@ func TestEnsureContourConfig(t *testing.T) { Namespace: "contour-namespace-1", Name: "envoy-contour-1", }, + LoadBalancer: "service:contour-namespace-1/envoy-contour-1", }, }, }, @@ -95,6 +97,7 @@ func TestEnsureContourConfig(t *testing.T) { Namespace: "contour-namespace-1", Name: "envoy-contour-1", }, + LoadBalancer: "service:contour-namespace-1/envoy-contour-1", }, }, }, @@ -122,6 +125,7 @@ func TestEnsureContourConfig(t *testing.T) { Namespace: "yet-another-namespace", Name: "some-other-envoy-service", }, + LoadBalancer: "service:contour-namespace-1/envoy-contour-1", }, }, }, @@ -137,6 +141,7 @@ func TestEnsureContourConfig(t *testing.T) { Namespace: "contour-namespace-1", Name: "envoy-contour-1", }, + LoadBalancer: "service:contour-namespace-1/envoy-contour-1", }, }, }, @@ -164,6 +169,7 @@ func TestEnsureContourConfig(t *testing.T) { Namespace: "contour-namespace-1", Name: "envoy-contour-1", }, + LoadBalancer: "service:contour-namespace-1/envoy-contour-1", ClientCertificate: &contour_api_v1alpha1.NamespacedName{ Namespace: "client-cert-namespace", Name: "client-cert", @@ -186,6 +192,7 @@ func TestEnsureContourConfig(t *testing.T) { Namespace: "contour-namespace-1", Name: "envoy-contour-1", }, + LoadBalancer: "service:contour-namespace-1/envoy-contour-1", ClientCertificate: &contour_api_v1alpha1.NamespacedName{ Namespace: "client-cert-namespace", Name: "client-cert", diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go index bf2fc5b0672..55b1afd1242 100644 --- a/pkg/config/parameters.go +++ b/pkg/config/parameters.go @@ -644,11 +644,9 @@ type Parameters struct { // Name of the envoy service to inspect for Ingress status details. EnvoyServiceName string `yaml:"envoy-service-name,omitempty"` - // Namespace of the envoy ingress to inspect for Ingress status details. - EnvoyIngressNamespace string `yaml:"envoy-ingress-namespace,omitempty"` - - // Name of the envoy ingress to inspect for Ingress status details. - EnvoyIngressName string `yaml:"envoy-ingress-name,omitempty"` + // Identifier of ingress object for load balancer address in the format of + // (ingress|service):/, or hostname:fqdn1[,fqdn2]. + LoadBalancerStatus string `yaml:"load-balancer-status,omitempty"` // DefaultHTTPVersions defines the default set of HTTPS // versions the proxy should accept. HTTP versions are @@ -1033,8 +1031,6 @@ func Defaults() Parameters { }, EnvoyServiceName: "envoy", EnvoyServiceNamespace: contourNamespace, - EnvoyIngressName: "envoy", - EnvoyIngressNamespace: contourNamespace, DefaultHTTPVersions: []HTTPVersionType{}, Cluster: ClusterParameters{ DNSLookupFamily: AutoClusterDNSFamily, diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html index 2c5bc508f24..5f7b202088e 100644 --- a/site/content/docs/main/config/api-reference.html +++ b/site/content/docs/main/config/api-reference.html @@ -6433,6 +6433,24 @@

EnvoyConfig +loadBalancer +
+ +string + + + +(Optional) +

LoadBalancer specifies how Contour should set the ingress status address. +If provided, the value can be in one of the formats: +- hostname:: Contour will use the provided comma separated list of addresses directly. +- service:/: Contour will use the address of the designated service. +- ingress:/: Contour will use the address of the designated ingress.

+

Contour’s default is an empty string.

+ + + + http
diff --git a/site/content/docs/main/configuration.md b/site/content/docs/main/configuration.md index 06eea341d61..175663b9efd 100644 --- a/site/content/docs/main/configuration.md +++ b/site/content/docs/main/configuration.md @@ -16,52 +16,53 @@ The `contour serve` command is the main command which is used to watch for Kuber There are a number of flags that can be passed to this command which further configures how Contour operates. Many of these flags are mirrored in the [Contour Configuration File](#configuration-file). -| Flag Name | Description | -| --------------------------------------------------------------- | --------------------------------------------------------------------------------------- | -| `--config-path` | Path to base configuration | -| `--contour-config-name` | Name of the ContourConfiguration resource to use | -| `--incluster` | Use in cluster configuration | -| `--kubeconfig=` | Path to kubeconfig (if not in running inside a cluster) | -| `--xds-address=` | xDS gRPC API address | -| `--xds-port=` | xDS gRPC API port | -| `--stats-address=` | Envoy /stats interface address | -| `--stats-port=` | Envoy /stats interface port | -| `--debug-http-address=
` | Address the debug http endpoint will bind to. | -| `--debug-http-port=` | Port the debug http endpoint will bind to | -| `--http-address=` | Address the metrics HTTP endpoint will bind to | -| `--http-port=` | Port the metrics HTTP endpoint will bind to. | -| `--health-address=` | Address the health HTTP endpoint will bind to | -| `--health-port=` | Port the health HTTP endpoint will bind to | -| `--contour-cafile=` | CA bundle file name for serving gRPC with TLS | -| `--contour-cert-file=` | Contour certificate file name for serving gRPC over TLS | -| `--contour-key-file=` | Contour key file name for serving gRPC over TLS | -| `--insecure` | Allow serving without TLS secured gRPC | -| `--root-namespaces=` | Restrict contour to searching these namespaces for root ingress routes | -| `--watch-namespaces=` | Restrict contour to searching these namespaces for all resources | -| `--ingress-class-name=` | Contour IngressClass name (comma-separated list allowed) | -| `--ingress-status-address=
` | Address to set in Ingress object status | -| `--envoy-http-access-log=` | Envoy HTTP access log | -| `--envoy-https-access-log=` | Envoy HTTPS access log | -| `--envoy-service-http-address=` | Kubernetes Service address for HTTP requests | -| `--envoy-service-https-address=` | Kubernetes Service address for HTTPS requests | -| `--envoy-service-http-port=` | Kubernetes Service port for HTTP requests | -| `--envoy-service-https-port=` | Kubernetes Service port for HTTPS requests | -| `--envoy-service-name=` | Name of the Envoy service to inspect for Ingress status details. | -| `--envoy-service-namespace=` | Envoy Service Namespace | -| `--use-proxy-protocol` | Use PROXY protocol for all listeners | -| `--accesslog-format=` | Format for Envoy access logs | -| `--disable-leader-election` | Disable leader election mechanism | -| `--disable-feature=` | Do not start an informer for the specified resources. Flag can be given multiple times. | -| `--leader-election-lease-duration` | The duration of the leadership lease. | -| `--leader-election-renew-deadline` | The duration leader will retry refreshing leadership before giving up. | -| `--leader-election-retry-period` | The interval which Contour will attempt to acquire leadership lease. | -| `--leader-election-resource-name` | The name of the resource (Lease) leader election will lease. | -| `--leader-election-resource-namespace` | The namespace of the resource (Lease) leader election will lease. | -| `-d, --debug` | Enable debug logging | -| `--kubernetes-debug=` | Enable Kubernetes client debug logging | -| `--log-format=` | Log output format for Contour. Either text (default) or json. | -| `--kubernetes-client-qps=` | QPS allowed for the Kubernetes client. | -| `--kubernetes-client-burst=` | Burst allowed for the Kubernetes client. | +| Flag Name | Description | +|----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------| +| `--config-path` | Path to base configuration | +| `--contour-config-name` | Name of the ContourConfiguration resource to use | +| `--incluster` | Use in cluster configuration | +| `--kubeconfig=` | Path to kubeconfig (if not in running inside a cluster) | +| `--xds-address=` | xDS gRPC API address | +| `--xds-port=` | xDS gRPC API port | +| `--stats-address=` | Envoy /stats interface address | +| `--stats-port=` | Envoy /stats interface port | +| `--debug-http-address=
` | Address the debug http endpoint will bind to. | +| `--debug-http-port=` | Port the debug http endpoint will bind to | +| `--http-address=` | Address the metrics HTTP endpoint will bind to | +| `--http-port=` | Port the metrics HTTP endpoint will bind to. | +| `--health-address=` | Address the health HTTP endpoint will bind to | +| `--health-port=` | Port the health HTTP endpoint will bind to | +| `--contour-cafile=` | CA bundle file name for serving gRPC with TLS | +| `--contour-cert-file=` | Contour certificate file name for serving gRPC over TLS | +| `--contour-key-file=` | Contour key file name for serving gRPC over TLS | +| `--insecure` | Allow serving without TLS secured gRPC | +| `--root-namespaces=` | Restrict contour to searching these namespaces for root ingress routes | +| `--watch-namespaces=` | Restrict contour to searching these namespaces for all resources | +| `--ingress-class-name=` | Contour IngressClass name (comma-separated list allowed) | +| `--ingress-status-address=
` | Address to set in Ingress object status | +| `--envoy-http-access-log=` | Envoy HTTP access log | +| `--envoy-https-access-log=` | Envoy HTTPS access log | +| `--envoy-service-http-address=` | Kubernetes Service address for HTTP requests | +| `--envoy-service-https-address=` | Kubernetes Service address for HTTPS requests | +| `--envoy-service-http-port=` | Kubernetes Service port for HTTP requests | +| `--envoy-service-https-port=` | Kubernetes Service port for HTTPS requests | +| `--envoy-service-name=` | Name of the Envoy service to inspect for Ingress status details. | +| `--envoy-service-namespace=` | Envoy Service Namespace | +| `--use-proxy-protocol` | Use PROXY protocol for all listeners | +| `--accesslog-format=` | Format for Envoy access logs | +| `--disable-leader-election` | Disable leader election mechanism | +| `--disable-feature=` | Do not start an informer for the specified resources. Flag can be given multiple times. | +| `--leader-election-lease-duration` | The duration of the leadership lease. | +| `--leader-election-renew-deadline` | The duration leader will retry refreshing leadership before giving up. | +| `--leader-election-retry-period` | The interval which Contour will attempt to acquire leadership lease. | +| `--leader-election-resource-name` | The name of the resource (Lease) leader election will lease. | +| `--leader-election-resource-namespace` | The namespace of the resource (Lease) leader election will lease. | +| `--load-balancer-status= | Address to set (kind=hostname) or the source to inspect for ingress status (kind=service or ingress). | +| `-d, --debug` | Enable debug logging | +| `--kubernetes-debug=` | Enable Kubernetes client debug logging | +| `--log-format=` | Log output format for Contour. Either text (default) or json. | +| `--kubernetes-client-qps=` | QPS allowed for the Kubernetes client. | +| `--kubernetes-client-burst=` | Burst allowed for the Kubernetes client. | ## Configuration File