Commit 173ee4f4 authored by Geoff Simmons's avatar Geoff Simmons

Add the optional defaultKey field to self-sharding configuration.

XXX: currently only used for sharding by cookie. Will be extended
for use with all by=KEY cases.
parent 342a12d1
...@@ -91,6 +91,8 @@ spec: ...@@ -91,6 +91,8 @@ spec:
- SHA3_224 - SHA3_224
- SHA3_256 - SHA3_256
- SHA3_512 - SHA3_512
defaultKey:
type: string
conditions: conditions:
type: array type: array
minItems: 1 minItems: 1
......
...@@ -58,6 +58,11 @@ deploy-shard-by-cookie-helm: ...@@ -58,6 +58,11 @@ deploy-shard-by-cookie-helm:
@helm install viking-ingress-shard-by-cookie \ @helm install viking-ingress-shard-by-cookie \
$(CHARTDIR)/viking-test-app --values values-shard-by-cookie.yaml $(CHARTDIR)/viking-test-app --values values-shard-by-cookie.yaml
deploy-shard-by-cookie-default-helm:
@helm install viking-ingress-shard-by-cookie-default \
$(CHARTDIR)/viking-test-app \
--values values-shard-by-cookie-default.yaml
deploy-primary-only-by-clientid-helm: deploy-primary-only-by-clientid-helm:
@helm install viking-ingress-primary-only-by-clientid $(CHARTDIR)/viking-test-app \ @helm install viking-ingress-primary-only-by-clientid $(CHARTDIR)/viking-test-app \
--values values-primary-only-by-clientid.yaml --values values-primary-only-by-clientid.yaml
...@@ -98,6 +103,9 @@ verify: ...@@ -98,6 +103,9 @@ verify:
verify-cookie: verify-cookie:
$(mkdir)/verify-cookie.sh $(mkdir)/verify-cookie.sh
verify-cookie-default:
$(mkdir)/verify-cookie-default.sh
wait: wait:
@echo Waiting until varnish-ingress Pods are not configured for Ingress @echo Waiting until varnish-ingress Pods are not configured for Ingress
$(TESTDIR)/wait.sh app=varnish-ingress $(TESTDIR)/wait.sh app=varnish-ingress
...@@ -126,6 +134,10 @@ undeploy-shard-by-cookie-helm: ...@@ -126,6 +134,10 @@ undeploy-shard-by-cookie-helm:
@helm uninstall viking-ingress-shard-by-cookie @helm uninstall viking-ingress-shard-by-cookie
$(MAKE) wait $(MAKE) wait
undeploy-shard-by-cookie-default-helm:
@helm uninstall viking-ingress-shard-by-cookie-default
$(MAKE) wait
undeploy-primary-only-by-clientid-helm: undeploy-primary-only-by-clientid-helm:
@helm uninstall viking-ingress-primary-only-by-clientid @helm uninstall viking-ingress-primary-only-by-clientid
$(MAKE) wait $(MAKE) wait
...@@ -201,6 +213,8 @@ deploy-shard-by-key: deploy-shard-by-key-helm ...@@ -201,6 +213,8 @@ deploy-shard-by-key: deploy-shard-by-key-helm
undeploy-shard-by-key: undeploy-shard-by-key-helm undeploy-shard-by-key: undeploy-shard-by-key-helm
deploy-shard-by-cookie: deploy-shard-by-cookie-helm deploy-shard-by-cookie: deploy-shard-by-cookie-helm
undeploy-shard-by-cookie: undeploy-shard-by-cookie-helm undeploy-shard-by-cookie: undeploy-shard-by-cookie-helm
deploy-shard-by-cookie-default: deploy-shard-by-cookie-default-helm
undeploy-shard-by-cookie-default: undeploy-shard-by-cookie-default-helm
deploy-primary-only-by-clientid: deploy-primary-only-by-clientid-helm deploy-primary-only-by-clientid: deploy-primary-only-by-clientid-helm
undeploy-primary-only-by-clientid: undeploy-primary-only-by-clientid-helm undeploy-primary-only-by-clientid: undeploy-primary-only-by-clientid-helm
deploy-shard-conditions: deploy-shard-conditions-helm deploy-shard-conditions: deploy-shard-conditions-helm
...@@ -225,7 +239,9 @@ undeploy: undeploy-shard-by-key ...@@ -225,7 +239,9 @@ undeploy: undeploy-shard-by-key
else ifeq ($(EXAMPLE),shard-by-cookie) else ifeq ($(EXAMPLE),shard-by-cookie)
deploy: deploy-shard-by-cookie deploy: deploy-shard-by-cookie
undeploy: undeploy-shard-by-cookie undeploy: undeploy-shard-by-cookie
verify: verify-cookie else ifeq ($(EXAMPLE),shard-by-cookie-default)
deploy: deploy-shard-by-cookie-default
undeploy: undeploy-shard-by-cookie-default
else ifeq ($(EXAMPLE),primary-only-by-clientid) else ifeq ($(EXAMPLE),primary-only-by-clientid)
deploy: deploy-primary-only-by-clientid deploy: deploy-primary-only-by-clientid
undeploy: undeploy-primary-only-by-clientid undeploy: undeploy-primary-only-by-clientid
...@@ -234,7 +250,7 @@ deploy: deploy-shard-conditions ...@@ -234,7 +250,7 @@ deploy: deploy-shard-conditions
undeploy: undeploy-shard-conditions undeploy: undeploy-shard-conditions
else else
deploy undeploy: deploy undeploy:
$(error EXAMPLE must be set to self-sharding, shard-conditions, primary-only[-by-clientid], or shard-by-[digest|url|key|cookie]) $(error EXAMPLE must be set to self-sharding, shard-conditions, primary-only[-by-clientid], or shard-by-[digest|url|key|cookie[-default]])
endif endif
.PHONY: all $(MAKECMDGOALS) .PHONY: all $(MAKECMDGOALS)
# looks like -*- vcl -*-
varnishtest "cafe example with self-sharding by Cookie, and default key"
# The beresp may send Connection:close, if Varnish went to pipe due to
# primary-only. So we run each test in a separate connection.
client c1 -connect "${localhost} ${localport}" {
txreq -url /coffee/foo -hdr "Host: cafe.example.com" \
-hdr "Cookie: baz=quux; foo=abcdefghijklmnopqrstuvwxyz; 47=11"
rxresp
expect resp.status == 200
expect resp.body ~ "(?m)^URI: /coffee/foo$"
expect resp.body ~ "(?m)^Server name: coffee-[a-z0-9]+-[a-z0-9]+$"
} -run
client c1 -connect "${localhost} ${localport}" {
txreq -url /tea/bar -hdr "Host: cafe.example.com" \
-hdr "Cookie: baz=quux; foo=foobar"
rxresp
expect resp.status == 200
expect resp.body ~ "(?m)^URI: /tea/bar"
expect resp.body ~ "(?m)^Server name: tea-[a-z0-9]+-[a-z0-9]+$"
} -run
client c1 -connect "${localhost} ${localport}" {
txreq -url /coffee/baz -hdr "Host: cafe.example.com" \
-hdr "Cookie: foo=47; baz=quux"
rxresp
expect resp.status == 200
expect resp.body ~ "(?m)^URI: /coffee/baz"
expect resp.body ~ "(?m)^Server name: coffee-[a-z0-9]+-[a-z0-9]+$"
} -run
client c1 -connect "${localhost} ${localport}" {
txreq -url /tea/quux -hdr "Host: cafe.example.com" \
-hdr "Cookie: foo=fighter"
rxresp
expect resp.status == 200
expect resp.body ~ "(?m)^URI: /tea/quux"
expect resp.body ~ "(?m)^Server name: tea-[a-z0-9]+-[a-z0-9]+$"
} -run
client c1 -connect "${localhost} ${localport}" {
txreq -url /coffee/foo -hdr "Host: cafe.example.com" \
-hdr "Cookie: baz=quux; 47=11"
rxresp
expect resp.status == 200
expect resp.body ~ "(?m)^URI: /coffee/foo$"
expect resp.body ~ "(?m)^Server name: coffee-[a-z0-9]+-[a-z0-9]+$"
} -run
client c1 -connect "${localhost} ${localport}" {
txreq -url /coffee/foo -hdr "Host: cafe.example.com"
rxresp
expect resp.status == 200
expect resp.body ~ "(?m)^URI: /coffee/foo$"
expect resp.body ~ "(?m)^Server name: coffee-[a-z0-9]+-[a-z0-9]+$"
} -run
apps:
coffee:
image: nginxdemos/hello:plain-text
replicas: 2
tea:
image: nginxdemos/hello:plain-text
replicas: 3
ingress:
name: cafe-ingress
rules:
- host: cafe.example.com
paths:
- path: /tea
type: Prefix
app: tea
- path: /coffee
type: Prefix
app: coffee
vikingAdmSvc: varnish-ingress-admin
selfSharding:
rules:
- shard:
key: cookie=foo
primaryOnly: true
defaultKey: ""
# Use reqDisposition to bypass builtin vcl_recv so that responses to
# requests with the Cookie head may be cacheable.
# cf. "cookie pass" in examples/req-disposition
reqDisposition:
- conditions:
- comparand: req.http.Host
compare: not-exists
- comparand: req.esi_level
count: 0
- comparand: req.proto
compare: prefix
values:
- HTTP/1.1
match-flags:
case-sensitive: false
disposition:
action: synth
status: 400
- conditions:
- comparand: req.method
compare: not-equal
values:
- GET
- HEAD
- PUT
- POST
- TRACE
- OPTIONS
- DELETE
- PATCH
- CONNECT
disposition:
action: synth
status: 405
- conditions:
- comparand: req.method
compare: not-equal
values:
- GET
- HEAD
disposition:
action: pass
#! /bin/bash -ex
MYDIR=$(dirname ${BASH_SOURCE[0]})
source ${MYDIR}/../../test/utils.sh
LOCALPORT=${LOCALPORT:-8888}
wait_until_ready app=varnish-ingress
wait_until_configured app=varnish-ingress
kubectl port-forward svc/varnish-ingress ${LOCALPORT}:80 >/dev/null &
trap 'kill $(jobs -p)' EXIT
wait_for_port ${LOCALPORT}
# XXX hackish, see the comments in verify.sh
sleep 10
varnishtest ${TESTOPTS} -Dlocalport=${LOCALPORT} cafe-cookie-default.vtc
...@@ -76,9 +76,10 @@ type ShardRule struct { ...@@ -76,9 +76,10 @@ type ShardRule struct {
// ShardSpec specifies the configuration details for sharding. // ShardSpec specifies the configuration details for sharding.
type ShardSpec struct { type ShardSpec struct {
Key string `json:"key,omitempty"` Key string `json:"key,omitempty"`
Digest string `json:"digest,omitempty"` Digest string `json:"digest,omitempty"`
PrimaryOnly bool `json:"primaryOnly,omitempty"` DefaultKey *string `json:"defaultKey,omitempty"`
PrimaryOnly bool `json:"primaryOnly,omitempty"`
} }
// ProbeSpec specifies health probes for self-sharding and BackendConfig. // ProbeSpec specifies health probes for self-sharding and BackendConfig.
......
...@@ -446,6 +446,7 @@ func (worker *NamespaceWorker) configSharding(spec *vcl.Spec, ...@@ -446,6 +446,7 @@ func (worker *NamespaceWorker) configSharding(spec *vcl.Spec,
vclRule := vcl.ShardRule{ vclRule := vcl.ShardRule{
Conditions: reqConds2vclConds(rule.Conditions), Conditions: reqConds2vclConds(rule.Conditions),
PrimaryOnly: rule.Sharding.PrimaryOnly, PrimaryOnly: rule.Sharding.PrimaryOnly,
DefaultKey: rule.Sharding.DefaultKey,
By: vcl.ByHash, By: vcl.ByHash,
} }
if rule.Sharding.Digest != "" && if rule.Sharding.Digest != "" &&
......
...@@ -31,7 +31,6 @@ package vcl ...@@ -31,7 +31,6 @@ package vcl
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"strconv"
"text/template" "text/template"
) )
...@@ -151,7 +150,15 @@ sub vcl_recv { ...@@ -151,7 +150,15 @@ sub vcl_recv {
{{- digest_update 'c' $rule }} {{- digest_update 'c' $rule }}
{{- if isCookieKey $rule }} {{- if isCookieKey $rule }}
if (!vk8s_shard_cookie_{{$ridx}}.match(req.http.Cookie)) { if (!vk8s_shard_cookie_{{$ridx}}.match(req.http.Cookie)) {
{{- if hasDefaultKey $rule }}
set req.http.VK8S-Shard-Key = "{{ $rule.DefaultKey }}";
{{- else }}
return (synth(400)); return (synth(400));
{{- end }}
}
else {
set req.http.VK8S-Shard-Key
= vk8s_shard_cookie_{{$ridx}}.backref(1);
} }
{{- end }} {{- end }}
vk8s_cluster_primary.set(vk8s_cluster.backend(resolve=NOW vk8s_cluster_primary.set(vk8s_cluster.backend(resolve=NOW
...@@ -190,7 +197,15 @@ sub vk8s_cluster_fetch { ...@@ -190,7 +197,15 @@ sub vk8s_cluster_fetch {
{{- digest_update 'b' $rule }} {{- digest_update 'b' $rule }}
{{- if isCookieKey $rule }} {{- if isCookieKey $rule }}
if (!vk8s_shard_cookie_{{$ridx}}.match(bereq.http.Cookie)) { if (!vk8s_shard_cookie_{{$ridx}}.match(bereq.http.Cookie)) {
{{- if hasDefaultKey $rule }}
set bereq.http.VK8S-Shard-Key = "{{ $rule.DefaultKey }}";
{{- else }}
return (error(400)); return (error(400));
{{- end }}
}
else {
set bereq.http.VK8S-Shard-Key
= vk8s_shard_cookie_{{$ridx}}.backref(1);
} }
{{- end }} {{- end }}
vk8s_cluster_param.set({{ key 'b' $rule $ridx }}); vk8s_cluster_param.set({{ key 'b' $rule $ridx }});
...@@ -257,8 +272,10 @@ func context(ctx rune, key string) string { ...@@ -257,8 +272,10 @@ func context(ctx rune, key string) string {
func keyParams(ctx rune, rule ShardRule, idx int) string { func keyParams(ctx rune, rule ShardRule, idx int) string {
pfx := "" pfx := ""
http := "bereq"
if ctx == 'c' { if ctx == 'c' {
pfx = ", " pfx = ", "
http = "req"
} }
switch rule.By { switch rule.By {
case ByHash: case ByHash:
...@@ -269,8 +286,8 @@ func keyParams(ctx rune, rule ShardRule, idx int) string { ...@@ -269,8 +286,8 @@ func keyParams(ctx rune, rule ShardRule, idx int) string {
return pfx + "by=KEY, key=vk8s_cluster.key(" + return pfx + "by=KEY, key=vk8s_cluster.key(" +
context(ctx, rule.Key) + ")" context(ctx, rule.Key) + ")"
case Cookie: case Cookie:
return pfx + "by=KEY, key=vk8s_cluster.key(vk8s_shard_cookie_" + return pfx + "by=KEY, key=vk8s_cluster.key(" + http +
strconv.Itoa(idx) + ".backref(1))" ".http.VK8S-Shard-Key)"
} }
return pfx + "by=BLOB, key_blob=vk8s_shard_digest.final()" return pfx + "by=BLOB, key_blob=vk8s_shard_digest.final()"
} }
...@@ -279,6 +296,10 @@ func isCookieKey(rule ShardRule) bool { ...@@ -279,6 +296,10 @@ func isCookieKey(rule ShardRule) bool {
return rule.By == Cookie return rule.By == Cookie
} }
func hasDefaultKey(rule ShardRule) bool {
return rule.DefaultKey != nil
}
func digestInit(rule ShardRule) string { func digestInit(rule ShardRule) string {
if rule.By != Blob { if rule.By != Blob {
return "" return ""
...@@ -336,6 +357,7 @@ const selfShardName = "self-sharding" ...@@ -336,6 +357,7 @@ const selfShardName = "self-sharding"
var shardFuncMap = template.FuncMap{ var shardFuncMap = template.FuncMap{
"key": keyParams, "key": keyParams,
"isCookieKey": isCookieKey, "isCookieKey": isCookieKey,
"hasDefaultKey": hasDefaultKey,
"digest_init": digestInit, "digest_init": digestInit,
"digest_update": digestUpdate, "digest_update": digestUpdate,
"hasPrimary": hasPrimary, "hasPrimary": hasPrimary,
......
...@@ -30,6 +30,7 @@ package vcl ...@@ -30,6 +30,7 @@ package vcl
import ( import (
"bytes" "bytes"
_ "io/ioutil"
"testing" "testing"
) )
...@@ -150,3 +151,16 @@ func TestShardByCookie(t *testing.T) { ...@@ -150,3 +151,16 @@ func TestShardByCookie(t *testing.T) {
varnishCluster.Rules[0].Key = "foobar" varnishCluster.Rules[0].Key = "foobar"
templateTest(t, shardTmpl, varnishCluster, "shard_by_cookie.golden") templateTest(t, shardTmpl, varnishCluster, "shard_by_cookie.golden")
} }
func TestShardByCookieDefault(t *testing.T) {
defaultKey := "defaultKey"
varnishCluster.Rules = []ShardRule{{
PrimaryOnly: true,
By: Cookie,
Key: "bazquux",
DefaultKey: &defaultKey,
Conditions: []Condition{},
}}
templateTest(t, shardTmpl, varnishCluster,
"shard_by_cookie_default.golden")
}
...@@ -432,6 +432,7 @@ const ( ...@@ -432,6 +432,7 @@ const (
// conditions under which the configuration holds. // conditions under which the configuration holds.
type ShardRule struct { type ShardRule struct {
Conditions []Condition Conditions []Condition
DefaultKey *string
Key string Key string
By KeyBy By KeyBy
Algo HashAlgo Algo HashAlgo
......
...@@ -82,7 +82,11 @@ sub vcl_recv { ...@@ -82,7 +82,11 @@ sub vcl_recv {
if (!vk8s_shard_cookie_0.match(req.http.Cookie)) { if (!vk8s_shard_cookie_0.match(req.http.Cookie)) {
return (synth(400)); return (synth(400));
} }
vk8s_cluster_primary.set(vk8s_cluster.backend(resolve=NOW, by=KEY, key=vk8s_cluster.key(vk8s_shard_cookie_0.backref(1)))); else {
set req.http.VK8S-Shard-Key
= vk8s_shard_cookie_0.backref(1);
}
vk8s_cluster_primary.set(vk8s_cluster.backend(resolve=NOW, by=KEY, key=vk8s_cluster.key(req.http.VK8S-Shard-Key)));
if (remote.ip !~ vk8s_cluster_acl if (remote.ip !~ vk8s_cluster_acl
&& "" + vk8s_cluster_primary.get() != server.identity) { && "" + vk8s_cluster_primary.get() != server.identity) {
set req.backend_hint = vk8s_cluster_primary.get(); set req.backend_hint = vk8s_cluster_primary.get();
......
...@@ -87,6 +87,9 @@ make EXAMPLE=shard-by-key deploy verify undeploy ...@@ -87,6 +87,9 @@ make EXAMPLE=shard-by-key deploy verify undeploy
echo Self-sharding by cookie example echo Self-sharding by cookie example
make EXAMPLE=shard-by-cookie deploy verify-cookie undeploy make EXAMPLE=shard-by-cookie deploy verify-cookie undeploy
echo Self-sharding by cookie with default key example
make EXAMPLE=shard-by-cookie-default deploy verify-cookie-default undeploy
echo Primary-only self-sharding by client.identity as key echo Primary-only self-sharding by client.identity as key
make EXAMPLE=primary-only-by-clientid deploy verify undeploy make EXAMPLE=primary-only-by-clientid deploy verify undeploy
......
...@@ -703,7 +703,15 @@ templates: ...@@ -703,7 +703,15 @@ templates:
{{- digest_update 'c' $rule }} {{- digest_update 'c' $rule }}
{{- if isCookieKey $rule }} {{- if isCookieKey $rule }}
if (!vk8s_shard_cookie_{{$ridx}}.match(req.http.Cookie)) { if (!vk8s_shard_cookie_{{$ridx}}.match(req.http.Cookie)) {
{{- if hasDefaultKey $rule }}
set req.http.VK8S-Shard-Key = "{{ $rule.DefaultKey }}";
{{- else }}
return (synth(400)); return (synth(400));
{{- end }}
}
else {
set req.http.VK8S-Shard-Key
= vk8s_shard_cookie_{{$ridx}}.backref(1);
} }
{{- end }} {{- end }}
vk8s_cluster_primary.set(vk8s_cluster.backend(resolve=NOW vk8s_cluster_primary.set(vk8s_cluster.backend(resolve=NOW
...@@ -742,7 +750,15 @@ templates: ...@@ -742,7 +750,15 @@ templates:
{{- digest_update 'b' $rule }} {{- digest_update 'b' $rule }}
{{- if isCookieKey $rule }} {{- if isCookieKey $rule }}
if (!vk8s_shard_cookie_{{$ridx}}.match(bereq.http.Cookie)) { if (!vk8s_shard_cookie_{{$ridx}}.match(bereq.http.Cookie)) {
{{- if hasDefaultKey $rule }}
set bereq.http.VK8S-Shard-Key = "{{ $rule.DefaultKey }}";
{{- else }}
return (error(400)); return (error(400));
{{- end }}
}
else {
set bereq.http.VK8S-Shard-Key
= vk8s_shard_cookie_{{$ridx}}.backref(1);
} }
{{- end }} {{- end }}
vk8s_cluster_param.set({{ key 'b' $rule $ridx }}); vk8s_cluster_param.set({{ key 'b' $rule $ridx }});
......
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