configfiles_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package configfiles
  14. import (
  15. "fmt"
  16. "path/filepath"
  17. "testing"
  18. "github.com/pkg/errors"
  19. apiequality "k8s.io/apimachinery/pkg/api/equality"
  20. "k8s.io/apimachinery/pkg/runtime"
  21. kubeletconfigv1beta1 "k8s.io/kubelet/config/v1beta1"
  22. kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
  23. kubeletscheme "k8s.io/kubernetes/pkg/kubelet/apis/config/scheme"
  24. utilfiles "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/files"
  25. utiltest "k8s.io/kubernetes/pkg/kubelet/kubeletconfig/util/test"
  26. utilfs "k8s.io/kubernetes/pkg/util/filesystem"
  27. )
  28. const configDir = "/test-config-dir"
  29. const relativePath = "relative/path/test"
  30. const kubeletFile = "kubelet"
  31. func TestLoad(t *testing.T) {
  32. cases := []struct {
  33. desc string
  34. file *string
  35. expect *kubeletconfig.KubeletConfiguration
  36. err string
  37. strictErr bool
  38. }{
  39. // missing file
  40. {
  41. desc: "missing file",
  42. err: "failed to read",
  43. },
  44. // empty file
  45. {
  46. desc: "empty file",
  47. file: newString(``),
  48. err: "was empty",
  49. },
  50. // invalid format
  51. {
  52. desc: "invalid yaml",
  53. file: newString(`*`),
  54. err: "failed to decode",
  55. },
  56. {
  57. desc: "invalid json",
  58. file: newString(`{*`),
  59. err: "failed to decode",
  60. },
  61. // invalid object
  62. {
  63. desc: "missing kind",
  64. file: newString(`{"apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
  65. err: "failed to decode",
  66. },
  67. {
  68. desc: "missing version",
  69. file: newString(`{"kind":"KubeletConfiguration"}`),
  70. err: "failed to decode",
  71. },
  72. {
  73. desc: "unregistered kind",
  74. file: newString(`{"kind":"BogusKind","apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
  75. err: "failed to decode",
  76. },
  77. {
  78. desc: "unregistered version",
  79. file: newString(`{"kind":"KubeletConfiguration","apiVersion":"bogusversion"}`),
  80. err: "failed to decode",
  81. },
  82. // empty object with correct kind and version should result in the defaults for that kind and version
  83. {
  84. desc: "default from yaml",
  85. file: newString(`kind: KubeletConfiguration
  86. apiVersion: kubelet.config.k8s.io/v1beta1`),
  87. expect: newConfig(t),
  88. },
  89. {
  90. desc: "default from json",
  91. file: newString(`{"kind":"KubeletConfiguration","apiVersion":"kubelet.config.k8s.io/v1beta1"}`),
  92. expect: newConfig(t),
  93. },
  94. // relative path
  95. {
  96. desc: "yaml, relative path is resolved",
  97. file: newString(fmt.Sprintf(`kind: KubeletConfiguration
  98. apiVersion: kubelet.config.k8s.io/v1beta1
  99. staticPodPath: %s`, relativePath)),
  100. expect: func() *kubeletconfig.KubeletConfiguration {
  101. kc := newConfig(t)
  102. kc.StaticPodPath = filepath.Join(configDir, relativePath)
  103. return kc
  104. }(),
  105. },
  106. {
  107. desc: "json, relative path is resolved",
  108. file: newString(fmt.Sprintf(`{"kind":"KubeletConfiguration","apiVersion":"kubelet.config.k8s.io/v1beta1","staticPodPath":"%s"}`, relativePath)),
  109. expect: func() *kubeletconfig.KubeletConfiguration {
  110. kc := newConfig(t)
  111. kc.StaticPodPath = filepath.Join(configDir, relativePath)
  112. return kc
  113. }(),
  114. },
  115. {
  116. // This should fail from v1beta2+
  117. desc: "duplicate field",
  118. file: newString(fmt.Sprintf(`kind: KubeletConfiguration
  119. apiVersion: kubelet.config.k8s.io/v1beta1
  120. staticPodPath: %s
  121. staticPodPath: %s/foo`, relativePath, relativePath)),
  122. // err: `key "staticPodPath" already set`,
  123. // strictErr: true,
  124. expect: func() *kubeletconfig.KubeletConfiguration {
  125. kc := newConfig(t)
  126. kc.StaticPodPath = filepath.Join(configDir, relativePath, "foo")
  127. return kc
  128. }(),
  129. },
  130. {
  131. // This should fail from v1beta2+
  132. desc: "unknown field",
  133. file: newString(`kind: KubeletConfiguration
  134. apiVersion: kubelet.config.k8s.io/v1beta1
  135. foo: bar`),
  136. // err: "found unknown field: foo",
  137. // strictErr: true,
  138. expect: newConfig(t),
  139. },
  140. }
  141. for _, c := range cases {
  142. t.Run(c.desc, func(t *testing.T) {
  143. fs := utilfs.NewFakeFs()
  144. path := filepath.Join(configDir, kubeletFile)
  145. if c.file != nil {
  146. if err := addFile(fs, path, *c.file); err != nil {
  147. t.Fatalf("unexpected error: %v", err)
  148. }
  149. }
  150. loader, err := NewFsLoader(fs, path)
  151. if err != nil {
  152. t.Fatalf("unexpected error: %v", err)
  153. }
  154. kc, err := loader.Load()
  155. if c.strictErr && !runtime.IsStrictDecodingError(errors.Cause(err)) {
  156. t.Fatalf("got error: %v, want strict decoding error", err)
  157. }
  158. if utiltest.SkipRest(t, c.desc, err, c.err) {
  159. return
  160. }
  161. if !apiequality.Semantic.DeepEqual(c.expect, kc) {
  162. t.Fatalf("expect %#v but got %#v", *c.expect, *kc)
  163. }
  164. })
  165. }
  166. }
  167. func TestResolveRelativePaths(t *testing.T) {
  168. absolutePath := filepath.Join(configDir, "absolute")
  169. cases := []struct {
  170. desc string
  171. path string
  172. expect string
  173. }{
  174. {"empty path", "", ""},
  175. {"absolute path", absolutePath, absolutePath},
  176. {"relative path", relativePath, filepath.Join(configDir, relativePath)},
  177. }
  178. paths := kubeletconfig.KubeletConfigurationPathRefs(newConfig(t))
  179. if len(paths) == 0 {
  180. t.Fatalf("requires at least one path field to exist in the KubeletConfiguration type")
  181. }
  182. for _, c := range cases {
  183. t.Run(c.desc, func(t *testing.T) {
  184. // set the path, resolve it, and check if it resolved as we would expect
  185. *(paths[0]) = c.path
  186. resolveRelativePaths(paths, configDir)
  187. if *(paths[0]) != c.expect {
  188. t.Fatalf("expect %s but got %s", c.expect, *(paths[0]))
  189. }
  190. })
  191. }
  192. }
  193. func newString(s string) *string {
  194. return &s
  195. }
  196. func addFile(fs utilfs.Filesystem, path string, file string) error {
  197. if err := utilfiles.EnsureDir(fs, filepath.Dir(path)); err != nil {
  198. return err
  199. }
  200. return utilfiles.ReplaceFile(fs, path, []byte(file))
  201. }
  202. func newConfig(t *testing.T) *kubeletconfig.KubeletConfiguration {
  203. kubeletScheme, _, err := kubeletscheme.NewSchemeAndCodecs()
  204. if err != nil {
  205. t.Fatalf("unexpected error: %v", err)
  206. }
  207. // get the built-in default configuration
  208. external := &kubeletconfigv1beta1.KubeletConfiguration{}
  209. kubeletScheme.Default(external)
  210. kc := &kubeletconfig.KubeletConfiguration{}
  211. err = kubeletScheme.Convert(external, kc, nil)
  212. if err != nil {
  213. t.Fatalf("unexpected error: %v", err)
  214. }
  215. return kc
  216. }