commit
34593c0f50
8 changed files with 179 additions and 13 deletions
|
@ -607,6 +607,9 @@ type Configuration struct {
|
||||||
|
|
||||||
// Block all requests with given Referer headers
|
// Block all requests with given Referer headers
|
||||||
BlockReferers []string `json:"block-referers"`
|
BlockReferers []string `json:"block-referers"`
|
||||||
|
|
||||||
|
// Lua shared dict configuration data / certificate data
|
||||||
|
LuaSharedDicts map[string]int `json:"lua-shared-dicts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDefault returns the default nginx configuration
|
// NewDefault returns the default nginx configuration
|
||||||
|
|
|
@ -59,6 +59,7 @@ const (
|
||||||
globalAuthSnippet = "global-auth-snippet"
|
globalAuthSnippet = "global-auth-snippet"
|
||||||
globalAuthCacheKey = "global-auth-cache-key"
|
globalAuthCacheKey = "global-auth-cache-key"
|
||||||
globalAuthCacheDuration = "global-auth-cache-duration"
|
globalAuthCacheDuration = "global-auth-cache-duration"
|
||||||
|
luaSharedDicts = "lua-shared-dicts"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -87,7 +88,22 @@ func ReadConfig(src map[string]string) config.Configuration {
|
||||||
blockUserAgentList := make([]string, 0)
|
blockUserAgentList := make([]string, 0)
|
||||||
blockRefererList := make([]string, 0)
|
blockRefererList := make([]string, 0)
|
||||||
responseHeaders := make([]string, 0)
|
responseHeaders := make([]string, 0)
|
||||||
|
luaSharedDict := make(map[string]int)
|
||||||
|
|
||||||
|
//parse lua shared dict values
|
||||||
|
if val, ok := conf[luaSharedDicts]; ok {
|
||||||
|
delete(conf, luaSharedDicts)
|
||||||
|
lsd := strings.Split(val, ",")
|
||||||
|
for _, v := range lsd {
|
||||||
|
v = strings.Replace(v, " ", "", -1)
|
||||||
|
results := strings.SplitN(v, ":", 2)
|
||||||
|
val, err := strconv.Atoi(results[1])
|
||||||
|
if err != nil {
|
||||||
|
klog.Warningf("%v is not a valid lua entry: %v", v, err)
|
||||||
|
}
|
||||||
|
luaSharedDict[results[0]] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
if val, ok := conf[customHTTPErrors]; ok {
|
if val, ok := conf[customHTTPErrors]; ok {
|
||||||
delete(conf, customHTTPErrors)
|
delete(conf, customHTTPErrors)
|
||||||
for _, i := range strings.Split(val, ",") {
|
for _, i := range strings.Split(val, ",") {
|
||||||
|
@ -305,6 +321,7 @@ func ReadConfig(src map[string]string) config.Configuration {
|
||||||
to.HideHeaders = hideHeadersList
|
to.HideHeaders = hideHeadersList
|
||||||
to.ProxyStreamResponses = streamResponses
|
to.ProxyStreamResponses = streamResponses
|
||||||
to.DisableIpv6DNS = !ing_net.IsIPv6Enabled()
|
to.DisableIpv6DNS = !ing_net.IsIPv6Enabled()
|
||||||
|
to.LuaSharedDicts = luaSharedDict
|
||||||
|
|
||||||
config := &mapstructure.DecoderConfig{
|
config := &mapstructure.DecoderConfig{
|
||||||
Metadata: nil,
|
Metadata: nil,
|
||||||
|
|
|
@ -74,6 +74,7 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
||||||
"nginx-status-ipv6-whitelist": "::1,2001::/16",
|
"nginx-status-ipv6-whitelist": "::1,2001::/16",
|
||||||
"proxy-add-original-uri-header": "false",
|
"proxy-add-original-uri-header": "false",
|
||||||
"disable-ipv6-dns": "true",
|
"disable-ipv6-dns": "true",
|
||||||
|
"lua-shared-dicts": "configuration_data:5,certificate_data:5",
|
||||||
}
|
}
|
||||||
def := config.NewDefault()
|
def := config.NewDefault()
|
||||||
def.CustomHTTPErrors = []int{300, 400}
|
def.CustomHTTPErrors = []int{300, 400}
|
||||||
|
@ -95,7 +96,7 @@ func TestMergeConfigMapToStruct(t *testing.T) {
|
||||||
def.NginxStatusIpv4Whitelist = []string{"127.0.0.1", "10.0.0.0/24"}
|
def.NginxStatusIpv4Whitelist = []string{"127.0.0.1", "10.0.0.0/24"}
|
||||||
def.NginxStatusIpv6Whitelist = []string{"::1", "2001::/16"}
|
def.NginxStatusIpv6Whitelist = []string{"::1", "2001::/16"}
|
||||||
def.ProxyAddOriginalURIHeader = false
|
def.ProxyAddOriginalURIHeader = false
|
||||||
|
def.LuaSharedDicts = map[string]int{"configuration_data": 5, "certificate_data": 5}
|
||||||
def.DisableIpv6DNS = true
|
def.DisableIpv6DNS = true
|
||||||
|
|
||||||
hash, err := hashstructure.Hash(def, &hashstructure.HashOptions{
|
hash, err := hashstructure.Hash(def, &hashstructure.HashOptions{
|
||||||
|
@ -303,3 +304,51 @@ func TestGlobalExternalAuthCacheDurationParsing(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLuaSharedDict(t *testing.T) {
|
||||||
|
|
||||||
|
testsCases := []struct {
|
||||||
|
name string
|
||||||
|
entry map[string]string
|
||||||
|
expect map[string]int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "lua valid entry",
|
||||||
|
entry: map[string]string{"lua-shared-dicts": "configuration_data:5,certificate_data:5"},
|
||||||
|
expect: map[string]int{"configuration_data": 5, "certificate_data": 5},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: "lua invalid entry",
|
||||||
|
entry: map[string]string{"lua-shared-dict": "configuration_data:5,certificate_data:5"},
|
||||||
|
expect: map[string]int{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lua mixed entry",
|
||||||
|
entry: map[string]string{"lua-shared-dicts": "configuration_data:10,certificate_data:5"},
|
||||||
|
expect: map[string]int{"configuration_data": 10, "certificate_data": 5},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lua valid entry - configuration_data only",
|
||||||
|
entry: map[string]string{"lua-shared-dicts": "configuration_data:5"},
|
||||||
|
expect: map[string]int{"configuration_data": 5},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lua valid entry certificate_data only",
|
||||||
|
entry: map[string]string{"lua-shared-dicts": "certificate_data:5"},
|
||||||
|
expect: map[string]int{"certificate_data": 5},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lua valid entry certificate_data only",
|
||||||
|
entry: map[string]string{"lua-shared-dicts": "configuration_data:10, my_random_dict:15,another_example:2"},
|
||||||
|
expect: map[string]int{"configuration_data": 10, "my_random_dict": 15, "another_example": 2},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for n, tc := range testsCases {
|
||||||
|
cfg := ReadConfig(tc.entry)
|
||||||
|
if !reflect.DeepEqual(cfg.LuaSharedDicts, tc.expect) {
|
||||||
|
t.Errorf("Testing %v. Expected \"%v\" but \"%v\" was returned", n, tc.expect, cfg.LuaSharedDicts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -216,18 +216,33 @@ func shouldConfigureLuaRestyWAF(disableLuaRestyWAF bool, mode string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildLuaSharedDictionaries(s interface{}, disableLuaRestyWAF bool) string {
|
func buildLuaSharedDictionaries(c interface{}, s interface{}, disableLuaRestyWAF bool) string {
|
||||||
|
|
||||||
|
var out []string
|
||||||
|
// Load config
|
||||||
|
cfg, ok := c.(config.Configuration)
|
||||||
|
if !ok {
|
||||||
|
klog.Errorf("expected a 'config.Configuration' type but %T was returned", c)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
servers, ok := s.([]*ingress.Server)
|
servers, ok := s.([]*ingress.Server)
|
||||||
if !ok {
|
if !ok {
|
||||||
klog.Errorf("expected an '[]*ingress.Server' type but %T was returned", s)
|
klog.Errorf("expected an '[]*ingress.Server' type but %T was returned", s)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
// check if config contains lua "lua_configuration_data" value otherwise, use default
|
||||||
out := []string{
|
cfgData, ok := cfg.LuaSharedDicts["configuration_data"]
|
||||||
"lua_shared_dict configuration_data 15M",
|
if !ok {
|
||||||
"lua_shared_dict certificate_data 16M",
|
cfgData = 15
|
||||||
}
|
}
|
||||||
|
out = append(out, fmt.Sprintf("lua_shared_dict configuration_data %dM", cfgData))
|
||||||
|
|
||||||
|
// check if config contains "lua_certificate_data" value otherwise, use default
|
||||||
|
certData, ok := cfg.LuaSharedDicts["certificate_data"]
|
||||||
|
if !ok {
|
||||||
|
certData = 16
|
||||||
|
}
|
||||||
|
out = append(out, fmt.Sprintf("lua_shared_dict certificate_data %dM", certData))
|
||||||
if !disableLuaRestyWAF {
|
if !disableLuaRestyWAF {
|
||||||
luaRestyWAFEnabled := func() bool {
|
luaRestyWAFEnabled := func() bool {
|
||||||
for _, server := range servers {
|
for _, server := range servers {
|
||||||
|
@ -243,7 +258,6 @@ func buildLuaSharedDictionaries(s interface{}, disableLuaRestyWAF bool) string {
|
||||||
out = append(out, "lua_shared_dict waf_storage 64M")
|
out = append(out, "lua_shared_dict waf_storage 64M")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(out, ";\n\r") + ";"
|
return strings.Join(out, ";\n\r") + ";"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,14 @@ proxy_pass http://upstream_balancer;`,
|
||||||
func TestBuildLuaSharedDictionaries(t *testing.T) {
|
func TestBuildLuaSharedDictionaries(t *testing.T) {
|
||||||
invalidType := &ingress.Ingress{}
|
invalidType := &ingress.Ingress{}
|
||||||
expected := ""
|
expected := ""
|
||||||
actual := buildLuaSharedDictionaries(invalidType, true)
|
|
||||||
|
// config lua dict
|
||||||
|
cfg := config.Configuration{
|
||||||
|
LuaSharedDicts: map[string]int{
|
||||||
|
"configuration_data": 10, "certificate_data": 20,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
actual := buildLuaSharedDictionaries(cfg, invalidType, true)
|
||||||
|
|
||||||
if !reflect.DeepEqual(expected, actual) {
|
if !reflect.DeepEqual(expected, actual) {
|
||||||
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
|
t.Errorf("Expected '%v' but returned '%v'", expected, actual)
|
||||||
|
@ -184,9 +191,9 @@ func TestBuildLuaSharedDictionaries(t *testing.T) {
|
||||||
Locations: []*ingress.Location{{Path: "/", LuaRestyWAF: luarestywaf.Config{}}},
|
Locations: []*ingress.Location{{Path: "/", LuaRestyWAF: luarestywaf.Config{}}},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
// returns value from config
|
||||||
configuration := buildLuaSharedDictionaries(servers, false)
|
configuration := buildLuaSharedDictionaries(cfg, servers, false)
|
||||||
if !strings.Contains(configuration, "lua_shared_dict configuration_data") {
|
if !strings.Contains(configuration, "lua_shared_dict configuration_data 10M;\n\rlua_shared_dict certificate_data 20M;") {
|
||||||
t.Errorf("expected to include 'configuration_data' but got %s", configuration)
|
t.Errorf("expected to include 'configuration_data' but got %s", configuration)
|
||||||
}
|
}
|
||||||
if strings.Contains(configuration, "waf_storage") {
|
if strings.Contains(configuration, "waf_storage") {
|
||||||
|
@ -194,10 +201,15 @@ func TestBuildLuaSharedDictionaries(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
servers[1].Locations[0].LuaRestyWAF = luarestywaf.Config{Mode: "ACTIVE"}
|
servers[1].Locations[0].LuaRestyWAF = luarestywaf.Config{Mode: "ACTIVE"}
|
||||||
configuration = buildLuaSharedDictionaries(servers, false)
|
configuration = buildLuaSharedDictionaries(cfg, servers, false)
|
||||||
if !strings.Contains(configuration, "lua_shared_dict waf_storage") {
|
if !strings.Contains(configuration, "lua_shared_dict waf_storage") {
|
||||||
t.Errorf("expected to configure 'waf_storage', but got %s", configuration)
|
t.Errorf("expected to configure 'waf_storage', but got %s", configuration)
|
||||||
}
|
}
|
||||||
|
// test invalid config
|
||||||
|
configuration = buildLuaSharedDictionaries(invalidType, servers, false)
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("Expected '%v' but returned '%v' ", expected, actual)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFormatIP(t *testing.T) {
|
func TestFormatIP(t *testing.T) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ http {
|
||||||
lua_package_path "/usr/local/openresty/site/lualib/?.ljbc;/usr/local/openresty/site/lualib/?/init.ljbc;/usr/local/openresty/lualib/?.ljbc;/usr/local/openresty/lualib/?/init.ljbc;/usr/local/openresty/site/lualib/?.lua;/usr/local/openresty/site/lualib/?/init.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/lualib/?/init.lua;./?.lua;/usr/local/openresty/luajit/share/luajit-2.1.0-beta3/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/openresty/luajit/share/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/?/init.lua;/usr/local/lib/lua/?.lua;;";
|
lua_package_path "/usr/local/openresty/site/lualib/?.ljbc;/usr/local/openresty/site/lualib/?/init.ljbc;/usr/local/openresty/lualib/?.ljbc;/usr/local/openresty/lualib/?/init.ljbc;/usr/local/openresty/site/lualib/?.lua;/usr/local/openresty/site/lualib/?/init.lua;/usr/local/openresty/lualib/?.lua;/usr/local/openresty/lualib/?/init.lua;./?.lua;/usr/local/openresty/luajit/share/luajit-2.1.0-beta3/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/openresty/luajit/share/lua/5.1/?.lua;/usr/local/openresty/luajit/share/lua/5.1/?/init.lua;/usr/local/lib/lua/?.lua;;";
|
||||||
lua_package_cpath "/usr/local/openresty/site/lualib/?.so;/usr/local/openresty/lualib/?.so;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/openresty/luajit/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so;/usr/local/openresty/luajit/lib/lua/5.1/?.so;;";
|
lua_package_cpath "/usr/local/openresty/site/lualib/?.so;/usr/local/openresty/lualib/?.so;./?.so;/usr/local/lib/lua/5.1/?.so;/usr/local/openresty/luajit/lib/lua/5.1/?.so;/usr/local/lib/lua/5.1/loadall.so;/usr/local/openresty/luajit/lib/lua/5.1/?.so;;";
|
||||||
|
|
||||||
{{ buildLuaSharedDictionaries $servers $all.Cfg.DisableLuaRestyWAF }}
|
{{ buildLuaSharedDictionaries $cfg $servers $all.Cfg.DisableLuaRestyWAF }}
|
||||||
|
|
||||||
init_by_lua_block {
|
init_by_lua_block {
|
||||||
collectgarbage("collect")
|
collectgarbage("collect")
|
||||||
|
|
|
@ -70,6 +70,30 @@ var _ = framework.IngressNginxDescribe("Dynamic Configuration", func() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Context("Lua shared dict", func() {
|
||||||
|
It("update config", func() {
|
||||||
|
|
||||||
|
host := "foo.com"
|
||||||
|
ingress := framework.NewSingleIngress(host, "/", host, f.Namespace, "http-svc", 80, nil)
|
||||||
|
f.EnsureIngress(ingress)
|
||||||
|
|
||||||
|
lkey := "lua-shared-dicts"
|
||||||
|
lval := "configuration_data:100,certificate_data:200"
|
||||||
|
|
||||||
|
By("update shared dict")
|
||||||
|
|
||||||
|
f.UpdateNginxConfigMapData(lkey, lval)
|
||||||
|
|
||||||
|
var nginxConfig string
|
||||||
|
f.WaitForNginxConfiguration(func(cfg string) bool {
|
||||||
|
nginxConfig = cfg
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
Expect(strings.ContainsAny(nginxConfig, "configuration_data:100M,certificate_data:200M"), true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
Context("when only backends change", func() {
|
Context("when only backends change", func() {
|
||||||
It("handles endpoints only changes", func() {
|
It("handles endpoints only changes", func() {
|
||||||
var nginxConfig string
|
var nginxConfig string
|
||||||
|
|
47
test/e2e/settings/lua_shared_dicts.go
Normal file
47
test/e2e/settings/lua_shared_dicts.go
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Copyright 2016 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package settings
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
"k8s.io/ingress-nginx/test/e2e/framework"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = framework.IngressNginxDescribe("LuaSharedDict", func() {
|
||||||
|
|
||||||
|
f := framework.NewDefaultFramework("lua-shared-dicts")
|
||||||
|
host := "lua-shared-dicts"
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
f.NewEchoDeployment()
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
})
|
||||||
|
|
||||||
|
It("update lua shared dict", func() {
|
||||||
|
ingress := framework.NewSingleIngress(host, "/", host, f.Namespace, "http-svc", 80, nil)
|
||||||
|
f.EnsureIngress(ingress)
|
||||||
|
By("update shared dict")
|
||||||
|
f.UpdateNginxConfigMapData("lua-shared-dicts", "configuration_data:123,certificate_data:456")
|
||||||
|
f.WaitForNginxConfiguration(func(cfg string) bool {
|
||||||
|
return strings.Contains(cfg, "lua_shared_dict configuration_data 123M; lua_shared_dict certificate_data 456M;")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in a new issue