Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/heptio/contour
Browse files Browse the repository at this point in the history
* 'master' of https://github.com/heptio/contour:
  Remove alias field
  internal/envoy: dry up Cluster_CommonLbConfig generation
  internal/contour: simplify cluster visitor
  internal/e2e: remove context.WithTimeout from steam* helpers
  internal/envoy: move TLSContext preparation to a helper
  internal/envoy: move h2/h2c protocol configuration into internal/envoy
  internal/contour: move v2.Cluster construction into internal/envoy
  internal/envoy: move apiconfigsource into internal/envoy
  internal/envoy: move more helpers into internal/envoy
  • Loading branch information
josebiro committed Oct 12, 2018
2 parents 134ef07 + 68842b8 commit 3b04268
Show file tree
Hide file tree
Showing 24 changed files with 788 additions and 330 deletions.
6 changes: 3 additions & 3 deletions apis/contour/v1beta1/ingressroute.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ type IngressRouteSpec struct {
// to be a "root".
type VirtualHost struct {
// The fully qualified domain name of the root of the ingress tree
// all leaves of the DAG rooted at this object relate to the fqdn (and its aliases)
// all leaves of the DAG rooted at this object relate to the fqdn
Fqdn string `json:"fqdn"`
// If present describes tls properties. The CNI names that will be matched on
// are described in fqdn and aliases, the tls.secretName secret must contain a
// are described in fqdn, the tls.secretName secret must contain a
// matching certificate
TLS *TLS `json:"tls,omitempty"`
}

// TLS describes tls properties. The CNI names that will be matched on
// are described in fqdn and aliases, the tls.secretName secret must contain a
// are described in fqdn, the tls.secretName secret must contain a
// matching certificate
type TLS struct {
// required, the name of a secret in the current namespace
Expand Down
5 changes: 0 additions & 5 deletions deployment/common/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ spec:
fqdn:
type: string
pattern: ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-z]{2,}$
aliases:
type: array
items:
type: string
pattern: ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$
tls:
properties:
secretName:
Expand Down
5 changes: 0 additions & 5 deletions deployment/ds-hostnet-split/01-common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,6 @@ spec:
fqdn:
type: string
pattern: ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-z]{2,}$
aliases:
type: array
items:
type: string
pattern: ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$
tls:
properties:
secretName:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ metadata:
spec:
virtualhost:
fqdn: bar.com
aliases:
- www.bar.com
routes:
- match: /
services:
Expand Down
5 changes: 0 additions & 5 deletions deployment/render/daemonset-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@ spec:
fqdn:
type: string
pattern: ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-z]{2,}$
aliases:
type: array
items:
type: string
pattern: ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$
tls:
properties:
secretName:
Expand Down
5 changes: 0 additions & 5 deletions deployment/render/deployment-rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,6 @@ spec:
fqdn:
type: string
pattern: ^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-z]{2,}$
aliases:
type: array
items:
type: string
pattern: ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$
tls:
properties:
secretName:
Expand Down
13 changes: 3 additions & 10 deletions design/ingressroute-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The working model for delegation is DNS.
As the owner of a DNS domain, for example `.com`, I _delegate_ to another nameserver the responsibility for handing the subdomain `heptio.com`.
Any nameserver can hold a record for `heptio.com`, but without the linkage from the parent `.com` TLD, its information is unreachable and non authoritative.

Each _root_ of a DAG starts at a virtual host, which describes properties such as the fully qualified name of the virtual host, any aliases of the vhost (for example, a `www.` prefix), TLS configuration, and possibly global access list details.
Each _root_ of a DAG starts at a virtual host, which describes properties such as the fully qualified name of the virtual host, TLS configuration, and possibly global access list details.
The vertices of a graph do not contain virtual host information.
Instead they are reachable from a root only by delegation.
This permits the _owner_ of an ingress root to both delegate the authority to publish a service on a portion of the route space inside a virtual host, and to further delegate authority to publish and delegate.
Expand All @@ -59,15 +59,10 @@ spec:
# to be a "root".
virtualhost:
# the fully qualified domain name of the root of the ingress tree
# all leaves of the DAG rooted at this object relate to the fqdn (and its aliases)
# all leaves of the DAG rooted at this object relate to the fqdn
fqdn: www.google.com
# a set of aliases for the domain, these may be alternative fqdns which are considered
# aliases of the primary fqdn
aliases:
- www.google.com.au
- google.com
# if present describes tls properties. The CNI names that will be matched on
# are described in fqdn and aliases, the tls.secretName secret must contain a
# are described in fqdn, the tls.secretName secret must contain a
# matching certificate
tls:
# required, the name of a secret in the current namespace
Expand Down Expand Up @@ -282,8 +277,6 @@ metadata:
spec:
virtualhost:
fqdn: heptio.com
aliases:
- www.heptio.com
routes:
- match: /
# delegate everything to heptio-wordpress/wordpress
Expand Down
177 changes: 6 additions & 171 deletions internal/contour/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,12 @@ package contour
import (
"sync"

"strings"
"time"

"github.com/envoyproxy/go-control-plane/envoy/api/v2"
"github.com/envoyproxy/go-control-plane/envoy/api/v2/auth"
"github.com/envoyproxy/go-control-plane/envoy/api/v2/cluster"
"github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
envoy_type "github.com/envoyproxy/go-control-plane/envoy/type"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
ingressroutev1 "github.com/heptio/contour/apis/contour/v1beta1"
"github.com/heptio/contour/internal/dag"
"github.com/heptio/contour/internal/envoy"
)

const (
// Default healthcheck / lb algorithm values
hcTimeout = 2 * time.Second
hcInterval = 10 * time.Second
hcUnhealthyThreshold = 3
hcHealthyThreshold = 2
hcHost = "contour-envoy-healthcheck"
)

