Skip to content

Commit 2eb032f

Browse files
Merge pull request #139 from openshift-cherrypick-robot/cherry-pick-137-to-release-4.2
[release-4.2] Bug 1762748: Fix high memory usage
2 parents 104fe17 + 03aa0c9 commit 2eb032f

File tree

4 files changed

+142
-12
lines changed

4 files changed

+142
-12
lines changed

providers/openshift/provider.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"os"
1515
"sort"
1616
"strings"
17+
"sync"
1718
"time"
1819

1920
"github.com/bitly/go-simplejson"
@@ -29,6 +30,13 @@ import (
2930
authorizationv1beta1 "k8s.io/client-go/pkg/apis/authorization/v1beta1"
3031
)
3132

33+
// httpClientCache stores httpClient objects so that new client does not have to
34+
// be created on each request just to prevent CAs content changed
35+
// key is bytes of the hashed metadata of the files for CAs the client was
36+
// created with
37+
// NOTE: the entries of the map are currently not being cleaned up
38+
var httpClientCache sync.Map
39+
3240
func emptyURL(u *url.URL) bool {
3341
return u == nil || u.String() == ""
3442
}
@@ -131,18 +139,29 @@ func (p *OpenShiftProvider) newOpenShiftClient() (*http.Client, error) {
131139
capaths = paths
132140
system_roots = false
133141
}
142+
143+
// try to retrieve a cached client
144+
metadataHash, err := util.GetFilesMetadataHash(capaths)
145+
if httpClient, ok := httpClientCache.Load(metadataHash); ok {
146+
return httpClient.(*http.Client), nil
147+
}
148+
149+
// client not in cache, create new
134150
pool, err := util.GetCertPool(capaths, system_roots)
135151
if err != nil {
136152
return nil, err
137153
}
138154

139-
return &http.Client{
155+
httpClient := &http.Client{
140156
Jar: http.DefaultClient.Jar,
141157
Transport: &http.Transport{
142158
Proxy: http.ProxyFromEnvironment,
143159
TLSClientConfig: oscrypto.SecureTLSConfig(&tls.Config{RootCAs: pool}),
144160
},
145-
}, nil
161+
}
162+
httpClientCache.Store(metadataHash, httpClient)
163+
164+
return httpClient, nil
146165
}
147166

148167
// encodeSARWithScope adds a "scopes" array to the SAR if it does not have one already, and outputs

providers/openshift/provider_test.go

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package openshift
22

33
import (
4-
"k8s.io/apiserver/pkg/authentication/user"
5-
"k8s.io/apiserver/pkg/authorization/authorizer"
4+
"io/ioutil"
65
"net/http"
6+
"os"
77
"reflect"
88
"testing"
9+
10+
"k8s.io/apiserver/pkg/authentication/user"
11+
"k8s.io/apiserver/pkg/authorization/authorizer"
912
)
1013

