@@ -20,6 +20,7 @@ import (
20
20
"archive/tar"
21
21
"bytes"
22
22
"compress/gzip"
23
+ "crypto/sha256"
23
24
"crypto/tls"
24
25
"crypto/x509"
25
26
"errors"
@@ -45,6 +46,7 @@ import (
45
46
46
47
const (
47
48
chartCollection = "charts"
49
+ repositoryCollection = "repos"
48
50
chartFilesCollection = "files"
49
51
defaultTimeoutSeconds = 10
50
52
additionalCAFile = "/usr/local/share/ca-certificates/ca.crt"
@@ -62,7 +64,7 @@ type httpClient interface {
62
64
63
65
var netClient httpClient = & http.Client {}
64
66
65
- func parseRepoUrl (repoURL string ) (* url.URL , error ) {
67
+ func parseRepoURL (repoURL string ) (* url.URL , error ) {
66
68
repoURL = strings .TrimSpace (repoURL )
67
69
return url .ParseRequestURI (repoURL )
68
70
}
@@ -85,14 +87,30 @@ func init() {
85
87
// imported into the database as fast as possible. E.g. we want all icons for
86
88
// charts before fetching readmes for each chart and version pair.
87
89
func syncRepo (dbSession datastore.Session , repoName , repoURL string , authorizationHeader string ) error {
88
- url , err := parseRepoUrl (repoURL )
90
+ url , err := parseRepoURL (repoURL )
89
91
if err != nil {
90
92
log .WithFields (log.Fields {"url" : repoURL }).WithError (err ).Error ("failed to parse URL" )
91
93
return err
92
94
}
93
95
94
96
r := repo {Name : repoName , URL : url .String (), AuthorizationHeader : authorizationHeader }
95
- index , err := fetchRepoIndex (r )
97
+ repoBytes , err := fetchRepoIndex (r )
98
+ if err != nil {
99
+ return err
100
+ }
101
+
102
+ repoChecksum , err := getSha256 (repoBytes )
103
+ if err != nil {
104
+ return err
105
+ }
106
+
107
+ // Check if the repo has been already processed
108
+ if repoAlreadyProcessed (dbSession , repoName , repoChecksum ) {
109
+ log .WithFields (log.Fields {"url" : repoURL }).Info ("Skipping repository since there are no updates" )
110
+ return nil
111
+ }
112
+
113
+ index , err := parseRepoIndex (repoBytes )
96
114
if err != nil {
97
115
return err
98
116
}
@@ -148,9 +166,39 @@ func syncRepo(dbSession datastore.Session, repoName, repoURL string, authorizati
148
166
// Wait for the worker pools to finish processing
149
167
wg .Wait ()
150
168
169
+ // Update cache in the database
170
+ if err = updateLastCheck (dbSession , repoName , repoChecksum , time .Now ()); err != nil {
171
+ return err
172
+ }
173
+ log .WithFields (log.Fields {"url" : repoURL }).Info ("Stored repository update in cache" )
174
+
151
175
return nil
152
176
}
153
177
178
+ func getSha256 (src []byte ) (string , error ) {
179
+ f := bytes .NewReader (src )
180
+ h := sha256 .New ()
181
+ if _ , err := io .Copy (h , f ); err != nil {
182
+ return "" , err
183
+ }
184
+ return fmt .Sprintf ("%x" , h .Sum (nil )), nil
185
+ }
186
+
187
+ func repoAlreadyProcessed (dbSession datastore.Session , repoName string , checksum string ) bool {
188
+ db , closer := dbSession .DB ()
189
+ defer closer ()
190
+ lastCheck := & repoCheck {}
191
+ err := db .C (repositoryCollection ).Find (bson.M {"_id" : repoName }).One (lastCheck )
192
+ return err == nil && checksum == lastCheck .Checksum
193
+ }
194
+
195
+ func updateLastCheck (dbSession datastore.Session , repoName string , checksum string , now time.Time ) error {
196
+ db , closer := dbSession .DB ()
197
+ defer closer ()
198
+ _ , err := db .C (repositoryCollection ).UpsertId (repoName , bson.M {"$set" : bson.M {"last_update" : now , "checksum" : checksum }})
199
+ return err
200
+ }
201
+
154
202
func deleteRepo (dbSession datastore.Session , repoName string ) error {
155
203
db , closer := dbSession .DB ()
156
204
defer closer ()
@@ -167,8 +215,8 @@ func deleteRepo(dbSession datastore.Session, repoName string) error {
167
215
return err
168
216
}
169
217
170
- func fetchRepoIndex (r repo ) (* helmrepo. IndexFile , error ) {
171
- indexURL , err := parseRepoUrl (r .URL )
218
+ func fetchRepoIndex (r repo ) ([] byte , error ) {
219
+ indexURL , err := parseRepoURL (r .URL )
172
220
if err != nil {
173
221
log .WithFields (log.Fields {"url" : r .URL }).WithError (err ).Error ("failed to parse URL" )
174
222
return nil , err
@@ -203,7 +251,7 @@ func fetchRepoIndex(r repo) (*helmrepo.IndexFile, error) {
203
251
if err != nil {
204
252
return nil , err
205
253
}
206
- return parseRepoIndex ( body )
254
+ return body , nil
207
255
}
208
256
209
257
func parseRepoIndex (body []byte ) (* helmrepo.IndexFile , error ) {
@@ -433,7 +481,7 @@ func extractFilesFromTarball(filenames []string, tarf *tar.Reader) (map[string]s
433
481
434
482
func chartTarballURL (r repo , cv chartVersion ) string {
435
483
source := cv .URLs [0 ]
436
- if _ , err := parseRepoUrl (source ); err != nil {
484
+ if _ , err := parseRepoURL (source ); err != nil {
437
485
// If the chart URL is not absolute, join with repo URL. It's fine if the
438
486
// URL we build here is invalid as we can catch this error when actually
439
487
// making the request
0 commit comments