Skip to content

Commit f3d3ea5

Browse files
committed
fix: discover mounted geoip db files (kubernetes#7228)
* fix: discover mounted geoip db files * add test * fix runtime reload of config.MaxmindEditionFiles * add e2e test * log missing geoip2 db
1 parent 7b550d5 commit f3d3ea5

File tree

6 files changed

+127
-10
lines changed

6 files changed

+127
-10
lines changed

cmd/nginx/flags.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,17 @@ https://blog.maxmind.com/2019/12/18/significant-changes-to-accessing-and-using-g
308308
}
309309

310310
var err error
311-
if (nginx.MaxmindLicenseKey != "" || nginx.MaxmindMirror != "") && nginx.MaxmindEditionIDs != "" {
311+
if nginx.MaxmindEditionIDs != "" {
312312
if err = nginx.ValidateGeoLite2DBEditions(); err != nil {
313313
return false, nil, err
314314
}
315-
klog.InfoS("downloading maxmind GeoIP2 databases")
316-
if err = nginx.DownloadGeoLite2DB(nginx.MaxmindRetriesCount, nginx.MaxmindRetriesTimeout); err != nil {
317-
klog.ErrorS(err, "unexpected error downloading GeoIP2 database")
315+
if nginx.MaxmindLicenseKey != "" || nginx.MaxmindMirror != "" {
316+
klog.InfoS("downloading maxmind GeoIP2 databases")
317+
if err = nginx.DownloadGeoLite2DB(nginx.MaxmindRetriesCount, nginx.MaxmindRetriesTimeout); err != nil {
318+
klog.ErrorS(err, "unexpected error downloading GeoIP2 database")
319+
}
318320
}
319-
config.MaxmindEditionFiles = nginx.MaxmindEditionFiles
321+
config.MaxmindEditionFiles = &nginx.MaxmindEditionFiles
320322
}
321323

322324
return false, config, err

internal/ingress/controller/config/config.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ type TemplateConfig struct {
925925
ListenPorts *ListenPorts
926926
PublishService *apiv1.Service
927927
EnableMetrics bool
928-
MaxmindEditionFiles []string
928+
MaxmindEditionFiles *[]string
929929
MonitorMaxBatchSize int
930930

931931
PID string

internal/ingress/controller/controller.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ type Configuration struct {
105105
ValidationWebhookKeyPath string
106106

107107
GlobalExternalAuth *ngx_config.GlobalExternalAuth
108-
MaxmindEditionFiles []string
108+
MaxmindEditionFiles *[]string
109109

110110
MonitorMaxBatchSize int
111111

internal/nginx/maxmind.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,19 @@ const (
6464

6565
// GeoLite2DBExists checks if the required databases for
6666
// the GeoIP2 NGINX module are present in the filesystem
67+
// and indexes the discovered databases for iteration in
68+
// the config.
6769
func GeoLite2DBExists() bool {
70+
files := []string{}
6871
for _, dbName := range strings.Split(MaxmindEditionIDs, ",") {
69-
if !fileExists(path.Join(geoIPPath, dbName+dbExtension)) {
72+
filename := dbName + dbExtension
73+
if !fileExists(path.Join(geoIPPath, filename)) {
74+
klog.Error(filename, " not found")
7075
return false
7176
}
77+
files = append(files, filename)
7278
}
79+
MaxmindEditionFiles = files
7380

7481
return true
7582
}
@@ -101,7 +108,6 @@ func DownloadGeoLite2DB(attempts int, period time.Duration) error {
101108
if dlError != nil {
102109
break
103110
}
104-
MaxmindEditionFiles = append(MaxmindEditionFiles, dbName+dbExtension)
105111
}
106112

107113
lastErr = dlError
@@ -217,11 +223,13 @@ func ValidateGeoLite2DBEditions() error {
217223
return nil
218224
}
219225

220-
func fileExists(filePath string) bool {
226+
func _fileExists(filePath string) bool {
221227
info, err := os.Stat(filePath)
222228
if os.IsNotExist(err) {
223229
return false
224230
}
225231

226232
return !info.IsDir()
227233
}
234+
235+
var fileExists = _fileExists

internal/nginx/maxmind_test.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package nginx
18+
19+
import (
20+
"reflect"
21+
"testing"
22+
)
23+
24+
func resetForTesting() {
25+
fileExists = _fileExists
26+
MaxmindLicenseKey = ""
27+
MaxmindEditionIDs = ""
28+
MaxmindEditionFiles = []string{}
29+
MaxmindMirror = ""
30+
}
31+
32+
func TestGeoLite2DBExists(t *testing.T) {
33+
tests := []struct {
34+
name string
35+
setup func()
36+
want bool
37+
wantFiles []string
38+
}{
39+
{
40+
name: "empty",
41+
wantFiles: []string{},
42+
},
43+
{
44+
name: "existing files",
45+
setup: func() {
46+
MaxmindEditionIDs = "GeoLite2-City,GeoLite2-ASN"
47+
fileExists = func(string) bool {
48+
return true
49+
}
50+
},
51+
want: true,
52+
wantFiles: []string{"GeoLite2-City.mmdb", "GeoLite2-ASN.mmdb"},
53+
},
54+
}
55+
for _, tt := range tests {
56+
t.Run(tt.name, func(t *testing.T) {
57+
resetForTesting()
58+
// mimics assignment in flags.go
59+
config := &MaxmindEditionFiles
60+
61+
if tt.setup != nil {
62+
tt.setup()
63+
}
64+
if got := GeoLite2DBExists(); got != tt.want {
65+
t.Errorf("GeoLite2DBExists() = %v, want %v", got, tt.want)
66+
}
67+
if !reflect.DeepEqual(MaxmindEditionFiles, tt.wantFiles) {
68+
t.Errorf("nginx.MaxmindEditionFiles = %v, want %v", MaxmindEditionFiles, tt.wantFiles)
69+
}
70+
if !reflect.DeepEqual(*config, tt.wantFiles) {
71+
t.Errorf("config.MaxmindEditionFiles = %v, want %v", *config, tt.wantFiles)
72+
}
73+
})
74+
}
75+
}

test/e2e/settings/geoip2.go

+32
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,23 @@ limitations under the License.
1717
package settings
1818

1919
import (
20+
"context"
21+
"fmt"
22+
"path/filepath"
2023
"strings"
2124

2225
"net/http"
2326

2427
"github.com/onsi/ginkgo"
28+
"github.com/stretchr/testify/assert"
2529

30+
appsv1 "k8s.io/api/apps/v1"
31+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2632
"k8s.io/ingress-nginx/test/e2e/framework"
2733
)
2834

35+
const testdataURL = "https://github.com/maxmind/MaxMind-DB/blob/5a0be1c0320490b8e4379dbd5295a18a648ff156/test-data/GeoLite2-Country-Test.mmdb?raw=true"
36+
2937
var _ = framework.DescribeSetting("Geoip2", func() {
3038
f := framework.NewDefaultFramework("geoip2")
3139

@@ -35,6 +43,30 @@ var _ = framework.DescribeSetting("Geoip2", func() {
3543
f.NewEchoDeployment()
3644
})
3745

46+
ginkgo.It("should include geoip2 line in config when enabled and db file exists", func() {
47+
edition := "GeoLite2-Country"
48+
49+
err := f.UpdateIngressControllerDeployment(func(deployment *appsv1.Deployment) error {
50+
args := deployment.Spec.Template.Spec.Containers[0].Args
51+
args = append(args, "--maxmind-edition-ids="+edition)
52+
deployment.Spec.Template.Spec.Containers[0].Args = args
53+
_, err := f.KubeClientSet.AppsV1().Deployments(f.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{})
54+
return err
55+
})
56+
assert.Nil(ginkgo.GinkgoT(), err, "updating ingress controller deployment flags")
57+
58+
filename := fmt.Sprintf("/etc/nginx/geoip/%s.mmdb", edition)
59+
exec, err := f.ExecIngressPod(fmt.Sprintf(`sh -c "mkdir -p '%s' && wget -O '%s' '%s' 2>&1"`, filepath.Dir(filename), filename, testdataURL))
60+
framework.Logf(exec)
61+
assert.Nil(ginkgo.GinkgoT(), err, fmt.Sprintln("error downloading test geoip2 db", filename))
62+
63+
f.UpdateNginxConfigMapData("use-geoip2", "true")
64+
f.WaitForNginxConfiguration(
65+
func(cfg string) bool {
66+
return strings.Contains(cfg, fmt.Sprintf("geoip2 %s", filename))
67+
})
68+
})
69+
3870
ginkgo.It("should only allow requests from specific countries", func() {
3971
ginkgo.Skip("GeoIP test are temporarily disabled")
4072

0 commit comments

Comments
 (0)