1114
type mockAuthRequestHandler struct {
@@ -14,6 +17,42 @@ type mockAuthRequestHandler struct {
1417
type mockAuthorizer struct {
1518
}
1619

20+
// if you're seeing cert expiration errors on 'Nov 3 11:57:34 2119 GMT', I am sorry
21+
const longLivedCACert = `
22+
-----BEGIN CERTIFICATE-----
23+
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
53+
-----END CERTIFICATE-----
54+
`
55+
1756
func TestParseSubjectAccessReviews(t *testing.T) {
1857

1958
tests := []struct {
@@ -93,3 +132,49 @@ func TestDontPassBasicAuthentication(t *testing.T) {
93132
t.Errorf("access token should be empty string for basic authentication: %v", session)
94133
}
95134
}
135+
136+
func TestNewOpenShiftClient(t *testing.T) {
137+
tmpfile, err := ioutil.TempFile("", "osclienttest-")
138+
if err != nil {
139+
t.Fatalf("failed to create tempfile: %v", err)
140+
}
141+
defer os.Remove(tmpfile.Name())
142+
143+
_, err = tmpfile.WriteString(longLivedCACert)
144+
if err != nil {
145+
t.Fatalf("failed to write CA cert to tmpfile: %v", err)
146+
}
147+
148+
p := &OpenShiftProvider{}
149+
p.paths = recordsByPath{pathRecord{"/someurl", authorizer.AttributesRecord{}}}
150+
p.authenticator = &mockAuthRequestHandler{}
151+
p.authorizer = &mockAuthorizer{}
152+
p.SetReviewCAs([]string{tmpfile.Name()})
153+
154+
client, err := p.newOpenShiftClient()
155+
if err != nil {
156+
t.Fatalf("failed to create an OpenShift Client")
157+
}
158+
159+
newClient, err := p.newOpenShiftClient()
160+
if err != nil {
161+
t.Fatalf("failed to create a new OpenShift Client")
162+
}
163+
164+
// caching should make sure the clients are the same
165+
if client != newClient {
166+
t.Errorf("repeated call of newOpenShiftClient() returned different client pointers")
167+
}
168+
169+
// useless change but should change the metadata enough to get us a new client
170+
tmpfile.WriteString("\n")
171+
172+
newClient, err = p.newOpenShiftClient()
173+
if err != nil {
174+
t.Fatalf("failed to create a new OpenShift Client")
175+
}
176+
177+
if client == newClient {
178+
t.Errorf("repeated call of newOpenShiftClient() after one of the CA changed returned the same client pointer")
179+
}
180+
}

util/util.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package util
22

33
import (
4+
"crypto/sha256"
45
"crypto/x509"
6+
"encoding/base64"
57
"fmt"
68
"io/ioutil"
79
"log"
10+
"os"
11+
"sort"
12+
"strconv"
13+
"strings"
814
)
915

1016
func GetCertPool(paths []string, system_roots bool) (*x509.CertPool, error) {
@@ -33,3 +39,23 @@ func GetCertPool(paths []string, system_roots bool) (*x509.CertPool, error) {
3339
}
3440
return pool, nil
3541
}
42+
43+
// GetFilesMetadataHash returns base64-encoded hash of (size + name + modtime) of the file at path
44+
func GetFilesMetadataHash(paths []string) (string, error) {
45+
hashData := make([]string, 0, len(paths))
46+
47+
for _, path := range paths {
48+
meta, err := os.Stat(path)
49+
if err != nil {
50+
return "", fmt.Errorf("couldn't stat '%s': %v", path, err)
51+
}
52+
53+
hashData = append(hashData, meta.Name()+strconv.FormatInt(meta.Size(), 10)+meta.ModTime().String())
54+
}
55+
56+
// sort the strings so that the same paths in different order still generate the same hash
57+
sort.Strings(hashData)
58+
59+
h := sha256.Sum256([]byte(strings.Join(hashData, "")))
60+
return base64.StdEncoding.EncodeToString(h[:]), nil
61+
}

util/util_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
package util
22

33
import (
4-
"testing"
5-
"os"
4+
"encoding/hex"
65
"io/ioutil"
6+
"os"
77
"reflect"
8-
"encoding/hex"
8+
"testing"
99

1010
"github.com/bmizerany/assert"
1111
)
1212

1313
var (
1414
testCA1Subj = "301e311c301a060355040313136f617574682d70726f78792074657374206361"
15-
testCA1 = `-----BEGIN CERTIFICATE-----
15+
testCA1 = `-----BEGIN CERTIFICATE-----
1616
MIICuTCCAaGgAwIBAgIFAKuKEWowDQYJKoZIhvcNAQELBQAwHjEcMBoGA1UEAxMT
1717
b2F1dGgtcHJveHkgdGVzdCBjYTAeFw0xNzEwMjQyMDExMzJaFw0xOTEwMjQyMDEx
1818
MzJaMB4xHDAaBgNVBAMTE29hdXRoLXByb3h5IHRlc3QgY2EwggEiMA0GCSqGSIb3
@@ -31,7 +31,7 @@ pP5YlVqdRCVrxgT80PIMsvQhfcuIrbbeiRDEUdEX7FqebuGCEa2757MTdW7UYQiB
3131
-----END CERTIFICATE-----
3232
`
3333
testCA2Subj = "3025312330210603550403131a6f617574682d70726f7879207365636f6e642074657374206361"
34-
testCA2 = `-----BEGIN CERTIFICATE-----
34+
testCA2 = `-----BEGIN CERTIFICATE-----
3535
MIICxzCCAa+gAwIBAgIFAKuMKewwDQYJKoZIhvcNAQELBQAwJTEjMCEGA1UEAxMa
3636
b2F1dGgtcHJveHkgc2Vjb25kIHRlc3QgY2EwHhcNMTcxMDI1MTYxMTQxWhcNMTkx
3737
MDI1MTYxMTQxWjAlMSMwIQYDVQQDExpvYXV0aC1wcm94eSBzZWNvbmQgdGVzdCBj
@@ -64,18 +64,18 @@ func makeTestCertFile(t *testing.T, pem, dir string) *os.File {
6464
}
6565

6666
func TestGetCertPool(t *testing.T) {
67-
_, err := GetCertPool([]string(nil))
67+
_, err := GetCertPool([]string(nil), false)
6868
if err == nil {
6969
t.Errorf("expected an error")
7070
}
71-
assert.Equal(t, "Invalid empty list of Root CAs file paths" ,err.Error())
71+
assert.Equal(t, "Invalid empty list of Root CAs file paths", err.Error())
7272

7373
tempDir := os.TempDir()
7474
defer os.RemoveAll(tempDir)
7575
certFile1 := makeTestCertFile(t, testCA1, tempDir)
7676
certFile2 := makeTestCertFile(t, testCA2, tempDir)
7777

78-
certPool, err := GetCertPool([]string{certFile1.Name(), certFile2.Name()})
78+
certPool, err := GetCertPool([]string{certFile1.Name(), certFile2.Name()}, false)
7979
if err != nil {
8080
t.Errorf("unexpected error %v", err)
8181
}

0 commit comments

Comments
 (0)