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
|