Commit 1a030947 authored by Geoff Simmons's avatar Geoff Simmons

Add support for custom VCL.

parent 8c70952e
......@@ -151,6 +151,9 @@ spec:
value:
type: string
minLength: 1
vcl:
type: string
minLength: 1
status:
acceptedNames:
kind: VarnishConfig
......
......@@ -51,6 +51,7 @@ type VarnishConfig struct {
type VarnishConfigSpec struct {
Services []string `json:"services,omitempty"`
SelfSharding *SelfShardSpec `json:"self-sharding,omitempty"`
VCL string `json:"vcl,omitempty"`
Auth []AuthSpec `json:"auth,omitempty"`
ACLs []ACLSpec `json:"acl,omitempty"`
}
......
......@@ -439,6 +439,7 @@ func (worker *NamespaceWorker) addOrUpdateIng(ing *extensions.Ingress) error {
if err = worker.configACL(&vclSpec, vcfg); err != nil {
return err
}
vclSpec.VCL = vcfg.Spec.VCL
} else {
worker.log.Infof("Found no VarnishConfigs for Varnish Service "+
"%s/%s", svc.Namespace, svc.Name)
......
......@@ -322,9 +322,11 @@ type Spec struct {
// Authentication, derived from the Auth section of a
// VarnishConfig.
Auths []Auth
// VCL is custom VCL, derived from VarnishConfig.Spec.VCL.
VCL string
// ACLs is a list of specifications for whitelisting or
// blacklisting IPs with access control lists, derived from
// VarnishConfig.ACLs.
// VarnishConfig.Spec.ACLs.
ACLs []ACL
}
......@@ -348,6 +350,7 @@ func (spec Spec) DeepHash() uint64 {
spec.AllServices[svc].hash(hash)
}
spec.ShardCluster.hash(hash)
hash.Write([]byte(spec.VCL))
for _, auth := range spec.Auths {
auth.hash(hash)
}
......@@ -367,6 +370,7 @@ func (spec Spec) Canonical() Spec {
Rules: make([]Rule, len(spec.Rules)),
AllServices: make(map[string]Service, len(spec.AllServices)),
ShardCluster: spec.ShardCluster,
VCL: spec.VCL,
Auths: make([]Auth, len(spec.Auths)),
ACLs: make([]ACL, len(spec.ACLs)),
}
......
......@@ -134,6 +134,9 @@ func (spec Spec) GetSrc() (string, error) {
return "", err
}
}
if spec.VCL != "" {
buf.WriteString(spec.VCL)
}
return buf.String(), nil
}
......
vcl 4.0;
import std;
import directors;
import re2;
backend vk8s_notfound {
# 192.0.2.0/24 reserved for docs & examples (RFC5737).
.host = "192.0.2.255";
.port = "80";
}
backend vk8s_coffee-svc_192_0_2_4 {
.host = "192.0.2.4";
.port = "80";
}
backend vk8s_coffee-svc_192_0_2_5 {
.host = "192.0.2.5";
.port = "80";
}
backend vk8s_tea-svc_192_0_2_1 {
.host = "192.0.2.1";
.port = "80";
}
backend vk8s_tea-svc_192_0_2_2 {
.host = "192.0.2.2";
.port = "80";
}
backend vk8s_tea-svc_192_0_2_3 {
.host = "192.0.2.3";
.port = "80";
}
sub vcl_init {
new vk8s_hosts = re2.set(posix_syntax=true, literal=true, anchor=both);
vk8s_hosts.add("cafe.example.com");
vk8s_hosts.compile();
new vk8s_coffee-svc_director = directors.round_robin();
vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_4);
vk8s_coffee-svc_director.add_backend(vk8s_coffee-svc_192_0_2_5);
new vk8s_tea-svc_director = directors.round_robin();
vk8s_tea-svc_director.add_backend(vk8s_tea-svc_192_0_2_1);
vk8s_tea-svc_director.add_backend(vk8s_tea-svc_192_0_2_2);
vk8s_tea-svc_director.add_backend(vk8s_tea-svc_192_0_2_3);
new vk8s_cafe_example_com_url = re2.set(posix_syntax=true, anchor=start);
vk8s_cafe_example_com_url.add("/coffee",
backend=vk8s_coffee-svc_director.backend());
vk8s_cafe_example_com_url.add("/tea",
backend=vk8s_tea-svc_director.backend());
vk8s_cafe_example_com_url.compile();
}
sub vk8s_set_backend {
set req.backend_hint = vk8s_notfound;
if (vk8s_hosts.match(req.http.Host)) {
if (vk8s_hosts.nmatches() != 1) {
# Fail fast when the match was not unique.
return (fail);
}
if (0 != 0) {
#
}
elsif (vk8s_hosts.which() == 1) {
if (vk8s_cafe_example_com_url.match(req.url)) {
set req.backend_hint = vk8s_cafe_example_com_url.backend(select=FIRST);
}
}
}
if (req.backend_hint == vk8s_notfound) {
return (synth(404));
}
}
sub vcl_miss {
call vk8s_set_backend;
}
sub vcl_pass {
call vk8s_set_backend;
}
sub vcl_deliver {
set resp.http.Hello = "world";
}
\ No newline at end of file
......@@ -566,3 +566,42 @@ func TestAclTemplate(t *testing.T) {
}
}
}
var customVCLSpec = Spec{
DefaultService: Service{},
Rules: []Rule{{
Host: "cafe.example.com",
PathMap: map[string]Service{
"/tea": teaSvc,
"/coffee": coffeeSvc,
},
}},
AllServices: map[string]Service{
"tea-svc": teaSvc,
"coffee-svc": coffeeSvc,
},
VCL: `sub vcl_deliver {
set resp.http.Hello = "world";
}`,
}
func TestCustomVCL(t *testing.T) {
gold := "custom_vcl.golden"
vcl, err := customVCLSpec.GetSrc()
if err != nil {
t.Fatal("GetSrc():", err)
}
ok, err := cmpGold([]byte(vcl), gold)
if err != nil {
t.Fatalf("Reading %s: %v", gold, err)
}
if !ok {
t.Errorf("Generated VCL for custom VCL does not match gold "+
"file: %s", gold)
if testing.Verbose() {
t.Log("Generated: ", vcl)
}
}
}
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