Skip to content

Commit 4715a5e

Browse files
authored
Merge pull request #955 from vincepri/backport-fixes
Backports for v0.5.3
2 parents 67ee49a + 1b7c3e6 commit 4715a5e

File tree

13 files changed

+210
-39
lines changed

13 files changed

+210
-39
lines changed

pkg/client/config/config.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,8 @@ func loadConfig(context string) (*rest.Config, error) {
133133
}
134134
loadingRules.Precedence = append(loadingRules.Precedence, path.Join(u.HomeDir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName))
135135
}
136-
if c, err := loadConfigWithContext(apiServerURL, loadingRules, context); err == nil {
137-
return c, nil
138-
}
139136

140-
return nil, fmt.Errorf("could not locate a kubeconfig")
137+
return loadConfigWithContext(apiServerURL, loadingRules, context)
141138
}
142139

143140
func loadConfigWithContext(apiServerURL string, loader clientcmd.ClientConfigLoader, context string) (*rest.Config, error) {

pkg/client/options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ type MatchingLabels map[string]string
381381

382382
func (m MatchingLabels) ApplyToList(opts *ListOptions) {
383383
// TODO(directxman12): can we avoid reserializing this over and over?
384-
sel := labels.SelectorFromSet(map[string]string(m))
384+
sel := labels.SelectorFromValidatedSet(map[string]string(m))
385385
opts.LabelSelector = sel
386386
}
387387

pkg/client/options_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,17 @@ var _ = Describe("DeleteAllOfOptions", func() {
215215
Expect(newDeleteAllOfOpts).To(Equal(o))
216216
})
217217
})
218+
219+
var _ = Describe("MatchingLabels", func() {
220+
It("Should produce an invalid selector when given invalid input", func() {
221+
matchingLabels := client.MatchingLabels(map[string]string{"k": "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui"})
222+
listOpts := &client.ListOptions{}
223+
matchingLabels.ApplyToList(listOpts)
224+
225+
r, _ := listOpts.LabelSelector.Requirements()
226+
_, err := labels.NewRequirement(r[0].Key(), r[0].Operator(), r[0].Values().List())
227+
Expect(err).ToNot(BeNil())
228+
expectedErrMsg := `invalid label value: "axahm2EJ8Phiephe2eixohbee9eGeiyees1thuozi1xoh0GiuH3diewi8iem7Nui": at key: "k": must be no more than 63 characters`
229+
Expect(err.Error()).To(Equal(expectedErrMsg))
230+
})
231+
})

pkg/controller/controllerutil/controllerutil.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,10 @@ func AddFinalizerWithError(o runtime.Object, finalizer string) error {
262262
// RemoveFinalizer accepts a metav1 object and removes the provided finalizer if present.
263263
func RemoveFinalizer(o metav1.Object, finalizer string) {
264264
f := o.GetFinalizers()
265-
for i, e := range f {
266-
if e == finalizer {
265+
for i := 0; i < len(f); i++ {
266+
if f[i] == finalizer {
267267
f = append(f[:i], f[i+1:]...)
268+
i--
268269
}
269270
}
270271
o.SetFinalizers(f)
@@ -280,3 +281,10 @@ func RemoveFinalizerWithError(o runtime.Object, finalizer string) error {
280281
RemoveFinalizer(m, finalizer)
281282
return nil
282283
}
284+
285+
// Object allows functions to work indistinctly with any resource that
286+
// implements both Object interfaces.
287+
type Object interface {
288+
metav1.Object
289+
runtime.Object
290+
}

pkg/controller/controllerutil/controllerutil_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,12 @@ var _ = Describe("Controllerutil", func() {
445445
controllerutil.RemoveFinalizer(deploy, testFinalizer)
446446
Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{}))
447447
})
448+
449+
It("should remove all equal finalizers if present", func() {
450+
deploy.SetFinalizers(append(deploy.Finalizers, testFinalizer, testFinalizer))
451+
controllerutil.RemoveFinalizer(deploy, testFinalizer)
452+
Expect(deploy.ObjectMeta.GetFinalizers()).To(Equal([]string{}))
453+
})
448454
})
449455
})
450456
})

