1
16
17 package configfiles
18
19 import (
20 "errors"
21 "fmt"
22 "path/filepath"
23 goruntime "runtime"
24 "testing"
25
26 apiequality "k8s.io/apimachinery/pkg/api/equality"
27 "k8s.io/apimachinery/pkg/runtime"
28 kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
29 kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
30 kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/config/scheme"
31 utilfiles "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/files"
32 utiltest "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/test"
33 utilfs "k8s.io/kubernetes/pkg/util/filesystem"
34 )
35
36 const configDir = "/test-config-dir"
37 const relativePath = "relative/path/test"
38 const kubeletFile = "kubelet"
39
40 func TestLoad(t *testing.T) {
41 cases := []struct {
42 desc string
43 file *string
44 expect *kubeletconfig.KubeletConfiguration
45 err string
46 strictErr bool
47 skipOnWindows bool
48 }{
49
50 {
51 desc: "missing file",
52 err: "failed to read",
53 },
54
55 {
56 desc: "empty file",
57 file: newString(``),
58 err: "was empty",
59 },
60
61 {
62 desc: "invalid yaml",
63 file: newString(`*`),
64 err: "failed to decode",
65 },
66 {
67 desc: "invalid json",
68 file: newString(`{*`),
69 err: "failed to decode",
70 },
71
72 {
73 desc: "missing kind",
74 file: newString(`{"apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
75 err: "failed to decode",
76 },
77 {
78 desc: "missing version",
79 file: newString(`{"kind":"KubeletConfiguration"}`),
80 err: "failed to decode",
81 },
82 {
83 desc: "unregistered kind",
84 file: newString(`{"kind":"BogusKind","apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
85 err: "failed to decode",
86 },
87 {
88 desc: "unregistered version",
89 file: newString(`{"kind":"KubeletConfiguration","apiVersion":"bogusversion"}`),
90 err: "failed to decode",
91 },
92
93
94 {
95 desc: "default from yaml",
96 file: newString(`kind: KubeletConfiguration
97 apiVersion: kubelet.config.k8s.io/v1beta1`),
98 expect: newConfig(t),
99 skipOnWindows: true,
100 },
101 {
102 desc: "default from json",
103 file: newString(`{"kind":"KubeletConfiguration","apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
104 expect: newConfig(t),
105 skipOnWindows: true,
106 },
107
108
109 {
110 desc: "yaml, relative path is resolved",
111 file: newString(fmt.Sprintf(`kind: KubeletConfiguration
112 apiVersion: kubelet.config.k8s.io/v1beta1
113 staticPodPath: %s`, relativePath)),
114 expect: func() *kubeletconfig.KubeletConfiguration {
115 kc := newConfig(t)
116 kc.StaticPodPath = filepath.Join(configDir, relativePath)
117 return kc
118 }(),
119 skipOnWindows: true,
120 },
121 {
122 desc: "json, relative path is resolved",
123 file: newString(fmt.Sprintf(`{"kind":"KubeletConfiguration","apiVersion":"kubelet.config.k8s.io/v1beta1","staticPodPath":"%s"}`, relativePath)),
124 expect: func() *kubeletconfig.KubeletConfiguration {
125 kc := newConfig(t)
126 kc.StaticPodPath = filepath.Join(configDir, relativePath)
127 return kc
128 }(),
129 skipOnWindows: true,
130 },
131 {
132
133 desc: "duplicate field",
134 file: newString(fmt.Sprintf(`kind: KubeletConfiguration
135 apiVersion: kubelet.config.k8s.io/v1beta1
136 staticPodPath: %s
137 staticPodPath: %s/foo`, relativePath, relativePath)),
138
139
140 expect: func() *kubeletconfig.KubeletConfiguration {
141 kc := newConfig(t)
142 kc.StaticPodPath = filepath.Join(configDir, relativePath, "foo")
143 return kc
144 }(),
145 skipOnWindows: true,
146 },
147 {
148
149 desc: "unknown field",
150 file: newString(`kind: KubeletConfiguration
151 apiVersion: kubelet.config.k8s.io/v1beta1
152 foo: bar`),
153
154
155 expect: newConfig(t),
156 skipOnWindows: true,
157 },
158 }
159
160 for _, c := range cases {
161 t.Run(c.desc, func(t *testing.T) {
162
163 if c.skipOnWindows && goruntime.GOOS == "windows" {
164 t.Skip("Skipping test that fails on Windows")
165 }
166
167 fs := utilfs.NewTempFs()
168 fs.MkdirAll(configDir, 0777)
169 path := filepath.Join(configDir, kubeletFile)
170 if c.file != nil {
171 if err := addFile(fs, path, *c.file); err != nil {
172 t.Fatalf("unexpected error: %v", err)
173 }
174 }
175 loader, err := NewFsLoader(fs, path)
176 if err != nil {
177 t.Fatalf("unexpected error: %v", err)
178 }
179 kc, err := loader.Load()
180
181 if c.strictErr && !runtime.IsStrictDecodingError(errors.Unwrap(err)) {
182 t.Fatalf("got error: %v, want strict decoding error", err)
183 }
184 if utiltest.SkipRest(t, c.desc, err, c.err) {
185 return
186 }
187 if !apiequality.Semantic.DeepEqual(c.expect, kc) {
188 t.Fatalf("expect %#v but got %#v", *c.expect, *kc)
189 }
190 })
191 }
192 }
193
194 func TestResolveRelativePaths(t *testing.T) {
195 absolutePath := filepath.Join(configDir, "absolute")
196 cases := []struct {
197 desc string
198 path string
199 expect string
200 skipOnWindows bool
201 }{
202 {"empty path", "", "", false},
203 {"absolute path", absolutePath, absolutePath, true},
204 {"relative path", relativePath, filepath.Join(configDir, relativePath), false},
205 }
206
207 paths := kubeletconfig.KubeletConfigurationPathRefs(newConfig(t))
208 if len(paths) == 0 {
209 t.Fatalf("requires at least one path field to exist in the KubeletConfiguration type")
210 }
211 for _, c := range cases {
212 t.Run(c.desc, func(t *testing.T) {
213
214 if c.skipOnWindows && goruntime.GOOS == "windows" {
215 t.Skip("Skipping test that fails on Windows")
216 }
217
218
219 *(paths[0]) = c.path
220 resolveRelativePaths(paths, configDir)
221 if *(paths[0]) != c.expect {
222 t.Fatalf("expect %s but got %s", c.expect, *(paths[0]))
223 }
224 })
225 }
226 }
227
228 func newString(s string) *string {
229 return &s
230 }
231
232 func addFile(fs utilfs.Filesystem, path string, file string) error {
233 if err := utilfiles.EnsureDir(fs, filepath.Dir(path)); err != nil {
234 return err
235 }
236 return utilfiles.ReplaceFile(fs, path, []byte(file))
237 }
238
239 func newConfig(t *testing.T) *kubeletconfig.KubeletConfiguration {
240 kubeletScheme, _, err := kubeletscheme.NewSchemeAndCodecs()
241 if err != nil {
242 t.Fatalf("unexpected error: %v", err)
243 }
244
245 external := &kubeletconfigv1beta1.KubeletConfiguration{}
246 kubeletScheme.Default(external)
247 kc := &kubeletconfig.KubeletConfiguration{}
248 err = kubeletScheme.Convert(external, kc, nil)
249 if err != nil {
250 t.Fatalf("unexpected error: %v", err)
251 }
252 return kc
253 }
254
View as plain text