k8s.io/client-go@v0.22.2/applyconfigurations/doc.go (about)

     1  /*
     2  Copyright 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  // Code generated by applyconfiguration-gen. DO NOT EDIT.
    18  
    19  /*
    20  Package applyconfigurations provides typesafe go representations of the apply
    21  configurations that are used to constructs Server-side Apply requests.
    22  
    23  Basics
    24  
    25  The Apply functions in the typed client (see the k8s.io/client-go/kubernetes/typed packages) offer
    26  a direct and typesafe way of calling Server-side Apply. Each Apply function takes an "apply
    27  configuration" type as an argument, which is a structured representation of an Apply request. For
    28  example:
    29  
    30      import (
    31           ...
    32           v1ac "k8s.io/client-go/applyconfigurations/autoscaling/v1"
    33      )
    34      hpaApplyConfig := v1ac.HorizontalPodAutoscaler(autoscalerName, ns).
    35           WithSpec(v1ac.HorizontalPodAutoscalerSpec().
    36                    WithMinReplicas(0)
    37           )
    38      return hpav1client.Apply(ctx, hpaApplyConfig, metav1.ApplyOptions{FieldManager: "mycontroller", Force: true})
    39  
    40  Note in this example that HorizontalPodAutoscaler is imported from an "applyconfigurations"
    41  package. Each "apply configuration" type represents the same Kubernetes object kind as the
    42  corresponding go struct, but where all fields are pointers to make them optional, allowing apply
    43  requests to be accurately represented. For example, this when the apply configuration in the above
    44  example is marshalled to YAML, it produces:
    45  
    46      apiVersion: autoscaling/v1
    47      kind: HorizontalPodAutoscaler
    48      metadata:
    49          name: myHPA
    50          namespace: myNamespace
    51      spec:
    52          minReplicas: 0
    53  
    54  To understand why this is needed, the above YAML cannot be produced by the
    55  v1.HorizontalPodAutoscaler go struct. Take for example:
    56  
    57      hpa := v1.HorizontalPodAutoscaler{
    58           TypeMeta: metav1.TypeMeta{
    59                    APIVersion: "autoscaling/v1",
    60                    Kind:       "HorizontalPodAutoscaler",
    61           },
    62           ObjectMeta: ObjectMeta{
    63                    Namespace: ns,
    64                    Name:      autoscalerName,
    65           },
    66           Spec: v1.HorizontalPodAutoscalerSpec{
    67                    MinReplicas: pointer.Int32Ptr(0),
    68           },
    69      }
    70  
    71  The above code attempts to declare the same apply configuration as shown in the previous examples,
    72  but when marshalled to YAML, produces:
    73  
    74      kind: HorizontalPodAutoscaler
    75      apiVersion: autoscaling/v1
    76      metadata:
    77        name: myHPA
    78        namespace: myNamespace
    79        creationTimestamp: null
    80      spec:
    81        scaleTargetRef:
    82          kind: ""
    83          name: ""
    84        minReplicas: 0
    85        maxReplicas: 0
    86  
    87  Which, among other things, contains spec.maxReplicas set to 0. This is almost certainly not what
    88  the caller intended (the intended apply configuration says nothing about the maxReplicas field),
    89  and could have serious consequences on a production system: it directs the autoscaler to downscale
    90  to zero pods. The problem here originates from the fact that the go structs contain required fields
    91  that are zero valued if not set explicitly. The go structs work as intended for create and update
    92  operations, but are fundamentally incompatible with apply, which is why we have introduced the
    93  generated "apply configuration" types.
    94  
    95  The "apply configurations" also have convenience With<FieldName> functions that make it easier to
    96  build apply requests. This allows developers to set fields without having to deal with the fact that
    97  all the fields in the "apply configuration" types are pointers, and are inconvenient to set using
    98  go. For example "MinReplicas: &0" is not legal go code, so without the With functions, developers
    99  would work around this problem by using a library, .e.g. "MinReplicas: pointer.Int32Ptr(0)", but
   100  string enumerations like corev1.Protocol are still a problem since they cannot be supported by a
   101  general purpose library. In addition to the convenience, the With functions also isolate
   102  developers from the underlying representation, which makes it safer for the underlying
   103  representation to be changed to support additional features in the future.
   104  
   105  Controller Support
   106  
   107  The new client-go support makes it much easier to use Server-side Apply in controllers, by either of
   108  two mechanisms.
   109  
   110  Mechanism 1:
   111  
   112  When authoring new controllers to use Server-side Apply, a good approach is to have the controller
   113  recreate the apply configuration for an object each time it reconciles that object.  This ensures
   114  that the controller fully reconciles all the fields that it is responsible for. Controllers
   115  typically should unconditionally set all the fields they own by setting "Force: true" in the
   116  ApplyOptions. Controllers must also provide a FieldManager name that is unique to the
   117  reconciliation loop that apply is called from.
   118  
   119  When upgrading existing controllers to use Server-side Apply the same approach often works
   120  well--migrate the controllers to recreate the apply configuration each time it reconciles any
   121  object. For cases where this does not work well, see Mechanism 2.
   122  
   123  Mechanism 2:
   124  
   125  When upgrading existing controllers to use Server-side Apply, the controller might have multiple
   126  code paths that update different parts of an object depending on various conditions. Migrating a
   127  controller like this to Server-side Apply can be risky because if the controller forgets to include
   128  any fields in an apply configuration that is included in a previous apply request, a field can be
   129  accidentally deleted. For such cases, an alternative to mechanism 1 is to replace any controller
   130  reconciliation code that performs a "read/modify-in-place/update" (or patch) workflow with a
   131  "extract/modify-in-place/apply" workflow. Here's an example of the new workflow:
   132  
   133      fieldMgr := "my-field-manager"
   134      deploymentClient := clientset.AppsV1().Deployments("default")
   135      // read, could also be read from a shared informer
   136      deployment, err := deploymentClient.Get(ctx, "example-deployment", metav1.GetOptions{})
   137      if err != nil {
   138        // handle error
   139      }
   140      // extract
   141      deploymentApplyConfig, err := appsv1ac.ExtractDeployment(deployment, fieldMgr)
   142      if err != nil {
   143        // handle error
   144      }
   145      // modify-in-place
   146      deploymentApplyConfig.Spec.Template.Spec.WithContainers(corev1ac.Container().
   147  	WithName("modify-slice").
   148  	WithImage("nginx:1.14.2"),
   149      )
   150      // apply
   151      applied, err := deploymentClient.Apply(ctx, extractedDeployment, metav1.ApplyOptions{FieldManager: fieldMgr})
   152  */
   153  package applyconfigurations