pkg/envtest/crd.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,10 +278,16 @@ func renderCRDs(options *CRDInstallOptions) ([]runtime.Object, error) {
278278
var (
279279
err error
280280
info os.FileInfo
281-
crds []*unstructured.Unstructured
282281
files []os.FileInfo
283282
)
284283

284+
type GVKN struct {
285+
GVK schema.GroupVersionKind
286+
Name string
287+
}
288+
289+
crds := map[GVKN]*unstructured.Unstructured{}
290+
285291
for _, path := range options.Paths {
286292
var filePath = path
287293

@@ -294,7 +300,7 @@ func renderCRDs(options *CRDInstallOptions) ([]runtime.Object, error) {
294300
}
295301

296302
if !info.IsDir() {
297-
filePath, files = filepath.Dir(path), append(files, info)
303+
filePath, files = filepath.Dir(path), []os.FileInfo{info}
298304
} else {
299305
if files, err = ioutil.ReadDir(path); err != nil {
300306
return nil, err
@@ -307,14 +313,23 @@ func renderCRDs(options *CRDInstallOptions) ([]runtime.Object, error) {
307313
return nil, err
308314
}
309315

310-
// If CRD already in the list, skip it.
311-
if existsUnstructured(crds, crdList) {
312-
continue
316+
for i, crd := range crdList {
317+
gvkn := GVKN{GVK: crd.GroupVersionKind(), Name: crd.GetName()}
318+
if _, found := crds[gvkn]; found {
319+
// Currently, we only print a log when there are duplicates. We may want to error out if that makes more sense.
320+
log.Info("there are more than one CRD definitions with the same <Group, Version, Kind, Name>", "GVKN", gvkn)
321+
}
322+
// We always use the CRD definition that we found last.
323+
crds[gvkn] = crdList[i]
313324
}
314-
crds = append(crds, crdList...)
315325
}
316326

317-
return unstructuredCRDListToRuntime(crds), nil
327+
// Converting map to a list to return
328+
var res []runtime.Object
329+
for _, obj := range crds {
330+
res = append(res, obj)
331+
}
332+
return res, nil
318333
}
319334

320335
// readCRDs reads the CRDs from files and Unmarshals them into structs

pkg/envtest/envtest_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,19 @@ var _ = Describe("Test", func() {
213213
close(done)
214214
}, 10)
215215

216+
It("should be able to install CRDs using multiple files", func(done Done) {
217+
crds, err = InstallCRDs(env.Config, CRDInstallOptions{
218+
Paths: []string{
219+
filepath.Join(".", "testdata", "examplecrd.yaml"),
220+
filepath.Join(".", "testdata", "examplecrd_v1.yaml"),
221+
},
222+
})
223+
Expect(err).NotTo(HaveOccurred())
224+
Expect(crds).To(HaveLen(2))
225+
226+
close(done)
227+
}, 10)
228+
216229
It("should filter out already existent CRD", func(done Done) {
217230
crds, err = InstallCRDs(env.Config, CRDInstallOptions{
218231
Paths: []string{

pkg/envtest/helper.go

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

33
import (
4-
"reflect"
5-
64
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
75
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
86
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -57,18 +55,6 @@ func mergeCRDs(s1, s2 []runtime.Object) []runtime.Object {
5755
return merged
5856
}
5957

60-
// existsUnstructured verify if a any item is common between two lists.
61-
func existsUnstructured(s1, s2 []*unstructured.Unstructured) bool {
62-
for _, s1obj := range s1 {
63-
for _, s2obj := range s2 {
64-
if reflect.DeepEqual(s1obj, s2obj) {
65-
return true
66-
}
67-
}
68-
}
69-
return false
70-
}
71-
7258
func runtimeCRDListToUnstructured(l []runtime.Object) []*unstructured.Unstructured {
7359
res := []*unstructured.Unstructured{}
7460
for _, obj := range l {
@@ -81,11 +67,3 @@ func runtimeCRDListToUnstructured(l []runtime.Object) []*unstructured.Unstructur
8167
}
8268
return res
8369
}
84-
85-
func unstructuredCRDListToRuntime(l []*unstructured.Unstructured) []runtime.Object {
86-
res := []runtime.Object{}
87-
for _, obj := range l {
88-
res = append(res, obj.DeepCopy())
89-
}
90-
return res
91-
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
apiVersion: admissionregistration.k8s.io/v1beta1
3+
kind: MutatingWebhookConfiguration
4+
metadata:
5+
creationTimestamp: null
6+
name: mutating-webhook-configuration
7+
webhooks:
8+
- clientConfig:
9+
caBundle: Cg==
10+
service:
11+
name: webhook-service
12+
namespace: system
13+
path: /mutate-v1beta1
14+
failurePolicy: Fail
15+
name: mpods.kb.io
16+
rules:
17+
- apiGroups:
18+
- ""
19+
apiVersions:
20+
- v1
21+
operations:
22+
- CREATE
23+
- UPDATE
24+
resources:
25+
- pods
26+
---
27+
apiVersion: admissionregistration.k8s.io/v1
28+
kind: MutatingWebhookConfiguration
29+
metadata:
30+
creationTimestamp: null
31+
name: mutating-webhook-configuration2
32+
webhooks:
33+
- clientConfig:
34+
caBundle: Cg==
35+
service:
36+
name: webhook-service
37+
namespace: system
38+
path: /mutate-v1
39+
failurePolicy: Fail
40+
name: mpods2.kb.io
41+
rules:
42+
- apiGroups:
43+
- ""
44+
apiVersions:
45+
- v1
46+
operations:
47+
- CREATE
48+
- UPDATE
49+
resources:
50+
- pods
51+
---
52+
apiVersion: admissionregistration.k8s.io/v1beta1
53+
kind: ValidatingWebhookConfiguration
54+
metadata:
55+
creationTimestamp: null
56+
name: validating-webhook-configuration
57+
webhooks:
58+
- clientConfig:
59+
caBundle: Cg==
60+
service:
61+
name: webhook-service
62+
namespace: system
63+
path: /validate-v1beta1
64+
failurePolicy: Fail
65+
name: vpods.kb.io
66+
rules:
67+
- apiGroups:
68+
- ""
69+
apiVersions:
70+
- v1
71+
operations:
72+
- CREATE
73+
- UPDATE
74+
resources:
75+
- pods
76+
---
77+
apiVersion: admissionregistration.k8s.io/v1
78+
kind: ValidatingWebhookConfiguration
79+
metadata:
80+
creationTimestamp: null
81+
name: validating-webhook-configuration2
82+
webhooks:
83+
- clientConfig:
84+
caBundle: Cg==
85+
service:
86+
name: webhook-service
87+
namespace: system
88+
path: /validate-v1
89+
failurePolicy: Fail
90+
name: vpods2.kb.io
91+
rules:
92+
- apiGroups:
93+
- ""
94+
apiVersions:
95+
- v1
96+
operations:
97+
- CREATE
98+
- UPDATE
99+
resources:
100+
- pods
101+

pkg/envtest/webhook.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,13 @@ func readWebhooks(path string) ([]runtime.Object, []runtime.Object, error) {
375375
return nil, nil, err
376376
}
377377

378+
const (
379+
admissionregv1 = "admissionregistration.k8s.io/v1"
380+
admissionregv1beta1 = "admissionregistration.k8s.io/v1beta1"
381+
)
378382
switch {
379383
case generic.Kind == "MutatingWebhookConfiguration":
380-
if generic.APIVersion != "v1beta1" && generic.APIVersion != "v1" {
384+
if generic.APIVersion != admissionregv1beta1 && generic.APIVersion != admissionregv1 {
381385
return nil, nil, fmt.Errorf("only v1beta1 and v1 are supported right now for MutatingWebhookConfiguration (name: %s)", generic.Name)
382386
}
383387
hook := &unstructured.Unstructured{}
@@ -386,7 +390,7 @@ func readWebhooks(path string) ([]runtime.Object, []runtime.Object, error) {
386390
}
387391
mutHooks = append(mutHooks, hook)
388392
case generic.Kind == "ValidatingWebhookConfiguration":
389-
if generic.APIVersion != "v1beta1" && generic.APIVersion != "v1" {
393+
if generic.APIVersion != admissionregv1beta1 && generic.APIVersion != admissionregv1 {
390394
return nil, nil, fmt.Errorf("only v1beta1 and v1 are supported right now for ValidatingWebhookConfiguration (name: %s)", generic.Name)
391395
}
392396
hook := &unstructured.Unstructured{}

pkg/envtest/webhook_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package envtest
33
import (
44
"context"
55
"fmt"
6+
"path/filepath"
67
"time"
78

89
. "github.com/onsi/ginkgo"
@@ -73,6 +74,16 @@ var _ = Describe("Test", func() {
7374
close(stopCh)
7475
close(done)
7576
})
77+
78+
It("should load webhooks from files", func() {
79+
installOptions := WebhookInstallOptions{
80+
DirectoryPaths: []string{filepath.Join("testdata", "webhooks")},
81+
}
82+
err := parseWebhookDirs(&installOptions)
83+
Expect(err).NotTo(HaveOccurred())
84+
Expect(len(installOptions.MutatingWebhooks)).To(Equal(2))
85+
Expect(len(installOptions.ValidatingWebhooks)).To(Equal(2))
86+
})
7687
})
7788
})
7889

pkg/log/zap/kube_helpers.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@ func (k *KubeAwareEncoder) EncodeEntry(entry zapcore.Entry, fields []zapcore.Fie
105105
// intercept stringer fields that happen to be Kubernetes runtime.Object or
106106
// types.NamespacedName values (Kubernetes runtime.Objects commonly
107107
// implement String, apparently).
108-
if field.Type == zapcore.StringerType {
108+
// *unstructured.Unstructured does NOT implement fmt.Striger interface.
109+
// We have handle it specially.
110+
if field.Type == zapcore.StringerType || field.Type == zapcore.ReflectType {
109111
switch val := field.Interface.(type) {
110112
case runtime.Object:
111113
fields[i] = zapcore.Field{

pkg/log/zap/zap_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
. "github.com/onsi/ginkgo"
2626
. "github.com/onsi/gomega"
2727
kapi "k8s.io/api/core/v1"
28+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2829
"k8s.io/apimachinery/pkg/types"
2930
)
3031

@@ -238,6 +239,27 @@ var _ = Describe("Zap logger setup", func() {
238239
}))
239240
})
240241

242+
It("should log an unstructured Kubernetes object", func() {
243+
pod := &unstructured.Unstructured{
244+
Object: map[string]interface{}{
245+
"metadata": map[string]interface{}{
246+
"name": "some-pod",
247+
"namespace": "some-ns",
248+
},
249+
},
250+
}
251+
logger.Info("here's a kubernetes object", "thing", pod)
252+
253+
outRaw := logOut.Bytes()
254+
res := map[string]interface{}{}
255+
Expect(json.Unmarshal(outRaw, &res)).To(Succeed())
256+
257+
Expect(res).To(HaveKeyWithValue("thing", map[string]interface{}{
258+
"name": "some-pod",
259+
"namespace": "some-ns",
260+
}))
261+
})
262+
241263
It("should log a standard namespaced NamespacedName name and namespace", func() {
242264
name := types.NamespacedName{Name: "some-pod", Namespace: "some-ns"}
243265
logger.Info("here's a kubernetes object", "thing", name)

0 commit comments

Comments
 (0)