apply.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. Copyright 2014 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 kubectl
  14. import (
  15. "k8s.io/api/core/v1"
  16. "k8s.io/apimachinery/pkg/api/meta"
  17. "k8s.io/apimachinery/pkg/runtime"
  18. )
  19. var metadataAccessor = meta.NewAccessor()
  20. // GetOriginalConfiguration retrieves the original configuration of the object
  21. // from the annotation, or nil if no annotation was found.
  22. func GetOriginalConfiguration(obj runtime.Object) ([]byte, error) {
  23. annots, err := metadataAccessor.Annotations(obj)
  24. if err != nil {
  25. return nil, err
  26. }
  27. if annots == nil {
  28. return nil, nil
  29. }
  30. original, ok := annots[v1.LastAppliedConfigAnnotation]
  31. if !ok {
  32. return nil, nil
  33. }
  34. return []byte(original), nil
  35. }
  36. // SetOriginalConfiguration sets the original configuration of the object
  37. // as the annotation on the object for later use in computing a three way patch.
  38. func setOriginalConfiguration(obj runtime.Object, original []byte) error {
  39. if len(original) < 1 {
  40. return nil
  41. }
  42. annots, err := metadataAccessor.Annotations(obj)
  43. if err != nil {
  44. return err
  45. }
  46. if annots == nil {
  47. annots = map[string]string{}
  48. }
  49. annots[v1.LastAppliedConfigAnnotation] = string(original)
  50. return metadataAccessor.SetAnnotations(obj, annots)
  51. }
  52. // GetModifiedConfiguration retrieves the modified configuration of the object.
  53. // If annotate is true, it embeds the result as an annotation in the modified
  54. // configuration. If an object was read from the command input, it will use that
  55. // version of the object. Otherwise, it will use the version from the server.
  56. func GetModifiedConfiguration(obj runtime.Object, annotate bool, codec runtime.Encoder) ([]byte, error) {
  57. // First serialize the object without the annotation to prevent recursion,
  58. // then add that serialization to it as the annotation and serialize it again.
  59. var modified []byte
  60. // Otherwise, use the server side version of the object.
  61. // Get the current annotations from the object.
  62. annots, err := metadataAccessor.Annotations(obj)
  63. if err != nil {
  64. return nil, err
  65. }
  66. if annots == nil {
  67. annots = map[string]string{}
  68. }
  69. original := annots[v1.LastAppliedConfigAnnotation]
  70. delete(annots, v1.LastAppliedConfigAnnotation)
  71. if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
  72. return nil, err
  73. }
  74. modified, err = runtime.Encode(codec, obj)
  75. if err != nil {
  76. return nil, err
  77. }
  78. if annotate {
  79. annots[v1.LastAppliedConfigAnnotation] = string(modified)
  80. if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
  81. return nil, err
  82. }
  83. modified, err = runtime.Encode(codec, obj)
  84. if err != nil {
  85. return nil, err
  86. }
  87. }
  88. // Restore the object to its original condition.
  89. annots[v1.LastAppliedConfigAnnotation] = original
  90. if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
  91. return nil, err
  92. }
  93. return modified, nil
  94. }
  95. // UpdateApplyAnnotation calls CreateApplyAnnotation if the last applied
  96. // configuration annotation is already present. Otherwise, it does nothing.
  97. func UpdateApplyAnnotation(obj runtime.Object, codec runtime.Encoder) error {
  98. if original, err := GetOriginalConfiguration(obj); err != nil || len(original) <= 0 {
  99. return err
  100. }
  101. return CreateApplyAnnotation(obj, codec)
  102. }
  103. // CreateApplyAnnotation gets the modified configuration of the object,
  104. // without embedding it again, and then sets it on the object as the annotation.
  105. func CreateApplyAnnotation(obj runtime.Object, codec runtime.Encoder) error {
  106. modified, err := GetModifiedConfiguration(obj, false, codec)
  107. if err != nil {
  108. return err
  109. }
  110. return setOriginalConfiguration(obj, modified)
  111. }
  112. // CreateOrUpdateAnnotation creates the annotation used by
  113. // kubectl apply only when createAnnotation is true
  114. // Otherwise, only update the annotation when it already exists
  115. func CreateOrUpdateAnnotation(createAnnotation bool, obj runtime.Object, codec runtime.Encoder) error {
  116. if createAnnotation {
  117. return CreateApplyAnnotation(obj, codec)
  118. }
  119. return UpdateApplyAnnotation(obj, codec)
  120. }