diff --git a/apis/projectcontour/v1alpha1/contourconfig.go b/apis/projectcontour/v1alpha1/contourconfig.go
index 16845ac6b55..9a4730e6eef 100644
--- a/apis/projectcontour/v1alpha1/contourconfig.go
+++ b/apis/projectcontour/v1alpha1/contourconfig.go
@@ -239,6 +239,16 @@ type EnvoyConfig struct {
// +optional
Service *NamespacedName `json:"service,omitempty"`
+ // LoadBalancer specifies how Contour should set the ingress status address.
+ // If provided, the value can be in one of the formats:
+ // - address:
: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ // - 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.
+ // +optional
+ LoadBalancer string `json:"loadBalancer,omitempty"`
+
// Defines the HTTP Listener for Envoy.
//
// Contour's default is { address: "0.0.0.0", port: 8080, accessLog: "/dev/stdout" }.
diff --git a/cmd/contour/serve.go b/cmd/contour/serve.go
index 16a00bdd283..c30056f8740 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"
@@ -168,6 +169,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,18 +676,7 @@ 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,
- gatewayRef: gatewayRef,
- statusUpdater: sh.Writer(),
- statusAddress: contourConfiguration.Ingress.StatusAddress,
- serviceName: contourConfiguration.Envoy.Service.Name,
- serviceNamespace: contourConfiguration.Envoy.Service.Namespace,
- }
- if err := s.mgr.Add(lbsw); err != nil {
+ if err := s.setupIngressLoadBalancerStatusWriter(contourConfiguration, ingressClassNames, gatewayRef, sh.Writer()); err != nil {
return err
}
@@ -711,6 +703,136 @@ func (s *Server) doServe() error {
return s.mgr.Start(signals.SetupSignalHandler())
}
+func (s *Server) setupIngressLoadBalancerStatusWriter(
+ contourConfiguration contour_v1alpha1.ContourConfigurationSpec,
+ ingressClassNames []string,
+ gatewayRef *types.NamespacedName,
+ statusUpdater k8s.StatusUpdater,
+) error {
+ lbsw := &loadBalancerStatusWriter{
+ log: s.log.WithField("context", "loadBalancerStatusWriter"),
+ cache: s.mgr.GetCache(),
+ lbStatus: make(chan core_v1.LoadBalancerStatus, 1),
+ ingressClassNames: ingressClassNames,
+ gatewayRef: gatewayRef,
+ statusUpdater: statusUpdater,
+ statusAddress: contourConfiguration.Ingress.StatusAddress,
+ serviceName: contourConfiguration.Envoy.Service.Name,
+ serviceNamespace: contourConfiguration.Envoy.Service.Namespace,
+ }
+ if err := s.mgr.Add(lbsw); err != nil {
+ return err
+ }
+
+ elbs := &envoyLoadBalancerStatus{}
+ if lbAddress := contourConfiguration.Ingress.StatusAddress; len(lbAddress) > 0 {
+ 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: elbs.Name,
+ LBStatus: lbsw.lbStatus,
+ Log: s.log.WithField("context", "serviceStatusLoadBalancerWatcher"),
+ }
+
+ var handler cache.ResourceEventHandler = serviceHandler
+ if elbs.Namespace != "" {
+ handler = k8s.NewNamespaceFilter([]string{elbs.Namespace}, handler)
+ }
+
+ if err := s.informOnResource(&core_v1.Service{}, handler); err != nil {
+ 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{
+ IngressName: elbs.Name,
+ LBStatus: lbsw.lbStatus,
+ Log: s.log.WithField("context", "ingressStatusLoadBalancerWatcher"),
+ }
+
+ var handler cache.ResourceEventHandler = ingressHandler
+ if elbs.Namespace != "" {
+ handler = k8s.NewNamespaceFilter([]string{elbs.Namespace}, handler)
+ }
+
+ 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)
+ }
+
+ return nil
+}
+
+type envoyLoadBalancerStatus struct {
+ Kind string
+ FQDNs string
+ config.NamespacedName
+}
+
+func (elbs *envoyLoadBalancerStatus) String() string {
+ if elbs.Kind == "hostname" {
+ return fmt.Sprintf("%s:%s", elbs.Kind, elbs.FQDNs)
+ }
+ 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)
+ }
+
+ if parts[1] == "" {
+ return nil, fmt.Errorf("invalid load-balancer-status: empty object reference")
+ }
+
+ 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)
+ }
+
+ return &elbs, nil
+}
+
func (s *Server) getExtensionSvcConfig(name, namespace string) (xdscache_v3.ExtensionServiceConfig, error) {
extensionSvc := &contour_v1alpha1.ExtensionService{}
key := client.ObjectKey{
diff --git a/cmd/contour/serve_test.go b/cmd/contour/serve_test.go
index 1cf5439a337..16af85a4b0f 100644
--- a/cmd/contour/serve_test.go
+++ b/cmd/contour/serve_test.go
@@ -24,6 +24,7 @@ import (
contour_v1alpha1 "github.com/projectcontour/contour/apis/projectcontour/v1alpha1"
"github.com/projectcontour/contour/internal/dag"
+ "github.com/projectcontour/contour/pkg/config"
)
func TestGetDAGBuilder(t *testing.T) {
@@ -256,3 +257,108 @@ 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)
+ require.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)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), tt.error)
+ })
+ }
+}
diff --git a/cmd/contour/servecontext.go b/cmd/contour/servecontext.go
index 8c4ee27d73b..3ba0d688438 100644
--- a/cmd/contour/servecontext.go
+++ b/cmd/contour/servecontext.go
@@ -612,6 +612,7 @@ func (ctx *serveContext) convertToContourConfigurationSpec() contour_v1alpha1.Co
EnvoyStripTrailingHostDot: &ctx.Config.Network.EnvoyStripTrailingHostDot,
},
OMEnforcedHealth: envoyOMEnforcedHealthListenerConfig,
+ LoadBalancer: ctx.Config.LoadBalancerStatus,
},
Gateway: gatewayConfig,
HTTPProxy: &contour_v1alpha1.HTTPProxyConfig{
diff --git a/examples/contour/01-crds.yaml b/examples/contour/01-crds.yaml
index c84529ae934..9c986b0ad99 100644
--- a/examples/contour/01-crds.yaml
+++ b/examples/contour/01-crds.yaml
@@ -460,6 +460,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ type: string
logging:
description: Logging defines how Envoy's logs can be configured.
properties:
@@ -4323,6 +4332,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ 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 051d4407997..ded4749c776 100644
--- a/examples/render/contour-deployment.yaml
+++ b/examples/render/contour-deployment.yaml
@@ -679,6 +679,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ type: string
logging:
description: Logging defines how Envoy's logs can be configured.
properties:
@@ -4542,6 +4551,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ 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 b81e837487f..8a937d71e05 100644
--- a/examples/render/contour-gateway-provisioner.yaml
+++ b/examples/render/contour-gateway-provisioner.yaml
@@ -471,6 +471,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ type: string
logging:
description: Logging defines how Envoy's logs can be configured.
properties:
@@ -4334,6 +4343,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ 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 a8929c25144..c76a682f6e3 100644
--- a/examples/render/contour-gateway.yaml
+++ b/examples/render/contour-gateway.yaml
@@ -496,6 +496,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ type: string
logging:
description: Logging defines how Envoy's logs can be configured.
properties:
@@ -4359,6 +4368,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ 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 eb70cef9cfa..325d146bd9f 100644
--- a/examples/render/contour.yaml
+++ b/examples/render/contour.yaml
@@ -679,6 +679,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ type: string
logging:
description: Logging defines how Envoy's logs can be configured.
properties:
@@ -4542,6 +4551,15 @@ 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:
+ - address:: Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+ - 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.
+ 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 0cb5cc1daa2..fed0f6eaf9b 100644
--- a/internal/k8s/statusaddress.go
+++ b/internal/k8s/statusaddress.go
@@ -280,3 +280,85 @@ func lbStatusToGatewayAddresses(lbs core_v1.LoadBalancerStatus) []gatewayapi_v1.
return addrs
}
+
+func networkingToCoreLBStatus(lbs networking_v1.IngressLoadBalancerStatus) core_v1.LoadBalancerStatus {
+ ingress := make([]core_v1.LoadBalancerIngress, len(lbs.Ingress))
+ for i, ing := range lbs.Ingress {
+ ports := make([]core_v1.PortStatus, len(ing.Ports))
+ for j, ps := range ing.Ports {
+ ports[j] = core_v1.PortStatus{
+ Port: ps.Port,
+ Protocol: ps.Protocol,
+ Error: ps.Error,
+ }
+ }
+ ingress[i] = core_v1.LoadBalancerIngress{
+ IP: ing.IP,
+ Hostname: ing.Hostname,
+ Ports: ports,
+ }
+ }
+ return core_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 core_v1.LoadBalancerStatus
+ Log logrus.FieldLogger
+}
+
+func (s *IngressStatusLoadBalancerWatcher) OnAdd(obj any, _ bool) {
+ ingress, ok := obj.(*networking_v1.Ingress)
+ if !ok {
+ // not a service
+ return
+ }
+ if ingress.Name != s.IngressName {
+ return
+ }
+ s.Log.WithField("name", ingress.Name).
+ WithField("namespace", ingress.Namespace).
+ Debug("received new service address")
+
+ s.notify(ingress.Status.LoadBalancer)
+}
+
+func (s *IngressStatusLoadBalancerWatcher) OnUpdate(_, newObj any) {
+ ingress, ok := newObj.(*networking_v1.Ingress)
+ if !ok {
+ // not a service
+ return
+ }
+ if ingress.Name != s.IngressName {
+ return
+ }
+ s.Log.WithField("name", ingress.Name).
+ WithField("namespace", ingress.Namespace).
+ Debug("received new service address")
+
+ s.notify(ingress.Status.LoadBalancer)
+}
+
+func (s *IngressStatusLoadBalancerWatcher) OnDelete(obj any) {
+ ingress, ok := obj.(*networking_v1.Ingress)
+ if !ok {
+ // not a service
+ return
+ }
+ if ingress.Name != s.IngressName {
+ return
+ }
+ s.notify(networking_v1.IngressLoadBalancerStatus{
+ Ingress: nil,
+ })
+}
+
+func (s *IngressStatusLoadBalancerWatcher) notify(lbstatus networking_v1.IngressLoadBalancerStatus) {
+ s.LBStatus <- networkingToCoreLBStatus(lbstatus)
+}
diff --git a/internal/provisioner/model/names.go b/internal/provisioner/model/names.go
index 3f82ca1a77f..e2a3968f1a9 100644
--- a/internal/provisioner/model/names.go
+++ b/internal/provisioner/model/names.go
@@ -32,6 +32,11 @@ func (c *Contour) EnvoyServiceName() string {
return "envoy-" + c.Name
}
+// EnvoyIngressName returns the name of the Envoy Ingress resource.
+func (c *Contour) EnvoyIngressName() string {
+ return "envoy-" + c.Name
+}
+
// ContourDeploymentName returns the name of the Contour Deployment resource.
func (c *Contour) ContourDeploymentName() string {
return "contour-" + c.Name
diff --git a/internal/provisioner/objects/deployment/deployment.go b/internal/provisioner/objects/deployment/deployment.go
index 0c0b56a1113..d2ffc7e2dda 100644
--- a/internal/provisioner/objects/deployment/deployment.go
+++ b/internal/provisioner/objects/deployment/deployment.go
@@ -95,6 +95,7 @@ func DesiredDeployment(contour *model.Contour, image string) *apps_v1.Deployment
fmt.Sprintf("--contour-config-name=%s", contour.ContourConfigurationName()),
fmt.Sprintf("--leader-election-resource-name=%s", contour.LeaderElectionLeaseName()),
fmt.Sprintf("--envoy-service-name=%s", contour.EnvoyServiceName()),
+ fmt.Sprintf("--envoy-ingress-name=%s", contour.EnvoyIngressName()),
fmt.Sprintf("--kubernetes-debug=%d", contour.Spec.KubernetesLogLevel),
}
diff --git a/pkg/config/parameters.go b/pkg/config/parameters.go
index 1e4c397d513..86b75c708f8 100644
--- a/pkg/config/parameters.go
+++ b/pkg/config/parameters.go
@@ -667,6 +667,10 @@ type Parameters struct {
// Name of the envoy service to inspect for Ingress status details.
EnvoyServiceName string `yaml:"envoy-service-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
// strings of the form "HTTP/xx". Supported versions are
diff --git a/site/content/docs/main/config/api-reference.html b/site/content/docs/main/config/api-reference.html
index f985ae33037..77ffeaa17d1 100644
--- a/site/content/docs/main/config/api-reference.html
+++ b/site/content/docs/main/config/api-reference.html
@@ -6714,6 +6714,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:
+- address: : Contour will use the provided comma separated list of addresses directly. The address can be a fully qualified domain name or an IP address.
+- 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 7fd5b5c260f..74a616098b5 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
|