// ClusterCache manages the contents of the gRPC CDS cache.
type ClusterCache struct {
clusterCache
Expand Down Expand Up @@ -120,160 +102,13 @@ func (v *clusterVisitor) Visit() map[string]*v2.Cluster {

func (v *clusterVisitor) visit(vertex dag.Vertex) {
if service, ok := vertex.(*dag.Service); ok {
v.edscluster(service)
}
// recurse into children of v
vertex.Visit(v.visit)
}

func (v *clusterVisitor) edscluster(svc *dag.Service) {
name := envoy.Clustername(svc)
if _, ok := v.clusters[name]; ok {
// already created this cluster via another edge. skip it.
return
}

c := &v2.Cluster{
Name: name,
Type: v2.Cluster_EDS,
EdsClusterConfig: edsconfig("contour", svc),
ConnectTimeout: 250 * time.Millisecond,
LbPolicy: edslbstrategy(svc.LoadBalancerStrategy),
CommonLbConfig: &v2.Cluster_CommonLbConfig{
HealthyPanicThreshold: &envoy_type.Percent{ // Disable HealthyPanicThreshold
Value: 0,
},
},
}

// Set HealthCheck if requested
if svc.HealthCheck != nil {
c.HealthChecks = edshealthcheck(svc.HealthCheck)
}

if svc.MaxConnections > 0 || svc.MaxPendingRequests > 0 || svc.MaxRequests > 0 || svc.MaxRetries > 0 {
c.CircuitBreakers = &cluster.CircuitBreakers{
Thresholds: []*cluster.CircuitBreakers_Thresholds{{
MaxConnections: uint32OrNil(svc.MaxConnections),
MaxPendingRequests: uint32OrNil(svc.MaxPendingRequests),
MaxRequests: uint32OrNil(svc.MaxRequests),
MaxRetries: uint32OrNil(svc.MaxRetries),
}},
}
}

switch svc.Protocol {
case "h2":
c.Http2ProtocolOptions = &core.Http2ProtocolOptions{}
c.TlsContext = &auth.UpstreamTlsContext{
CommonTlsContext: &auth.CommonTlsContext{
AlpnProtocols: []string{"h2"},
},
}
case "h2c":
c.Http2ProtocolOptions = &core.Http2ProtocolOptions{}
}
v.clusters[c.Name] = c
}

func edslbstrategy(lbStrategy string) v2.Cluster_LbPolicy {
switch lbStrategy {
case "WeightedLeastRequest":
return v2.Cluster_LEAST_REQUEST
case "RingHash":
return v2.Cluster_RING_HASH
case "Maglev":
return v2.Cluster_MAGLEV
case "Random":
return v2.Cluster_RANDOM
default:
return v2.Cluster_ROUND_ROBIN
}
}

func edshealthcheck(hc *ingressroutev1.HealthCheck) []*core.HealthCheck {
host := hcHost
if hc.Host != "" {
host = hc.Host
}

// TODO(dfc) why do we need to specify our own default, what is the default
// that envoy applies if these fields are left nil?
return []*core.HealthCheck{{
Timeout: secondsOrDefault(hc.TimeoutSeconds, hcTimeout),
Interval: secondsOrDefault(hc.IntervalSeconds, hcInterval),
UnhealthyThreshold: countOrDefault(hc.UnhealthyThresholdCount, hcUnhealthyThreshold),
HealthyThreshold: countOrDefault(hc.HealthyThresholdCount, hcHealthyThreshold),
HealthChecker: &core.HealthCheck_HttpHealthCheck_{
HttpHealthCheck: &core.HealthCheck_HttpHealthCheck{
Path: hc.Path,
Host: host,
},
},
}}
}

func secondsOrDefault(seconds int64, def time.Duration) *time.Duration {
if seconds != 0 {
t := time.Duration(seconds) * time.Second
return &t
}
return &def
}

func countOrDefault(count, def uint32) *types.UInt32Value {
if count != 0 {
return &types.UInt32Value{
Value: count,
name := envoy.Clustername(service)
if _, ok := v.clusters[name]; !ok {
c := envoy.Cluster(service)
v.clusters[c.Name] = c
}
}
return &types.UInt32Value{
Value: def,
}
}

// uint32OrNil returns a *types.UInt32Value containing the v or nil if v is zero.
func uint32OrNil(i int) *types.UInt32Value {
switch i {
case 0:
return nil
default:
return &types.UInt32Value{Value: uint32(i)}
}
}

func edsconfig(source string, service *dag.Service) *v2.Cluster_EdsClusterConfig {
name := []string{
service.Namespace(),
service.Name(),
service.ServicePort.Name,
}
if name[2] == "" {
name = name[:2]
}
return &v2.Cluster_EdsClusterConfig{
EdsConfig: apiconfigsource(source), // hard coded by initconfig
ServiceName: strings.Join(name, "/"),
}
}

func apiconfigsource(clusters ...string) *core.ConfigSource {
services := make([]*core.GrpcService, 0, len(clusters))
for _, c := range clusters {
services = append(services, &core.GrpcService{
TargetSpecifier: &core.GrpcService_EnvoyGrpc_{
EnvoyGrpc: &core.GrpcService_EnvoyGrpc{
ClusterName: c,
},
},
})
}
return &core.ConfigSource{
ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{
ApiConfigSource: &core.ApiConfigSource{
ApiType: core.ApiConfigSource_GRPC,
GrpcServices: services,
},
},
}
// recurse into children of v
vertex.Visit(v.visit)
}
Loading

0 comments on commit 3b04268

Please sign in to comment.