kusttarget.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*
  2. Copyright 2018 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 target implements state for the set of all resources to customize.
  14. package target
  15. import (
  16. "bytes"
  17. "encoding/json"
  18. "fmt"
  19. "strings"
  20. "github.com/ghodss/yaml"
  21. "github.com/pkg/errors"
  22. "sigs.k8s.io/kustomize/pkg/constants"
  23. "sigs.k8s.io/kustomize/pkg/ifc"
  24. "sigs.k8s.io/kustomize/pkg/ifc/transformer"
  25. interror "sigs.k8s.io/kustomize/pkg/internal/error"
  26. patchtransformer "sigs.k8s.io/kustomize/pkg/patch/transformer"
  27. "sigs.k8s.io/kustomize/pkg/resmap"
  28. "sigs.k8s.io/kustomize/pkg/resource"
  29. "sigs.k8s.io/kustomize/pkg/transformers"
  30. "sigs.k8s.io/kustomize/pkg/transformers/config"
  31. "sigs.k8s.io/kustomize/pkg/types"
  32. )
  33. // KustTarget encapsulates the entirety of a kustomization build.
  34. type KustTarget struct {
  35. kustomization *types.Kustomization
  36. ldr ifc.Loader
  37. rFactory *resmap.Factory
  38. tFactory transformer.Factory
  39. }
  40. // NewKustTarget returns a new instance of KustTarget primed with a Loader.
  41. func NewKustTarget(
  42. ldr ifc.Loader,
  43. rFactory *resmap.Factory,
  44. tFactory transformer.Factory) (*KustTarget, error) {
  45. content, err := loadKustFile(ldr)
  46. if err != nil {
  47. return nil, err
  48. }
  49. content = types.DealWithDeprecatedFields(content)
  50. var k types.Kustomization
  51. err = unmarshal(content, &k)
  52. if err != nil {
  53. return nil, err
  54. }
  55. errs := k.EnforceFields()
  56. if len(errs) > 0 {
  57. return nil, fmt.Errorf("Failed to read kustomization file under %s:\n"+strings.Join(errs, "\n"), ldr.Root())
  58. }
  59. return &KustTarget{
  60. kustomization: &k,
  61. ldr: ldr,
  62. rFactory: rFactory,
  63. tFactory: tFactory,
  64. }, nil
  65. }
  66. func quoted(l []string) []string {
  67. r := make([]string, len(l))
  68. for i, v := range l {
  69. r[i] = "'" + v + "'"
  70. }
  71. return r
  72. }
  73. func commaOr(q []string) string {
  74. return strings.Join(q[:len(q)-1], ", ") + " or " + q[len(q)-1]
  75. }
  76. func loadKustFile(ldr ifc.Loader) ([]byte, error) {
  77. var content []byte
  78. match := 0
  79. for _, kf := range constants.KustomizationFileNames {
  80. c, err := ldr.Load(kf)
  81. if err == nil {
  82. match += 1
  83. content = c
  84. }
  85. }
  86. switch match {
  87. case 0:
  88. return nil, fmt.Errorf(
  89. "unable to find one of %v in directory '%s'",
  90. commaOr(quoted(constants.KustomizationFileNames)), ldr.Root())
  91. case 1:
  92. return content, nil
  93. default:
  94. return nil, fmt.Errorf("Found multiple kustomization files under: %s\n", ldr.Root())
  95. }
  96. }
  97. func unmarshal(y []byte, o interface{}) error {
  98. j, err := yaml.YAMLToJSON(y)
  99. if err != nil {
  100. return err
  101. }
  102. dec := json.NewDecoder(bytes.NewReader(j))
  103. dec.DisallowUnknownFields()
  104. return dec.Decode(o)
  105. }
  106. // MakeCustomizedResMap creates a ResMap per kustomization instructions.
  107. // The Resources in the returned ResMap are fully customized.
  108. func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
  109. ra, err := kt.AccumulateTarget()
  110. if err != nil {
  111. return nil, err
  112. }
  113. err = ra.Transform(kt.tFactory.MakeHashTransformer())
  114. if err != nil {
  115. return nil, err
  116. }
  117. // Given that names have changed (prefixs/suffixes added),
  118. // fix all the back references to those names.
  119. err = ra.FixBackReferences()
  120. if err != nil {
  121. return nil, err
  122. }
  123. // With all the back references fixed, it's OK to resolve Vars.
  124. err = ra.ResolveVars()
  125. return ra.ResMap(), err
  126. }
  127. func (kt *KustTarget) shouldAddHashSuffixesToGeneratedResources() bool {
  128. return kt.kustomization.GeneratorOptions == nil ||
  129. !kt.kustomization.GeneratorOptions.DisableNameSuffixHash
  130. }
  131. // AccumulateTarget returns a new ResAccumulator,
  132. // holding customized resources and the data/rules used
  133. // to do so. The name back references and vars are
  134. // not yet fixed.
  135. func (kt *KustTarget) AccumulateTarget() (
  136. ra *ResAccumulator, err error) {
  137. // TODO(monopole): Get rid of the KustomizationErrors accumulator.
  138. // It's not consistently used, and complicates tests.
  139. errs := &interror.KustomizationErrors{}
  140. ra, errs = kt.accumulateBases()
  141. resources, err := kt.rFactory.FromFiles(
  142. kt.ldr, kt.kustomization.Resources)
  143. if err != nil {
  144. errs.Append(errors.Wrap(err, "rawResources failed to read Resources"))
  145. }
  146. if len(errs.Get()) > 0 {
  147. return ra, errs
  148. }
  149. err = ra.MergeResourcesWithErrorOnIdCollision(resources)
  150. if err != nil {
  151. errs.Append(errors.Wrap(err, "MergeResourcesWithErrorOnIdCollision"))
  152. }
  153. tConfig, err := config.MakeTransformerConfig(
  154. kt.ldr, kt.kustomization.Configurations)
  155. if err != nil {
  156. return nil, err
  157. }
  158. err = ra.MergeConfig(tConfig)
  159. if err != nil {
  160. errs.Append(errors.Wrap(err, "MergeConfig"))
  161. }
  162. err = ra.MergeVars(kt.kustomization.Vars)
  163. if err != nil {
  164. errs.Append(errors.Wrap(err, "MergeVars"))
  165. }
  166. crdTc, err := config.LoadConfigFromCRDs(kt.ldr, kt.kustomization.Crds)
  167. if err != nil {
  168. errs.Append(errors.Wrap(err, "LoadCRDs"))
  169. }
  170. err = ra.MergeConfig(crdTc)
  171. if err != nil {
  172. errs.Append(errors.Wrap(err, "merge CRDs"))
  173. }
  174. resMap, err := kt.generateConfigMapsAndSecrets(errs)
  175. if err != nil {
  176. errs.Append(errors.Wrap(err, "generateConfigMapsAndSecrets"))
  177. }
  178. err = ra.MergeResourcesWithOverride(resMap)
  179. if err != nil {
  180. return nil, err
  181. }
  182. patches, err := kt.rFactory.RF().SliceFromPatches(
  183. kt.ldr, kt.kustomization.PatchesStrategicMerge)
  184. if err != nil {
  185. errs.Append(errors.Wrap(err, "SliceFromPatches"))
  186. }
  187. if len(errs.Get()) > 0 {
  188. return nil, errs
  189. }
  190. t, err := kt.newTransformer(patches, ra.tConfig)
  191. if err != nil {
  192. return nil, err
  193. }
  194. err = ra.Transform(t)
  195. if err != nil {
  196. return nil, err
  197. }
  198. return ra, nil
  199. }
  200. func (kt *KustTarget) generateConfigMapsAndSecrets(
  201. errs *interror.KustomizationErrors) (resmap.ResMap, error) {
  202. kt.rFactory.Set(kt.ldr)
  203. cms, err := kt.rFactory.NewResMapFromConfigMapArgs(
  204. kt.kustomization.ConfigMapGenerator, kt.kustomization.GeneratorOptions)
  205. if err != nil {
  206. errs.Append(errors.Wrap(err, "NewResMapFromConfigMapArgs"))
  207. }
  208. secrets, err := kt.rFactory.NewResMapFromSecretArgs(
  209. kt.kustomization.SecretGenerator, kt.kustomization.GeneratorOptions)
  210. if err != nil {
  211. errs.Append(errors.Wrap(err, "NewResMapFromSecretArgs"))
  212. }
  213. return resmap.MergeWithErrorOnIdCollision(cms, secrets)
  214. }
  215. // accumulateBases returns a new ResAccumulator
  216. // holding customized resources and the data/rules
  217. // used to customized them from only the _bases_
  218. // of this KustTarget.
  219. func (kt *KustTarget) accumulateBases() (
  220. ra *ResAccumulator, errs *interror.KustomizationErrors) {
  221. errs = &interror.KustomizationErrors{}
  222. ra = MakeEmptyAccumulator()
  223. for _, path := range kt.kustomization.Bases {
  224. ldr, err := kt.ldr.New(path)
  225. if err != nil {
  226. errs.Append(errors.Wrap(err, "couldn't make loader for "+path))
  227. continue
  228. }
  229. subKt, err := NewKustTarget(
  230. ldr, kt.rFactory, kt.tFactory)
  231. if err != nil {
  232. errs.Append(errors.Wrap(err, "couldn't make target for "+path))
  233. ldr.Cleanup()
  234. continue
  235. }
  236. subRa, err := subKt.AccumulateTarget()
  237. if err != nil {
  238. errs.Append(errors.Wrap(err, "AccumulateTarget"))
  239. ldr.Cleanup()
  240. continue
  241. }
  242. err = ra.MergeAccumulator(subRa)
  243. if err != nil {
  244. errs.Append(errors.Wrap(err, path))
  245. }
  246. ldr.Cleanup()
  247. }
  248. return ra, errs
  249. }
  250. // newTransformer makes a Transformer that does a collection
  251. // of object transformations.
  252. func (kt *KustTarget) newTransformer(
  253. patches []*resource.Resource, tConfig *config.TransformerConfig) (
  254. transformers.Transformer, error) {
  255. var r []transformers.Transformer
  256. t, err := kt.tFactory.MakePatchTransformer(patches, kt.rFactory.RF())
  257. if err != nil {
  258. return nil, err
  259. }
  260. r = append(r, t)
  261. r = append(r, transformers.NewNamespaceTransformer(
  262. string(kt.kustomization.Namespace), tConfig.NameSpace))
  263. t, err = transformers.NewNamePrefixSuffixTransformer(
  264. string(kt.kustomization.NamePrefix),
  265. string(kt.kustomization.NameSuffix),
  266. tConfig.NamePrefix,
  267. )
  268. if err != nil {
  269. return nil, err
  270. }
  271. r = append(r, t)
  272. t, err = transformers.NewLabelsMapTransformer(
  273. kt.kustomization.CommonLabels, tConfig.CommonLabels)
  274. if err != nil {
  275. return nil, err
  276. }
  277. r = append(r, t)
  278. t, err = transformers.NewAnnotationsMapTransformer(
  279. kt.kustomization.CommonAnnotations, tConfig.CommonAnnotations)
  280. if err != nil {
  281. return nil, err
  282. }
  283. r = append(r, t)
  284. t, err = patchtransformer.NewPatchJson6902Factory(kt.ldr).
  285. MakePatchJson6902Transformer(kt.kustomization.PatchesJson6902)
  286. if err != nil {
  287. return nil, err
  288. }
  289. r = append(r, t)
  290. t, err = transformers.NewImageTransformer(kt.kustomization.Images)
  291. if err != nil {
  292. return nil, err
  293. }
  294. r = append(r, t)
  295. return transformers.NewMultiTransformer(r), nil
  296. }