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 ```