...

Source file src/k8s.io/kubectl/pkg/util/apply.go

Documentation: k8s.io/kubectl/pkg/util

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package util
    18  
    19  import (
    20  	"k8s.io/api/core/v1"
    21  	"k8s.io/apimachinery/pkg/api/meta"
    22  	"k8s.io/apimachinery/pkg/runtime"
    23  )
    24  
    25  var metadataAccessor = meta.NewAccessor()
    26  
    27  // GetOriginalConfiguration retrieves the original configuration of the object
    28  // from the annotation, or nil if no annotation was found.
    29  func GetOriginalConfiguration(obj runtime.Object) ([]byte, error) {
    30  	annots, err := metadataAccessor.Annotations(obj)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  
    35  	if annots == nil {
    36  		return nil, nil
    37  	}
    38  
    39  	original, ok := annots[v1.LastAppliedConfigAnnotation]
    40  	if !ok {
    41  		return nil, nil
    42  	}
    43  
    44  	return []byte(original), nil
    45  }
    46  
    47  // SetOriginalConfiguration sets the original configuration of the object
    48  // as the annotation on the object for later use in computing a three way patch.
    49  func setOriginalConfiguration(obj runtime.Object, original []byte) error {
    50  	if len(original) < 1 {
    51  		return nil
    52  	}
    53  
    54  	annots, err := metadataAccessor.Annotations(obj)
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	if annots == nil {
    60  		annots = map[string]string{}
    61  	}
    62  
    63  	annots[v1.LastAppliedConfigAnnotation] = string(original)
    64  	return metadataAccessor.SetAnnotations(obj, annots)
    65  }
    66  
    67  // GetModifiedConfiguration retrieves the modified configuration of the object.
    68  // If annotate is true, it embeds the result as an annotation in the modified
    69  // configuration. If an object was read from the command input, it will use that
    70  // version of the object. Otherwise, it will use the version from the server.
    71  func GetModifiedConfiguration(obj runtime.Object, annotate bool, codec runtime.Encoder) ([]byte, error) {
    72  	// First serialize the object without the annotation to prevent recursion,
    73  	// then add that serialization to it as the annotation and serialize it again.
    74  	var modified []byte
    75  
    76  	// Otherwise, use the server side version of the object.
    77  	// Get the current annotations from the object.
    78  	annots, err := metadataAccessor.Annotations(obj)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	if annots == nil {
    84  		annots = map[string]string{}
    85  	}
    86  
    87  	original := annots[v1.LastAppliedConfigAnnotation]
    88  	delete(annots, v1.LastAppliedConfigAnnotation)
    89  	if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	modified, err = runtime.Encode(codec, obj)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	if annotate {
    99  		annots[v1.LastAppliedConfigAnnotation] = string(modified)
   100  		if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
   101  			return nil, err
   102  		}
   103  
   104  		modified, err = runtime.Encode(codec, obj)
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  	}
   109  
   110  	// Restore the object to its original condition.
   111  	annots[v1.LastAppliedConfigAnnotation] = original
   112  	if err := metadataAccessor.SetAnnotations(obj, annots); err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	return modified, nil
   117  }
   118  
   119  // updateApplyAnnotation calls CreateApplyAnnotation if the last applied
   120  // configuration annotation is already present. Otherwise, it does nothing.
   121  func updateApplyAnnotation(obj runtime.Object, codec runtime.Encoder) error {
   122  	if original, err := GetOriginalConfiguration(obj); err != nil || len(original) <= 0 {
   123  		return err
   124  	}
   125  	return CreateApplyAnnotation(obj, codec)
   126  }
   127  
   128  // CreateApplyAnnotation gets the modified configuration of the object,
   129  // without embedding it again, and then sets it on the object as the annotation.
   130  func CreateApplyAnnotation(obj runtime.Object, codec runtime.Encoder) error {
   131  	modified, err := GetModifiedConfiguration(obj, false, codec)
   132  	if err != nil {
   133  		return err
   134  	}
   135  	return setOriginalConfiguration(obj, modified)
   136  }
   137  
   138  // CreateOrUpdateAnnotation creates the annotation used by
   139  // kubectl apply only when createAnnotation is true
   140  // Otherwise, only update the annotation when it already exists
   141  func CreateOrUpdateAnnotation(createAnnotation bool, obj runtime.Object, codec runtime.Encoder) error {
   142  	if createAnnotation {
   143  		return CreateApplyAnnotation(obj, codec)
   144  	}
   145  	return updateApplyAnnotation(obj, codec)
   146  }
   147  

View as plain text