Skip to content

Commit 471d63f

Browse files
authored
correct fix for GC of objects whose types could not be discovered (#148)
* correct fix for GC of objects whose types could not be discovered * add integration test to ensure lazy resource creation * avoid races in sio
1 parent e38447a commit 471d63f

File tree

22 files changed

+258
-51
lines changed

22 files changed

+258
-51
lines changed

.golangci.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ linters-settings:
1111
linters:
1212
disable-all: true
1313
enable:
14-
- bodyclose
1514
- deadcode
1615
- depguard
1716
- dogsled
@@ -29,5 +28,4 @@ linters:
2928
- stylecheck
3029
- typecheck
3130
- unconvert
32-
- unused
3331
- varcheck

internal/commands/apply.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func doApply(args []string, config applyCommandConfig) error {
144144
Application: config.App().Name(),
145145
Tag: config.App().Tag(),
146146
Environment: env,
147-
KindFilter: fp.kindFilter,
147+
KindFilter: fp.GVKFilter,
148148
ListQueryScope: scope,
149149
})
150150
}

internal/commands/delete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func doDelete(args []string, config deleteCommandConfig) error {
7575
Application: config.App().Name(),
7676
Tag: config.App().Tag(),
7777
Environment: env,
78-
KindFilter: fp.kindFilter,
78+
KindFilter: fp.GVKFilter,
7979
ListQueryScope: scope,
8080
})
8181
deletions, err = lister.deletions(nil, fp.Includes)

internal/commands/diff.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ func doDiff(args []string, config diffCommandConfig) error {
318318
Application: config.App().Name(),
319319
Tag: config.App().Tag(),
320320
Environment: env,
321-
KindFilter: fp.kindFilter,
321+
KindFilter: fp.GVKFilter,
322322
ListQueryScope: scope,
323323
})
324324
}

internal/commands/filter.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/splunk/qbec/internal/eval"
2424
"github.com/splunk/qbec/internal/model"
2525
"github.com/splunk/qbec/internal/sio"
26+
"k8s.io/apimachinery/pkg/runtime/schema"
2627
)
2728

