Commit d714e1bb authored by Geoff Simmons's avatar Geoff Simmons

Add the nameTtl object to the BackendConfig CRD.

Its two fields are mapped directly to the ttl and ttl_from parameters
of VMOD dynamic.
parent dd639a1f
...@@ -45,6 +45,19 @@ spec: ...@@ -45,6 +45,19 @@ spec:
between-bytes-timeout: between-bytes-timeout:
type: string type: string
pattern: '^\d+(\.\d+)?(ms|[smhdwy])$' pattern: '^\d+(\.\d+)?(ms|[smhdwy])$'
nameTtl:
type: object
properties:
ttl:
type: string
pattern: '^\d+(\.\d+)?(ms|[smhdwy])$'
from:
type: string
enum:
- cfg
- dns
- min
- max
dnsRetryDelay: dnsRetryDelay:
type: string type: string
pattern: '^\d+(\.\d+)?(ms|[smhdwy])$' pattern: '^\d+(\.\d+)?(ms|[smhdwy])$'
......
...@@ -23,7 +23,9 @@ apps: ...@@ -23,7 +23,9 @@ apps:
threshold: 3 threshold: 3
initial: 3 initial: 3
# Configuration specific to ExternalName Services # Configuration specific to ExternalName Services
dnsRetryDelay: 25s nameTtl:
ttl: 1s
from: cfg
domainUsageTimeout: 3h domainUsageTimeout: 3h
firstLookupTimeout: 20s firstLookupTimeout: 20s
resolverTimeout: 1m resolverTimeout: 1m
...@@ -81,7 +83,9 @@ apps: ...@@ -81,7 +83,9 @@ apps:
# outstanding DNS queries. Queries above the limit are queued. # outstanding DNS queries. Queries above the limit are queued.
# - followDNSRedirects (boolean): whether DNS queries follow redirects # - followDNSRedirects (boolean): whether DNS queries follow redirects
# (CNAME and DNAME). Default true # (CNAME and DNAME). Default true
dnsRetryDelay: 20s nameTtl:
ttl: 1s
from: min
domainUsageTimeout: 1h domainUsageTimeout: 1h
firstLookupTimeout: 15s firstLookupTimeout: 15s
resolverTimeout: 45s resolverTimeout: 45s
......
...@@ -8,6 +8,9 @@ apps: ...@@ -8,6 +8,9 @@ apps:
tls: tls:
verify: false verify: false
authority: caffeine.org authority: caffeine.org
nameTtl:
ttl: 1s
from: min
coffee: coffee:
image: uplex/https-echo image: uplex/https-echo
......
...@@ -12,4 +12,8 @@ kubectl port-forward svc/varnish-ingress ${LOCALPORT}:80 >/dev/null & ...@@ -12,4 +12,8 @@ kubectl port-forward svc/varnish-ingress ${LOCALPORT}:80 >/dev/null &
trap 'kill $(jobs -p)' EXIT trap 'kill $(jobs -p)' EXIT
wait_for_port ${LOCALPORT} wait_for_port ${LOCALPORT}
# Give VMOD dynamic and DNS time to determine the IP address of the
# ExternalName Service.
sleep 10
varnishtest ${TESTOPTS} -Dlocalport=${LOCALPORT} cafe.vtc varnishtest ${TESTOPTS} -Dlocalport=${LOCALPORT} cafe.vtc
...@@ -450,6 +450,7 @@ type BackendConfigSpec struct { ...@@ -450,6 +450,7 @@ type BackendConfigSpec struct {
Probe *ProbeSpec `json:"probe,omitempty"` Probe *ProbeSpec `json:"probe,omitempty"`
Director *DirectorSpec `json:"director,omitempty"` Director *DirectorSpec `json:"director,omitempty"`
TLS *TLSSpec `json:"tls,omitempty"` TLS *TLSSpec `json:"tls,omitempty"`
NameTTL *NameTTLSpec `json:"nameTtl,omitempty"`
HostHeader string `json:"host-header,omitempty"` HostHeader string `json:"host-header,omitempty"`
ConnectTimeout string `json:"connect-timeout,omitempty"` ConnectTimeout string `json:"connect-timeout,omitempty"`
FirstByteTimeout string `json:"first-byte-timeout,omitempty"` FirstByteTimeout string `json:"first-byte-timeout,omitempty"`
...@@ -500,6 +501,30 @@ type TLSSpec struct { ...@@ -500,6 +501,30 @@ type TLSSpec struct {
CASecret string `json:"caSecret,omitempty"` CASecret string `json:"caSecret,omitempty"`
} }
// NameTTLFromType is a enumeration of the ways that the name TTL
// specified in the BackendConfig can be evaluated with respect to DNS
// TTL.
type NameTTLFromType string
const (
// FromCfg to use the TTL from the BackendConfig only (or the
// default)
FromCfg NameTTLFromType = "cfg"
// FromDNS to use the TTL from DNS only
FromDNS = "dns"
// FromMax to use the maximum of DNS TTL and the configured TTL
FromMax = "max"
// FromMin to use the minimum of DNS TTL and the configured TTL
FromMin = "min"
)
// NameTTLSpec corresponds to spec.nameTtl in a BackendConfig, and
// configures the TTL for name lookups.
type NameTTLSpec struct {
TTL *string `json:"ttl,omitempty"`
From NameTTLFromType `json:"from,omitempty"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// BackendConfigList is a list of BackendConfig Custom Resources. // BackendConfigList is a list of BackendConfig Custom Resources.
......
...@@ -198,6 +198,11 @@ func (in *BackendConfigSpec) DeepCopyInto(out *BackendConfigSpec) { ...@@ -198,6 +198,11 @@ func (in *BackendConfigSpec) DeepCopyInto(out *BackendConfigSpec) {
*out = new(TLSSpec) *out = new(TLSSpec)
(*in).DeepCopyInto(*out) (*in).DeepCopyInto(*out)
} }
if in.NameTTL != nil {
in, out := &in.NameTTL, &out.NameTTL
*out = new(NameTTLSpec)
(*in).DeepCopyInto(*out)
}
if in.MaxConnections != nil { if in.MaxConnections != nil {
in, out := &in.MaxConnections, &out.MaxConnections in, out := &in.MaxConnections, &out.MaxConnections
*out = new(int32) *out = new(int32)
...@@ -315,6 +320,27 @@ func (in *MatchFlagsType) DeepCopy() *MatchFlagsType { ...@@ -315,6 +320,27 @@ func (in *MatchFlagsType) DeepCopy() *MatchFlagsType {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NameTTLSpec) DeepCopyInto(out *NameTTLSpec) {
*out = *in
if in.TTL != nil {
in, out := &in.TTL, &out.TTL
*out = new(string)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NameTTLSpec.
func (in *NameTTLSpec) DeepCopy() *NameTTLSpec {
if in == nil {
return nil
}
out := new(NameTTLSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProbeSpec) DeepCopyInto(out *ProbeSpec) { func (in *ProbeSpec) DeepCopyInto(out *ProbeSpec) {
*out = *in *out = *in
......
...@@ -58,7 +58,6 @@ const ( ...@@ -58,7 +58,6 @@ const (
varnishSvcKey = annotationPrefix + "varnish-svc" varnishSvcKey = annotationPrefix + "varnish-svc"
defACLcomparand = "client.ip" defACLcomparand = "client.ip"
defACLfailStatus = uint16(403) defACLfailStatus = uint16(403)
defDNSRetryDelay = "30s"
defMax2ndTTL = "5m" defMax2ndTTL = "5m"
defStickTblSz = 128 defStickTblSz = 128
defMaxConn = 2000 defMaxConn = 2000
...@@ -352,7 +351,6 @@ func (worker *NamespaceWorker) getVCLSvc( ...@@ -352,7 +351,6 @@ func (worker *NamespaceWorker) getVCLSvc(
Addresses: addrs, Addresses: addrs,
ExternalName: extName, ExternalName: extName,
ExternalPort: extPort, ExternalPort: extPort,
DNSRetryDelay: defDNSRetryDelay,
FollowDNSRedirects: true, FollowDNSRedirects: true,
} }
nsLister := worker.listers.bcfg.BackendConfigs(svcNamespace) nsLister := worker.listers.bcfg.BackendConfigs(svcNamespace)
...@@ -428,6 +426,22 @@ BCfgs: ...@@ -428,6 +426,22 @@ BCfgs:
if bcfg.Spec.FollowDNSRedirects != nil { if bcfg.Spec.FollowDNSRedirects != nil {
vclSvc.FollowDNSRedirects = *bcfg.Spec.FollowDNSRedirects vclSvc.FollowDNSRedirects = *bcfg.Spec.FollowDNSRedirects
} }
if bcfg.Spec.NameTTL != nil {
vclSvc.NameTTL = &vcl.NameTTLSpec{}
if bcfg.Spec.NameTTL.TTL != nil {
vclSvc.NameTTL.TTL = *bcfg.Spec.NameTTL.TTL
}
switch bcfg.Spec.NameTTL.From {
case vcr_v1alpha1.FromCfg:
vclSvc.NameTTL.From = vcl.FromCfg
case vcr_v1alpha1.FromDNS:
vclSvc.NameTTL.From = vcl.FromDNS
case vcr_v1alpha1.FromMin:
vclSvc.NameTTL.From = vcl.FromMin
case vcr_v1alpha1.FromMax:
vclSvc.NameTTL.From = vcl.FromMax
}
}
var onload *haproxy.OnloadSpec var onload *haproxy.OnloadSpec
if bcfg.Spec.TLS != nil { if bcfg.Spec.TLS != nil {
......
...@@ -84,9 +84,13 @@ func TestExternalNameSvc(t *testing.T) { ...@@ -84,9 +84,13 @@ func TestExternalNameSvc(t *testing.T) {
} }
var extTequilaSvc = Service{ var extTequilaSvc = Service{
Name: "tequila-svc", Name: "tequila-svc",
ExternalName: "tequila.example.com", ExternalName: "tequila.example.com",
ExternalPort: "88", ExternalPort: "88",
NameTTL: &NameTTLSpec{
TTL: "2h",
From: FromCfg,
},
DNSRetryDelay: "30s", DNSRetryDelay: "30s",
FollowDNSRedirects: true, FollowDNSRedirects: true,
Probe: &Probe{ Probe: &Probe{
...@@ -107,9 +111,12 @@ var extTequilaSvc = Service{ ...@@ -107,9 +111,12 @@ var extTequilaSvc = Service{
} }
var extMetaxaSvc = Service{ var extMetaxaSvc = Service{
Name: "metaxa-svc", Name: "metaxa-svc",
ExternalName: "metaxa.example.com", ExternalName: "metaxa.example.com",
ExternalPort: "8080", ExternalPort: "8080",
NameTTL: &NameTTLSpec{
From: FromMax,
},
DNSRetryDelay: "30s", DNSRetryDelay: "30s",
FollowDNSRedirects: true, FollowDNSRedirects: true,
Probe: &Probe{ Probe: &Probe{
......
...@@ -146,6 +146,46 @@ func (dir Director) hash(hash hash.Hash) { ...@@ -146,6 +146,46 @@ func (dir Director) hash(hash hash.Hash) {
hash.Write([]byte{byte(dir.Type)}) hash.Write([]byte{byte(dir.Type)})
} }
// NameTTLFrom is a enumeration of the ways that the name TTL that was
// specified in the BackendConfig can be evaluated with respect to DNS
// TTL. This value is mapped directly to the ttl_from parameter for
// VMOD dynamic.
type NameTTLFrom uint8
const (
// FromCfg corresponds to the enum value cfg in VMOD dynamic.
FromCfg NameTTLFrom = iota
// FromDNS corresponds to enum dns in VMOD dynamic
FromDNS
// FromMin corresponds to enum min in VMOD dynamic.
FromMin
// FromMax corresponds to enum max in VMOD dynamic.
FromMax
)
func (from NameTTLFrom) String() string {
switch from {
case FromCfg:
return "cfg"
case FromDNS:
return "dns"
case FromMin:
return "min"
case FromMax:
return "max"
default:
return "__INVALID_TTL_FROM__"
}
}
// NameTTLSpec encapsulates the TTL configuration used for VMOD
// dynamic. Its fields are mapped directly to the ttl and ttl_from
// paramater of the VMOD.
type NameTTLSpec struct {
TTL string
From NameTTLFrom
}
// Service represents either a backend Service (Endpoints to which // Service represents either a backend Service (Endpoints to which
// requests are routed) or a Varnish Service (with addresses for the // requests are routed) or a Varnish Service (with addresses for the
// admin ports). // admin ports).
...@@ -154,6 +194,7 @@ type Service struct { ...@@ -154,6 +194,7 @@ type Service struct {
Addresses []Address Addresses []Address
Probe *Probe Probe *Probe
Director *Director Director *Director
NameTTL *NameTTLSpec
Authority *string Authority *string
ExternalName string ExternalName string
ExternalPort string ExternalPort string
...@@ -187,6 +228,10 @@ func (svc Service) hash(hash hash.Hash) { ...@@ -187,6 +228,10 @@ func (svc Service) hash(hash hash.Hash) {
if svc.Authority != nil { if svc.Authority != nil {
hash.Write([]byte(*svc.Authority)) hash.Write([]byte(*svc.Authority))
} }
if svc.NameTTL != nil {
hash.Write([]byte(svc.NameTTL.TTL))
hash.Write([]byte{byte(svc.NameTTL.From)})
}
hash.Write([]byte(svc.ExternalName)) hash.Write([]byte(svc.ExternalName))
hash.Write([]byte(svc.ExternalPort)) hash.Write([]byte(svc.ExternalPort))
hash.Write([]byte(svc.HostHeader)) hash.Write([]byte(svc.HostHeader))
......
...@@ -53,18 +53,18 @@ sub vcl_init { ...@@ -53,18 +53,18 @@ sub vcl_init {
new vk8s_vodka-svc_resolver = dynamic.resolver(); new vk8s_vodka-svc_resolver = dynamic.resolver();
vk8s_vodka-svc_resolver.set_resolution_type(STUB); vk8s_vodka-svc_resolver.set_resolution_type(STUB);
new vk8s_vodka-svc_director = dynamic.director( new vk8s_vodka-svc_director = dynamic.director(
ttl_from = dns,
ttl = 30s,
resolver = vk8s_vodka-svc_resolver.use() resolver = vk8s_vodka-svc_resolver.use()
, ttl_from = dns
, retry_after = 30s
, port = "8888" , port = "8888"
); );
new vk8s_whiskey-svc_resolver = dynamic.resolver(); new vk8s_whiskey-svc_resolver = dynamic.resolver();
vk8s_whiskey-svc_resolver.set_resolution_type(STUB); vk8s_whiskey-svc_resolver.set_resolution_type(STUB);
new vk8s_whiskey-svc_director = dynamic.director( new vk8s_whiskey-svc_director = dynamic.director(
ttl_from = dns,
ttl = 30s,
resolver = vk8s_whiskey-svc_resolver.use() resolver = vk8s_whiskey-svc_resolver.use()
, ttl_from = dns
, retry_after = 30s
, port = "81" , port = "81"
); );
......
...@@ -41,9 +41,9 @@ sub vcl_init { ...@@ -41,9 +41,9 @@ sub vcl_init {
new vk8s_metaxa-svc_resolver = dynamic.resolver(); new vk8s_metaxa-svc_resolver = dynamic.resolver();
vk8s_metaxa-svc_resolver.set_resolution_type(STUB); vk8s_metaxa-svc_resolver.set_resolution_type(STUB);
new vk8s_metaxa-svc_director = dynamic.director( new vk8s_metaxa-svc_director = dynamic.director(
ttl_from = dns,
ttl = 30s,
resolver = vk8s_metaxa-svc_resolver.use() resolver = vk8s_metaxa-svc_resolver.use()
, ttl_from = max
, retry_after = 30s
, port = "8080" , port = "8080"
, host_header = "metaxa.example.org" , host_header = "metaxa.example.org"
, connect_timeout = 2s , connect_timeout = 2s
...@@ -57,9 +57,9 @@ sub vcl_init { ...@@ -57,9 +57,9 @@ sub vcl_init {
new vk8s_tequila-svc_resolver = dynamic.resolver(); new vk8s_tequila-svc_resolver = dynamic.resolver();
vk8s_tequila-svc_resolver.set_resolution_type(STUB); vk8s_tequila-svc_resolver.set_resolution_type(STUB);
new vk8s_tequila-svc_director = dynamic.director( new vk8s_tequila-svc_director = dynamic.director(
ttl_from = dns,
ttl = 30s,
resolver = vk8s_tequila-svc_resolver.use() resolver = vk8s_tequila-svc_resolver.use()
, ttl = 2h
, retry_after = 30s
, port = "88" , port = "88"
, host_header = "tequila.example.org" , host_header = "tequila.example.org"
, connect_timeout = 1s , connect_timeout = 1s
......
...@@ -164,9 +164,9 @@ sub vcl_init { ...@@ -164,9 +164,9 @@ sub vcl_init {
new vk8s_metaxa-svc_resolver = dynamic.resolver(); new vk8s_metaxa-svc_resolver = dynamic.resolver();
vk8s_metaxa-svc_resolver.set_resolution_type(STUB); vk8s_metaxa-svc_resolver.set_resolution_type(STUB);
new vk8s_metaxa-svc_director = dynamic.director( new vk8s_metaxa-svc_director = dynamic.director(
ttl_from = dns,
ttl = 30s,
resolver = vk8s_metaxa-svc_resolver.use() resolver = vk8s_metaxa-svc_resolver.use()
, ttl_from = max
, retry_after = 30s
, port = "8080" , port = "8080"
, host_header = "metaxa.example.org" , host_header = "metaxa.example.org"
, connect_timeout = 2s , connect_timeout = 2s
...@@ -180,9 +180,9 @@ sub vcl_init { ...@@ -180,9 +180,9 @@ sub vcl_init {
new vk8s_tequila-svc_resolver = dynamic.resolver(); new vk8s_tequila-svc_resolver = dynamic.resolver();
vk8s_tequila-svc_resolver.set_resolution_type(STUB); vk8s_tequila-svc_resolver.set_resolution_type(STUB);
new vk8s_tequila-svc_director = dynamic.director( new vk8s_tequila-svc_director = dynamic.director(
ttl_from = dns,
ttl = 30s,
resolver = vk8s_tequila-svc_resolver.use() resolver = vk8s_tequila-svc_resolver.use()
, ttl = 2h
, retry_after = 30s
, port = "88" , port = "88"
, host_header = "tequila.example.org" , host_header = "tequila.example.org"
, connect_timeout = 1s , connect_timeout = 1s
......
...@@ -156,10 +156,21 @@ sub vcl_init { ...@@ -156,10 +156,21 @@ sub vcl_init {
new {{resolverName $svc}} = dynamic.resolver(); new {{resolverName $svc}} = dynamic.resolver();
{{resolverName $svc}}.set_resolution_type(STUB); {{resolverName $svc}}.set_resolution_type(STUB);
new {{dirName $svc}} = dynamic.director( new {{dirName $svc}} = dynamic.director(
ttl_from = dns,
ttl = {{.DNSRetryDelay}},
resolver = {{resolverName $svc}}.use() resolver = {{resolverName $svc}}.use()
{{- with $svc}} {{- with $svc}}
{{- if .NameTTL }}
{{- if .NameTTL.TTL }}
, ttl = {{ .NameTTL.TTL }}
{{- end }}
{{- if .NameTTL.From }}
, ttl_from = {{ .NameTTL.From }}
{{- end }}
{{- else }}
, ttl_from = dns
{{- end }}
{{- if .DNSRetryDelay }}
, retry_after = {{ .DNSRetryDelay }}
{{- end }}
{{- if .ExternalPort}} {{- if .ExternalPort}}
, port = "{{.ExternalPort}}" , port = "{{.ExternalPort}}"
{{- end}} {{- end}}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment