Skip to content

Commit 2da7ffb

Browse files
authored
Fix cache invalidation (#12)
Fix cache invalidation on APIResource discovery
1 parent b093b9e commit 2da7ffb

File tree

5 files changed

+64
-43
lines changed

5 files changed

+64
-43
lines changed

.github/workflows/code-checks.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ jobs:
1010
name: Go code style
1111
runs-on: ubuntu-latest
1212
steps:
13-
- name: Set up Go 1.19
13+
- name: Set up Go 1.20
1414
uses: actions/setup-go@v4
1515
with:
16-
go-version: 1.19
16+
go-version: '1.20'
1717

1818
- uses: actions/checkout@v3
1919

.github/workflows/lint.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ jobs:
1111
name: Run Go linters
1212
runs-on: ubuntu-latest
1313
steps:
14-
- name: Set up Go 1.19
14+
- name: Set up Go 1.20
1515
uses: actions/setup-go@v4
1616
with:
17-
go-version: 1.19
17+
go-version: '1.20'
1818
id: go
1919

2020
- name: Check out addon-operator code
@@ -38,7 +38,7 @@ jobs:
3838
3939
- name: Run golangci-lint
4040
run: |
41-
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b . v1.52.0
41+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b . v1.54.2
4242
./golangci-lint run --sort-results
4343
4444
codespell:

.github/workflows/tests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ jobs:
1010
name: Run unit tests
1111
runs-on: ubuntu-latest
1212
steps:
13-
- name: Set up Go 1.19
13+
- name: Set up Go 1.20
1414
uses: actions/setup-go@v4
1515
with:
16-
go-version: 1.19
16+
go-version: '1.20'
1717
id: go
1818

1919
- name: Check out addon-operator code

.golangci.yaml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ linters-settings:
3737
goimports:
3838
local-prefixes: github.com/flant/
3939
depguard:
40-
list-type: blacklist
41-
include-go-root: true
42-
packages:
43-
- github.com/evanphx/json-patch
44-
packages-with-error-message:
45-
- github.com/evanphx/json-patch: "The 'github.com/evanphx/json-patch' package is superseded. Use pkg/utils/jsonpatch.go instead."
40+
rules:
41+
Main:
42+
files:
43+
- $all
44+
deny:
45+
- pkg: github.com/evanphx/json-patch
46+
desc: "The 'github.com/evanphx/json-patch' package is superseded. Use pkg/utils/jsonpatch.go instead."
4647
issues:
4748
exclude:
4849
# Using underscores is a common practice, refactor in the future

client/client.go

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import (
66
"strings"
77
"time"
88

9+
"github.com/pkg/errors"
910
log "github.com/sirupsen/logrus"
1011
apixv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
12+
apiErrors "k8s.io/apimachinery/pkg/api/errors"
1113
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1214
"k8s.io/apimachinery/pkg/runtime"
1315
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -326,6 +328,21 @@ func getInClusterConfig() (config *rest.Config, defaultNs string, err error) {
326328
// NOTE that fetching all preferred resources can give errors if there are non-working
327329
// api controllers in cluster.
328330
func (c *Client) APIResourceList(apiVersion string) (lists []*metav1.APIResourceList, err error) {
331+
lists, err = c.apiResourceList(apiVersion)
332+
if err != nil {
333+
if errors.Cause(err).Error() == "not found" {
334+
// *errors.errorString type is here, we can't check it another way
335+
c.cachedDiscovery.Invalidate()
336+
return c.apiResourceList(apiVersion)
337+
}
338+
339+
return nil, err
340+
}
341+
342+
return lists, nil
343+
}
344+
345+
func (c *Client) apiResourceList(apiVersion string) (lists []*metav1.APIResourceList, err error) {
329346
if apiVersion == "" {
330347
// Get all preferred resources.
331348
// Can return errors if api controllers are not available.
@@ -348,56 +365,51 @@ func (c *Client) APIResourceList(apiVersion string) (lists []*metav1.APIResource
348365

349366
list, err := c.discovery().ServerResourcesForGroupVersion(gv.String())
350367
if err != nil {
351-
return nil, fmt.Errorf("apiVersion '%s' has no supported resources in cluster: %v", apiVersion, err)
368+
// if not found, err has type *errors.errorString here
369+
return nil, errors.Wrapf(err, "apiVersion '%s' has no supported resources in cluster", apiVersion)
352370
}
353371
lists = []*metav1.APIResourceList{list}
354372
}
355373

356-
// TODO should it copy group and version into each resource?
357-
358-
// TODO create debug command to output this from cli
359-
// Debug mode will list all available CRDs for apiVersion
360-
// for _, r := range list.APIResources {
361-
// log.Debugf("GVR: %30s %30s %30s", list.GroupVersion, r.Kind,
362-
// fmt.Sprintf("%+v", append([]string{r.Name}, r.ShortNames...)),
363-
// )
364-
// }
365-
366374
return
367375
}
368376

369377
// APIResource fetches APIResource object from cluster that specifies the name of a resource and whether it is namespaced.
378+
// if resource not found, we try to invalidate cache and
370379
//
371380
// NOTE that fetching with empty apiVersion can give errors if there are non-working
372381
// api controllers in cluster.
373-
func (c *Client) APIResource(apiVersion, kind string) (res *metav1.APIResource, err error) {
382+
func (c *Client) APIResource(apiVersion, kind string) (*metav1.APIResource, error) {
383+
resource, err := c.apiResource(apiVersion, kind)
384+
if err != nil {
385+
if apiErrors.IsNotFound(err) {
386+
c.cachedDiscovery.Invalidate()
387+
resource, err = c.apiResource(apiVersion, kind)
388+
} else {
389+
return nil, fmt.Errorf("apiVersion '%s', kind '%s' is not supported by cluster: %w", apiVersion, kind, err)
390+
}
391+
}
392+
if err != nil {
393+
return nil, fmt.Errorf("apiVersion '%s', kind '%s' is not supported by cluster: %w", apiVersion, kind, err)
394+
}
395+
396+
return resource, nil
397+
}
398+
399+
func (c *Client) apiResource(apiVersion, kind string) (res *metav1.APIResource, err error) {
374400
lists, err := c.APIResourceList(apiVersion)
375401
if err != nil && len(lists) == 0 {
376402
// apiVersion is defined and there is a ServerResourcesForGroupVersion error
377403
return nil, err
378404
}
379405

380406
resource := getApiResourceFromResourceLists(kind, lists)
381-
if resource != nil {
382-
return resource, nil
383-
}
384-
385-
if c.cachedDiscovery != nil {
386-
c.cachedDiscovery.Invalidate()
387-
}
388-
389-
resource = getApiResourceFromResourceLists(kind, lists)
390-
if resource != nil {
391-
return resource, nil
407+
if resource == nil {
408+
gv, _ := schema.ParseGroupVersion(apiVersion)
409+
return nil, apiErrors.NewNotFound(schema.GroupResource{Group: gv.Group, Resource: kind}, "")
392410
}
393411

394-
// If resource is not found, append additional error, may be the custom API of the resource is not available.
395-
additionalErr := ""
396-
if err != nil {
397-
additionalErr = fmt.Sprintf(", additional error: %s", err.Error())
398-
}
399-
err = fmt.Errorf("apiVersion '%s', kind '%s' is not supported by cluster%s", apiVersion, kind, additionalErr)
400-
return nil, err
412+
return resource, nil
401413
}
402414

403415
// GroupVersionResource returns a GroupVersionResource object to use with dynamic informer.
@@ -424,6 +436,14 @@ func (c *Client) discovery() discovery.DiscoveryInterface {
424436
return c.Discovery()
425437
}
426438

439+
// InvalidateDiscoveryCache allows you to invalidate cache manually, for example, when you are deploying CRD
440+
// KubeClient tries to invalidate cache automatically when needed, but you can save a few resources to call this manually
441+
func (c *Client) InvalidateDiscoveryCache() {
442+
if c.cachedDiscovery != nil {
443+
c.cachedDiscovery.Invalidate()
444+
}
445+
}
446+
427447
func equalLowerCasedToOneOf(term string, choices ...string) bool {
428448
if len(choices) == 0 {
429449
return false

0 commit comments

Comments
 (0)