github.com/mkimuram/operator-sdk@v0.7.1-0.20190410172100-52ad33a4bda0/doc/design/milestone-0.0.2/action-api.md (about) 1 # Operator-SDK Action API Design Doc 2 3 ## Goal 4 5 Define an API for performing Actions(Create,Update,Delete) that is flexible enough to allow the SDK user to execute a sequence of dependent Actions and perform error handling. 6 7 ## Background 8 9 For milestone `0.0.1` the SDK invokes the user provided handler for an Event, which would return a list of Actions that the SDK would execute. The motivation for this was to ensure that all Actions are taken through the SDK. 10 11 ```Go 12 // Handle reacts to events and outputs actions. 13 // If any intended action failed, the event would be re-triggered. 14 // For actions done before the failed action, there is no rollback. 15 func Handle(ctx context.Context, event sdkTypes.Event) []sdkTypes.Action 16 ``` 17 18 The provided actions were: 19 - `kube-apply`: Create or Update or specified object 20 - `kube-delete`: Delete the specified object 21 22 This workflow of batch executing actions outside of the handler has the following issues: 23 It makes it harder for the user to write their operator logic as a sequence of dependent actions and queries, e.g: 24 - Create a ConfigMap 25 - If it already exists 26 - Query some application state and verify the ConfigMap data 27 - Update the ConfigMap data with the latest state if needed 28 29 The user cannot handle errors for failed actions e.g updating the status if some action fails. Currently the Handler would just be retriggered with the Event if an Action fails 30 31 ## Proposed Solution 32 33 The SDK should provide an API to Create, Update and Delete objects from inside the Handler. This will allow users to write the core operator logic in a more intuitive way by using a sequence of actions and queries. 34 35 This method also aligns with the original goal of ensuring that all actions of the operator are taken through the SDK. 36 37 ## API 38 **Note:** `sdkTypes.Object` is just the kubernetes `runtime.Object` 39 40 ### Handler: 41 42 ```Go 43 // Handle contains the business logic for an handling an Event 44 // It uses SDK Actions and Queries to reconcile the state 45 // If an error is returned the Event would be requeued and sent to the Handler again 46 func Handle(ctx context.Context, event sdkTypes.Event) error 47 ``` 48 49 ### Create Update Delete: 50 ```Go 51 // Create creates the provided object on the server, and updates 52 // the local object with the generated result from the server(UID, resourceVersion, etc). 53 // Returns an error if the object’s TypeMeta(Kind, APIVersion) or ObjectMeta(Name, Namespace) is missing or incorrect. 54 // Can also return an api error from the server 55 // e.g AlreadyExists https://github.com/kubernetes/apimachinery/blob/master/pkg/api/errors/errors.go#L423 56 func Create(object sdkTypes.Object) error 57 ``` 58 59 ```Go 60 // Update updates the provided object on the server, and updates 61 // the local object with the generated result from the server(UID, resourceVersion, etc). 62 // Returns an error if the object’s TypeMeta(Kind, APIVersion) or ObjectMeta(Name, Namespace) is missing or incorrect. 63 // Can also return an api error from the server 64 // e.g Conflict https://github.com/kubernetes/apimachinery/blob/master/pkg/api/errors/errors.go#L428 65 func Update(object sdkTypes.Object) error 66 ``` 67 68 ```Go 69 // Delete deletes the specified object. 70 // Returns an error if the object’s TypeMeta(Kind, APIVersion) or ObjectMeta(Name, Namespace) is missing or incorrect. 71 // Can also return an api error from the server 72 // e.g NotFound https://github.com/kubernetes/apimachinery/blob/master/pkg/api/errors/errors.go#L418 73 // “opts” configures the k8s.io/apimachinery/pkg/apis/meta/v1.DeleteOptions 74 func Delete(object sdkTypes.Object, opts ...DeleteOption) error 75 ``` 76 77 ### Example Usage: 78 79 ```Go 80 import ( 81 "k8s.io/api/core/v1" 82 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 83 apierrors "k8s.io/apimachinery/pkg/api/errors" 84 ) 85 86 func Handle(ctx context.Context, event sdkType.Event) { 87 ... 88 pod := &v1.Pod{ 89 TypeMeta: metav1.TypeMeta{ 90 Kind: "Pod", 91 APIVersion: "v1", 92 }, 93 ObjectMeta: metav1.ObjectMeta { 94 Name: "example", 95 Namespace: "default", 96 }, 97 Spec: v1.PodSpec{ 98 ... 99 } 100 } 101 102 // Create 103 err := sdk.Create(pod) 104 if err != nil && !apierrors.IsAlreadyExists(err) { 105 return errors.New("failed to create pod") 106 } 107 108 // Update 109 err := sdk.Update(pod) 110 if err != nil { 111 return errors.New("failed to update pod") 112 } 113 114 ... 115 116 // Delete with default options 117 err := sdk.Delete(pod) 118 if err != nil { 119 return errors.New("failed to delete pod") 120 } 121 122 // Delete with custom options 123 gracePeriodSeconds := int64(5) 124 metav1DeleteOptions := &metav1.DeleteOptions{GracePeriodSeconds: &gracePeriodSeconds} 125 err := sdk.Delete(pod, sdk.WithDeleteOptions(metav1DeleteOptions)) 126 } 127 ``` 128 129 ## Reference: 130 131 ### DeleteOptions: 132 133 ```Go 134 // DeleteOp wraps all the options for Delete. 135 type DeleteOp struct { 136 metaDeleteOptions metav1.DeleteOptions 137 } 138 139 // DeleteOption configures DeleteOp 140 type DeleteOption func(*DeleteOp) 141 142 // WithDeleteOptions sets the meta_v1.DeleteOptions for 143 // the Delete() operation. 144 func WithDeleteOptions(metaDeleteOptions *metav1.DeleteOptions) DeleteOption { 145 return func(op *DeleteOp) { 146 op.metaDeleteOptions = metaDeleteOptions 147 } 148 } 149 ``` 150 151