-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
factory.go
154 lines (137 loc) · 4.29 KB
/
factory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package kunstruct
import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/yaml"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/internal/k8sdeps/configmapandsecret"
"sigs.k8s.io/kustomize/api/types"
)
// KunstructuredFactoryImpl makes instances of UnstructAdapter.
// These instances in turn adapt structs in
// k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
// to implement ifc.Kunstructured.
// This factory is meant to implement ifc.KunstructuredFactory.
type KunstructuredFactoryImpl struct {
hasher *kustHash
}
var _ ifc.KunstructuredFactory = &KunstructuredFactoryImpl{}
// NewKunstructuredFactoryImpl returns a factory.
func NewKunstructuredFactoryImpl() ifc.KunstructuredFactory {
return &KunstructuredFactoryImpl{hasher: NewKustHash()}
}
// Hasher returns a kunstructured hasher
// input: kunstructured; output: string hash.
func (kf *KunstructuredFactoryImpl) Hasher() ifc.KunstructuredHasher {
return kf.hasher
}
// SliceFromBytes returns a slice of Kunstructured.
func (kf *KunstructuredFactoryImpl) SliceFromBytes(
in []byte) ([]ifc.Kunstructured, error) {
decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewReader(in), 1024)
var result []ifc.Kunstructured
var err error
for err == nil || isEmptyYamlError(err) {
var out unstructured.Unstructured
err = decoder.Decode(&out)
if err == nil {
if len(out.Object) == 0 {
continue
}
err = kf.validate(out)
if err != nil {
return nil, err
}
if !kf.skipResource(out) {
result = append(result, &UnstructAdapter{Unstructured: out})
}
}
}
if err != io.EOF {
return nil, err
}
return result, nil
}
func isEmptyYamlError(err error) bool {
return strings.Contains(err.Error(), "is missing in 'null'")
}
// FromMap returns an instance of Kunstructured.
func (kf *KunstructuredFactoryImpl) FromMap(
m map[string]interface{}) ifc.Kunstructured {
return &UnstructAdapter{Unstructured: unstructured.Unstructured{Object: m}}
}
// MakeConfigMap returns an instance of Kunstructured for ConfigMap
func (kf *KunstructuredFactoryImpl) MakeConfigMap(
kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(kvLdr).MakeConfigMap(args)
if err != nil {
return nil, err
}
return NewKunstructuredFromObject(o)
}
// MakeSecret returns an instance of Kunstructured for Secret
func (kf *KunstructuredFactoryImpl) MakeSecret(
kvLdr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) {
o, err := configmapandsecret.NewFactory(kvLdr).MakeSecret(args)
if err != nil {
return nil, err
}
return NewKunstructuredFromObject(o)
}
// validate validates that u has kind and name
// except for kind `List`, which doesn't require a name
func (kf *KunstructuredFactoryImpl) validate(u unstructured.Unstructured) error {
kind := u.GetKind()
if kind == "" {
return fmt.Errorf("missing kind in object %v", u)
} else if strings.HasSuffix(kind, "List") {
return nil
}
if u.GetName() == "" {
return fmt.Errorf("missing metadata.name in object %v", u)
}
if result, path := checkListItemNil(u.Object); result {
return fmt.Errorf("empty item at %v in object %v", path, u)
}
return nil
}
// nonKustomizableResourceAnnotation if set on a Resource will cause Kustomize to
// ignore the Resource rather than Kustomize it.
const ignoredByKustomizeResourceAnnotation = "config.kubernetes.io/local-config"
// skipResource returns true if the Resource should not be accumulated
func (kf *KunstructuredFactoryImpl) skipResource(u unstructured.Unstructured) bool {
an := u.GetAnnotations()
if an == nil {
// annotation unset
return false
}
// check if the Resource has opt-ed out of kustomize
_, found := an[ignoredByKustomizeResourceAnnotation]
return found
}
func checkListItemNil(in interface{}) (bool, string) {
switch v := in.(type) {
case map[string]interface{}:
for key, s := range v {
if result, path := checkListItemNil(s); result {
return result, key + "/" + path
}
}
case []interface{}:
for index, s := range v {
if s == nil {
return true, ""
}
if result, path := checkListItemNil(s); result {
return result, "[" + strconv.Itoa(index) + "]/" + path
}
}
}
return false, ""
}