2829
type filterParams struct {
@@ -32,6 +33,10 @@ type filterParams struct {
3233
componentFilter model.Filter
3334
}
3435

36+
func (f filterParams) GVKFilter(gvk schema.GroupVersionKind) bool {
37+
return f.kindFilter == nil || f.kindFilter.ShouldInclude(gvk.Kind)
38+
}
39+
3540
func (f filterParams) Includes(o model.K8sQbecMeta) bool {
3641
if !(f.kindFilter == nil || f.kindFilter.ShouldInclude(o.GetKind())) {
3742
return false

internal/commands/integration_scaffold_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ var (
2525

2626
func initialize(t *testing.T) {
2727
contextName = os.Getenv("QBEC_CONTEXT")
28-
if contextName != "" {
28+
if contextName == "" {
2929
contextName = "kind-kind"
3030
}
3131
c, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
@@ -77,3 +77,10 @@ func (s *integrationScaffold) executeCommand(testArgs ...string) error {
7777
)
7878
return s.baseScaffold.executeCommand(args...)
7979
}
80+
81+
func (s *integrationScaffold) sub() *integrationScaffold {
82+
return &integrationScaffold{
83+
baseScaffold: s.baseScaffold.sub(),
84+
ns: s.ns,
85+
}
86+
}

internal/commands/integration_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
package commands
44

55
import (
6+
"fmt"
67
"regexp"
8+
"sync"
79
"testing"
10+
"time"
811

912
"github.com/stretchr/testify/assert"
1013
"github.com/stretchr/testify/require"
@@ -99,3 +102,32 @@ func TestIntegrationBasic(t *testing.T) {
99102
a.EqualValues(2, len(stats["updated"].([]interface{})))
100103
})
101104
}
105+
106+
func TestIntegrationLazyCustomResources(t *testing.T) {
107+
dir := "testdata/projects/lazy-resources"
108+
ns, reset := newNamespace(t)
109+
defer reset()
110+
111+
extra := []string{"--vm:ext-str=suffix=" + fmt.Sprint(time.Now().Unix())}
112+
var err1, err2 error
113+
done := make(chan struct{}, 1)
114+
var wg sync.WaitGroup
115+
wg.Add(2)
116+
117+
s1 := newIntegrationScaffold(t, ns, dir)
118+
defer s1.reset()
119+
defer s1.executeCommand(append(extra, "delete", "local")...)
120+
121+
s2 := s1.sub()
122+
defer s2.reset()
123+
124+
go func() {
125+
defer func() { close(done) }()
126+
err1 = s2.executeCommand(append(extra, "apply", "-C", "crds", "local")...)
127+
require.NoError(t, err1)
128+
}()
129+
time.Sleep(2 * time.Second)
130+
err2 = s1.executeCommand(append(extra, "apply", "-k", "customresourcedefinitions", "local")...)
131+
require.NoError(t, err2)
132+
<-done
133+
}

internal/commands/remote-list.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ func (s *stubLister) deletions(ignore []model.K8sLocalObject, filter func(obj mo
4444
}
4545

4646
type remoteLister struct {
47-
client listClient
48-
ch chan listResult
49-
cfg remote.ListQueryConfig
47+
client listClient
48+
ch chan listResult
49+
cfg remote.ListQueryConfig
50+
unknownTypes map[schema.GroupVersionKind]bool
5051
}
5152

5253
type listResult struct {
@@ -90,8 +91,9 @@ func newRemoteLister(client listClient, allObjects []model.K8sLocalObject, defau
9091
sort.Strings(nsList)
9192

9293
return &remoteLister{
93-
client: client,
94-
ch: make(chan listResult, 1),
94+
client: client,
95+
ch: make(chan listResult, 1),
96+
unknownTypes: unknown,
9597
},
9698
remote.ListQueryScope{
9799
Namespaces: nsList,
@@ -102,6 +104,16 @@ func newRemoteLister(client listClient, allObjects []model.K8sLocalObject, defau
102104

103105
func (r *remoteLister) start(config remote.ListQueryConfig) {
104106
r.cfg = config
107+
if config.KindFilter == nil {
108+
config.KindFilter = func(_ schema.GroupVersionKind) bool { return true }
109+
}
110+
orig := config.KindFilter
111+
config.KindFilter = func(gvk schema.GroupVersionKind) bool {
112+
if r.unknownTypes[gvk] {
113+
return false
114+
}
115+
return orig(gvk)
116+
}
105117
go func() {
106118
start := time.Now()
107119
list, err := r.client.ListObjects(config)
@@ -120,14 +132,13 @@ func (r *remoteLister) deletions(all []model.K8sLocalObject, filter func(obj mod
120132
sio.Debugf("server objects load took %v\n", lr.duration)
121133

122134
cfg := r.cfg
123-
if cfg.KindFilter == nil {
124-
f, _ := model.NewKindFilter(nil, nil)
125-
cfg.KindFilter = f
126-
}
127135

128136
var removals []model.K8sQbecMeta
129137
for _, c := range all {
130-
if !cfg.KindFilter.ShouldInclude(c.GetKind()) {
138+
if !cfg.KindFilter(c.GroupVersionKind()) {
139+
continue
140+
}
141+
if r.unknownTypes[c.GroupVersionKind()] {
131142
continue
132143
}
133144
removals = append(removals, c)

internal/commands/setup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ func doSetup(root *cobra.Command, cf configFactory, overrideCP clientProvider) {
227227
if !cmd.Flags().Changed("colors") {
228228
cf.colors = isatty.IsTerminal(os.Stdout.Fd())
229229
}
230-
sio.EnableColors = cf.colors
230+
sio.EnableColors(cf.colors)
231231

232232
// if env file has been specified on the command line, ensure it is resolved w.r.t to the current working
233233
// directory before we change it
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1beta1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
name: foo.test.qbec.io
6+
spec:
7+
group: test.qbec.io
8+
names:
9+
kind: Foo
10+
listKind: FooList
11+
plural: foos
12+
singular: foo
13+
scope: Namespaced
14+
validation:
15+
openAPIV3Schema:
16+
description: Foo is a foo.
17+
properties:
18+
apiVersion:
19+
type: string
20+
kind:
21+
type: string
22+
metadata:
23+
type: object
24+
spec:
25+
properties:
26+
bar:
27+
description: the bar for the foo
28+
type: string
29+
required:
30+
- bar
31+
type: object
32+
status:
33+
type: object
34+
required:
35+
- metadata
36+
- spec
37+
type: object
38+
version: v1alpha1
39+
versions:
40+
- name: v1alpha1
41+
served: true
42+
storage: true

0 commit comments

Comments
 (0)