Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
k8s-ingress
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
3
Merge Requests
3
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
uplex-varnish
k8s-ingress
Commits
5b026b5b
Commit
5b026b5b
authored
Jan 07, 2019
by
Geoff Simmons
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Separate sources in pkg/varnish/vcl for spec and templating.
parent
beadac42
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
252 additions
and
191 deletions
+252
-191
doc.go
pkg/varnish/vcl/doc.go
+34
-0
spec.go
pkg/varnish/vcl/spec.go
+1
-191
template.go
pkg/varnish/vcl/template.go
+217
-0
No files found.
pkg/varnish/vcl/doc.go
0 → 100644
View file @
5b026b5b
/*
* Copyright (c) 2019 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
// Package vcl encapsulates representations of a VCL configuration
// derived from Ingress and VarnishConfig specifications, and
// checking the representations for equivalence (to check if new
// syncs are necessary). It drives the templating that generates
// VCL source code.
package
vcl
pkg/varnish/vcl/
vcl
.go
→
pkg/varnish/vcl/
spec
.go
View file @
5b026b5b
/*
* Copyright (c) 201
8
UPLEX Nils Goroll Systemoptimierung
* Copyright (c) 201
9
UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
...
...
@@ -26,24 +26,13 @@
* SUCH DAMAGE.
*/
// Package vcl encapsulates representations of a VCL configuration
// derived from Ingress and VarnishConfig specifications, and
// checking the representations for equivalence (to check if new
// syncs are necessary). It drives the templating that generates
// VCL source code.
package
vcl
import
(
"bytes"
"encoding/binary"
"fmt"
"hash"
"hash/fnv"
"path"
"regexp"
"sort"
"strings"
"text/template"
)
// Address represents an endpoint for either a backend instance
...
...
@@ -411,182 +400,3 @@ func (spec Spec) Canonical() Spec {
}
return
canon
}
var
fMap
=
template
.
FuncMap
{
"plusOne"
:
func
(
i
int
)
int
{
return
i
+
1
},
"vclMangle"
:
func
(
s
string
)
string
{
return
mangle
(
s
)
},
"aclMask"
:
func
(
bits
uint8
)
string
{
return
aclMask
(
bits
)
},
"aclCmp"
:
func
(
comparand
string
)
string
{
return
aclCmp
(
comparand
)
},
"hasXFF"
:
func
(
acls
[]
ACL
)
bool
{
return
hasXFF
(
acls
)
},
"cmpRelation"
:
func
(
cmp
CompareType
)
string
{
return
cmpRelation
(
cmp
)
},
"backendName"
:
func
(
svc
Service
,
addr
string
)
string
{
return
backendName
(
svc
,
addr
)
},
"dirName"
:
func
(
svc
Service
)
string
{
return
directorName
(
svc
)
},
"urlMatcher"
:
func
(
rule
Rule
)
string
{
return
urlMatcher
(
rule
)
},
"aclName"
:
func
(
name
string
)
string
{
return
"vk8s_"
+
mangle
(
name
)
+
"_acl"
},
}
const
(
ingTmplSrc
=
"vcl.tmpl"
shardTmplSrc
=
"self-shard.tmpl"
authTmplSrc
=
"auth.tmpl"
aclTmplSrc
=
"acl.tmpl"
)
var
(
ingressTmpl
*
template
.
Template
shardTmpl
*
template
.
Template
authTmpl
*
template
.
Template
aclTmpl
*
template
.
Template
symPattern
=
regexp
.
MustCompile
(
"^[[:alpha:]][[:word:]-]*$"
)
first
=
regexp
.
MustCompile
(
"[[:alpha:]]"
)
restIllegal
=
regexp
.
MustCompile
(
"[^[:word:]-]+"
)
)
// InitTemplates initializes templates for VCL generation.
func
InitTemplates
(
tmplDir
string
)
error
{
var
err
error
ingTmplPath
:=
path
.
Join
(
tmplDir
,
ingTmplSrc
)
shardTmplPath
:=
path
.
Join
(
tmplDir
,
shardTmplSrc
)
authTmplPath
:=
path
.
Join
(
tmplDir
,
authTmplSrc
)
aclTmplPath
:=
path
.
Join
(
tmplDir
,
aclTmplSrc
)
ingressTmpl
,
err
=
template
.
New
(
ingTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
ingTmplPath
)
if
err
!=
nil
{
return
err
}
shardTmpl
,
err
=
template
.
New
(
shardTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
shardTmplPath
)
if
err
!=
nil
{
return
err
}
authTmpl
,
err
=
template
.
New
(
authTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
authTmplPath
)
if
err
!=
nil
{
return
err
}
aclTmpl
,
err
=
template
.
New
(
aclTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
aclTmplPath
)
if
err
!=
nil
{
return
err
}
return
nil
}
func
replIllegal
(
ill
[]
byte
)
[]
byte
{
repl
:=
[]
byte
(
"_"
)
for
_
,
b
:=
range
ill
{
repl
=
append
(
repl
,
[]
byte
(
fmt
.
Sprintf
(
"%02x"
,
b
))
...
)
}
repl
=
append
(
repl
,
[]
byte
(
"_"
)
...
)
return
repl
}
// GetSrc returns the VCL generated to implement a Spec.
func
(
spec
Spec
)
GetSrc
()
(
string
,
error
)
{
var
buf
bytes
.
Buffer
if
err
:=
ingressTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
}
if
len
(
spec
.
ShardCluster
.
Nodes
)
>
0
{
if
err
:=
shardTmpl
.
Execute
(
&
buf
,
spec
.
ShardCluster
);
err
!=
nil
{
return
""
,
err
}
}
if
len
(
spec
.
ACLs
)
>
0
{
if
err
:=
aclTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
}
}
if
len
(
spec
.
Auths
)
>
0
{
if
err
:=
authTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
}
}
return
buf
.
String
(),
nil
}
func
mangle
(
s
string
)
string
{
var
mangled
string
bytes
:=
[]
byte
(
s
)
if
s
==
""
||
symPattern
.
Match
(
bytes
)
{
return
s
}
mangled
=
string
(
bytes
[
0
])
if
!
first
.
Match
(
bytes
[
0
:
1
])
{
mangled
=
"V"
+
mangled
}
rest
:=
restIllegal
.
ReplaceAllFunc
(
bytes
[
1
:
],
replIllegal
)
mangled
=
mangled
+
string
(
rest
)
return
mangled
}
func
backendName
(
svc
Service
,
addr
string
)
string
{
return
mangle
(
svc
.
Name
+
"_"
+
addr
)
}
func
directorName
(
svc
Service
)
string
{
return
mangle
(
svc
.
Name
+
"_director"
)
}
func
urlMatcher
(
rule
Rule
)
string
{
return
mangle
(
rule
.
Host
+
"_url"
)
}
func
aclMask
(
bits
uint8
)
string
{
if
bits
>
128
{
return
""
}
return
fmt
.
Sprintf
(
"/%d"
,
bits
)
}
const
(
xffFirst
=
`regsub(req.http.X-Forwarded-For,"^([^,\s]+).*","\1")`
xff2ndLast
=
`regsub(req.http.X-Forwarded-For,"^.*?([[:xdigit:]:.]+)\s*,[^,]*$","\1")`
)
func
aclCmp
(
comparand
string
)
string
{
if
strings
.
HasPrefix
(
comparand
,
"xff-"
)
||
strings
.
HasPrefix
(
comparand
,
"req.http."
)
{
if
comparand
==
"xff-first"
{
comparand
=
xffFirst
}
else
if
comparand
==
"xff-2ndlast"
{
comparand
=
xff2ndLast
}
return
fmt
.
Sprintf
(
`std.ip(%s, "0.0.0.0")`
,
comparand
)
}
return
comparand
}
func
hasXFF
(
acls
[]
ACL
)
bool
{
for
_
,
acl
:=
range
acls
{
if
strings
.
HasPrefix
(
acl
.
Comparand
,
"xff-"
)
{
return
true
}
}
return
false
}
func
cmpRelation
(
cmp
CompareType
)
string
{
switch
cmp
{
case
Equal
:
return
"=="
case
NotEqual
:
return
"!="
case
Match
:
return
"~"
case
NotMatch
:
return
"!~"
default
:
return
"__INVALID_COMPARISON_TYPE__"
}
}
pkg/varnish/vcl/template.go
0 → 100644
View file @
5b026b5b
/*
* Copyright (c) 2019 UPLEX Nils Goroll Systemoptimierung
* All rights reserved
*
* Author: Geoffrey Simmons <geoffrey.simmons@uplex.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package
vcl
import
(
"bytes"
"fmt"
"path"
"regexp"
"strings"
"text/template"
)
var
fMap
=
template
.
FuncMap
{
"plusOne"
:
func
(
i
int
)
int
{
return
i
+
1
},
"vclMangle"
:
func
(
s
string
)
string
{
return
mangle
(
s
)
},
"aclMask"
:
func
(
bits
uint8
)
string
{
return
aclMask
(
bits
)
},
"aclCmp"
:
func
(
comparand
string
)
string
{
return
aclCmp
(
comparand
)
},
"hasXFF"
:
func
(
acls
[]
ACL
)
bool
{
return
hasXFF
(
acls
)
},
"cmpRelation"
:
func
(
cmp
CompareType
)
string
{
return
cmpRelation
(
cmp
)
},
"backendName"
:
func
(
svc
Service
,
addr
string
)
string
{
return
backendName
(
svc
,
addr
)
},
"dirName"
:
func
(
svc
Service
)
string
{
return
directorName
(
svc
)
},
"urlMatcher"
:
func
(
rule
Rule
)
string
{
return
urlMatcher
(
rule
)
},
"aclName"
:
func
(
name
string
)
string
{
return
"vk8s_"
+
mangle
(
name
)
+
"_acl"
},
}
const
(
ingTmplSrc
=
"vcl.tmpl"
shardTmplSrc
=
"self-shard.tmpl"
authTmplSrc
=
"auth.tmpl"
aclTmplSrc
=
"acl.tmpl"
)
var
(
ingressTmpl
*
template
.
Template
shardTmpl
*
template
.
Template
authTmpl
*
template
.
Template
aclTmpl
*
template
.
Template
symPattern
=
regexp
.
MustCompile
(
"^[[:alpha:]][[:word:]-]*$"
)
first
=
regexp
.
MustCompile
(
"[[:alpha:]]"
)
restIllegal
=
regexp
.
MustCompile
(
"[^[:word:]-]+"
)
)
// InitTemplates initializes templates for VCL generation.
func
InitTemplates
(
tmplDir
string
)
error
{
var
err
error
ingTmplPath
:=
path
.
Join
(
tmplDir
,
ingTmplSrc
)
shardTmplPath
:=
path
.
Join
(
tmplDir
,
shardTmplSrc
)
authTmplPath
:=
path
.
Join
(
tmplDir
,
authTmplSrc
)
aclTmplPath
:=
path
.
Join
(
tmplDir
,
aclTmplSrc
)
ingressTmpl
,
err
=
template
.
New
(
ingTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
ingTmplPath
)
if
err
!=
nil
{
return
err
}
shardTmpl
,
err
=
template
.
New
(
shardTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
shardTmplPath
)
if
err
!=
nil
{
return
err
}
authTmpl
,
err
=
template
.
New
(
authTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
authTmplPath
)
if
err
!=
nil
{
return
err
}
aclTmpl
,
err
=
template
.
New
(
aclTmplSrc
)
.
Funcs
(
fMap
)
.
ParseFiles
(
aclTmplPath
)
if
err
!=
nil
{
return
err
}
return
nil
}
func
replIllegal
(
ill
[]
byte
)
[]
byte
{
repl
:=
[]
byte
(
"_"
)
for
_
,
b
:=
range
ill
{
repl
=
append
(
repl
,
[]
byte
(
fmt
.
Sprintf
(
"%02x"
,
b
))
...
)
}
repl
=
append
(
repl
,
[]
byte
(
"_"
)
...
)
return
repl
}
// GetSrc returns the VCL generated to implement a Spec.
func
(
spec
Spec
)
GetSrc
()
(
string
,
error
)
{
var
buf
bytes
.
Buffer
if
err
:=
ingressTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
}
if
len
(
spec
.
ShardCluster
.
Nodes
)
>
0
{
if
err
:=
shardTmpl
.
Execute
(
&
buf
,
spec
.
ShardCluster
);
err
!=
nil
{
return
""
,
err
}
}
if
len
(
spec
.
ACLs
)
>
0
{
if
err
:=
aclTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
}
}
if
len
(
spec
.
Auths
)
>
0
{
if
err
:=
authTmpl
.
Execute
(
&
buf
,
spec
);
err
!=
nil
{
return
""
,
err
}
}
return
buf
.
String
(),
nil
}
func
mangle
(
s
string
)
string
{
var
mangled
string
bytes
:=
[]
byte
(
s
)
if
s
==
""
||
symPattern
.
Match
(
bytes
)
{
return
s
}
mangled
=
string
(
bytes
[
0
])
if
!
first
.
Match
(
bytes
[
0
:
1
])
{
mangled
=
"V"
+
mangled
}
rest
:=
restIllegal
.
ReplaceAllFunc
(
bytes
[
1
:
],
replIllegal
)
mangled
=
mangled
+
string
(
rest
)
return
mangled
}
func
backendName
(
svc
Service
,
addr
string
)
string
{
return
mangle
(
svc
.
Name
+
"_"
+
addr
)
}
func
directorName
(
svc
Service
)
string
{
return
mangle
(
svc
.
Name
+
"_director"
)
}
func
urlMatcher
(
rule
Rule
)
string
{
return
mangle
(
rule
.
Host
+
"_url"
)
}
func
aclMask
(
bits
uint8
)
string
{
if
bits
>
128
{
return
""
}
return
fmt
.
Sprintf
(
"/%d"
,
bits
)
}
const
(
xffFirst
=
`regsub(req.http.X-Forwarded-For,"^([^,\s]+).*","\1")`
xff2ndLast
=
`regsub(req.http.X-Forwarded-For,"^.*?([[:xdigit:]:.]+)\s*,[^,]*$","\1")`
)
func
aclCmp
(
comparand
string
)
string
{
if
strings
.
HasPrefix
(
comparand
,
"xff-"
)
||
strings
.
HasPrefix
(
comparand
,
"req.http."
)
{
if
comparand
==
"xff-first"
{
comparand
=
xffFirst
}
else
if
comparand
==
"xff-2ndlast"
{
comparand
=
xff2ndLast
}
return
fmt
.
Sprintf
(
`std.ip(%s, "0.0.0.0")`
,
comparand
)
}
return
comparand
}
func
hasXFF
(
acls
[]
ACL
)
bool
{
for
_
,
acl
:=
range
acls
{
if
strings
.
HasPrefix
(
acl
.
Comparand
,
"xff-"
)
{
return
true
}
}
return
false
}
func
cmpRelation
(
cmp
CompareType
)
string
{
switch
cmp
{
case
Equal
:
return
"=="
case
NotEqual
:
return
"!="
case
Match
:
return
"~"
case
NotMatch
:
return
"!~"
default
:
return
"__INVALID_COMPARISON_TYPE__"
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment