github.com/fabianvf/ocp-release-operator-sdk@v0.0.0-20190426141702-57620ee2f090/doc/design/milestone-0.0.2/query-api.md (about)

     1  # Operator-SDK Query API Design Doc
     2  
     3  ## Goal
     4  
     5  In order to build a functional operator, the ability to observe state is a must. For e.g the etcd-operator needs to know the number of live etcd pods so that it can reconcile the etcd cluster based on that. The operator-sdk needs to provide an API to Query(`Get`, `List`) objects that would allow an operator to observe the state of its application.
     6  
     7  ## Background
     8  
     9  Client-go provides APIs for querying objects in the standard Kubernetes groups via `Get` and `List`.
    10  However, each client is specific to an object’s APIVersion and Kind which makes the API too verbose.
    11  For example, to get a specific Deployment object:
    12  - Create a Kubernetes clientset that implements kubernetes.Interface.
    13  - Call `kubeclient.AppsV1().Deployments("default").Get("name", v1.GetOptions{})`
    14  
    15  To retrieve a different object like a Pod, the above API would change to:
    16  `kubeclient.CoreV1().Pods("default").Get("name", v1.GetOptions{})`
    17  
    18  In addition Custom Resources also require their own clients that need to be generated by the users themselves via code-generation.
    19  
    20  To avoid these issues the SDK can provide a more generic API to query objects that would work for all object types.
    21  
    22  ## Proposal
    23  
    24  To simplify the retrieval of Kubernetes objects, the SDK can use a dynamic resource client to provide an API for `Get()` and `List()` that works for all object APIVersions and Kinds.
    25  
    26  ## API
    27  
    28  ### Get()
    29  
    30  ```Go
    31  // Get gets the Kubernetes object and then unmarshals the retrieved data into the "into" object.
    32  // "into" is a Kubernetes runtime.Object that must have
    33  // "Kind" and "APIVersion" specified in its "TypeMeta" field
    34  // and "Name" and "Namespace" specified in its "ObjectMeta" field.
    35  // Those are used to construct the underlying resource client.
    36  // "opts" configures the Get operation.
    37  func Get(into sdkTypes.Object, opts ...GetOption) error
    38  ```
    39  
    40  Get() accepts GetOption as variadic functional parameters. In this way, we follow the open-close principle 
    41  which allows us to extend the Get API with unforeseen parameters without modifying the API itself. See the reference section on how the options are implemented.
    42  
    43  Example Usage:
    44  ```Go
    45  // meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    46  
    47  d := &apps_v1.Deployment{
    48      TypeMeta: meta_v1.TypeMeta{
    49          Kind:       "Deployment",
    50          APIVersion: "apps/v1",
    51      }
    52      ObjectMeta: meta_v1.ObjectMeta{
    53          Name:      "example",
    54          Namespace: "default",
    55      }
    56  }
    57  // Get with default options
    58  err := sdk.Get(d)
    59  // Get with custom options 
    60  o := &meta_v1.GetOptions{ResourceVersion: "0"}
    61  err := sdk.Get(d, sdk.WithGetOptions(o))
    62  ```
    63  
    64  ### List()
    65  
    66  ```Go
    67  // List gets a list of Kubernetes object and then unmarshals the retrieved data into the "into" object.
    68  // "namespace" indicates which Kubernetes namespace to look for the list of Kubernetes objects.
    69  // "into" is a sdkType.Object that must have
    70  // "Kind" and "APIVersion" specified in its "TypeMeta" field
    71  // Those are used to construct the underlying resource client.
    72  // "opts" configures the List operation.
    73  func List(namespace string, into sdkTypes.Object, opts ...ListOption) error
    74  ```
    75  
    76  List() accepts ListOptions similar to GetOptions. See the reference section for implementation details.
    77  
    78  Example usage:
    79  
    80  ```Go
    81  // meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    82  // apps_v1 "k8s.io/api/apps/v1"
    83  
    84  dl := &apps_v1.DeploymentList{
    85      TypeMeta: meta_v1.TypeMeta{
    86          Kind:       "Deployment",
    87          APIVersion: "apps/v1",
    88      }
    89  }
    90  // List with default options
    91  err = sdk.List("default", dl)
    92  // List with custom options
    93  labelSelector := getLabelSelector("app", "dev")
    94  o := &metav1.ListOptions{LabelSelector: labelSelector}
    95  err = sdk.List("default", dl, op.WithListOptions(o))
    96  ```
    97  
    98  
    99  
   100  ## Reference: 
   101  
   102  ### GetOptions:
   103  
   104  ```Go
   105  // GetOp wraps all the options for Get().
   106  type GetOp struct {
   107      metaGetOptions *meta_v1.GetOptions
   108  }
   109  
   110  // GetOption configures GetOp.
   111  type GetOption func(*GetOp)
   112  
   113  
   114  // WithGetOptions sets the meta_v1.GetOptions for the Get() operation.
   115  func WithGetOptions(metaGetOptions *meta_v1.GetOptions) GetOption {
   116      return func(op *GetOp) {
   117          op.metaGetOptions = metaGetOptions
   118      }
   119  }
   120  ```
   121  
   122  ### ListOptions:
   123  
   124  ```Go
   125  // ListOp wraps all the options for List.
   126  type ListOp struct {
   127      metaListOptions *metav1.ListOptions
   128  }
   129  
   130  // ListOption configures ListOp.
   131  type ListOption func(*ListOp)
   132  
   133  // WithListOptions sets the meta_v1.ListOptions for
   134  // the List() operation.
   135  func WithListOptions(metaListOptions *meta_v1.ListOptions) ListOption {
   136      return func(op *ListOp) {
   137          op.metaListOptions = metaListOptions
   138      }
   139  }
   140  ```