github.com/docker/compose-on-kubernetes@v0.5.0/internal/registry/stackregistry.go (about) 1 package registry 2 3 import ( 4 "context" 5 6 iv "github.com/docker/compose-on-kubernetes/internal/internalversion" 7 "github.com/pkg/errors" 8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 9 "k8s.io/apimachinery/pkg/fields" 10 "k8s.io/apimachinery/pkg/labels" 11 "k8s.io/apimachinery/pkg/runtime" 12 "k8s.io/apiserver/pkg/registry/generic" 13 genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" 14 "k8s.io/apiserver/pkg/registry/rest" 15 "k8s.io/apiserver/pkg/storage" 16 appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1" 17 corev1 "k8s.io/client-go/kubernetes/typed/core/v1" 18 restclient "k8s.io/client-go/rest" 19 ) 20 21 const composeOutOfDate = "# This compose file is outdated: the stack was updated by other means\n" 22 23 // StackREST is a storage for stack resource 24 type StackREST struct { 25 genericregistry.Store 26 } 27 28 type stackRESTGet interface { 29 GetStack(ctx context.Context, name string, options *metav1.GetOptions) (*iv.Stack, error) 30 } 31 32 type stackRESTStore interface { 33 stackRESTGet 34 CreateStack(ctx context.Context, newStack *iv.Stack, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (*iv.Stack, error) 35 UpdateStack(ctx context.Context, name string, transform StackTransform, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, 36 forceAllowCreate bool, options *metav1.UpdateOptions) (*iv.Stack, bool, error) 37 } 38 39 // GetStack wraps the Get method in a more strictly typed way 40 func (s *StackREST) GetStack(ctx context.Context, name string, options *metav1.GetOptions) (*iv.Stack, error) { 41 obj, err := s.Get(ctx, name, options) 42 if err != nil { 43 return nil, err 44 } 45 stack, ok := obj.(*iv.Stack) 46 if !ok { 47 return nil, errors.New("Object is not a stack") 48 } 49 return stack, nil 50 } 51 52 // CreateStack wraps the Create method in a more strictly typed way 53 func (s *StackREST) CreateStack(ctx context.Context, newStack *iv.Stack, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (*iv.Stack, error) { 54 obj, err := s.Create(ctx, newStack, createValidation, options) 55 if err != nil { 56 return nil, err 57 } 58 stack, ok := obj.(*iv.Stack) 59 if !ok { 60 return nil, errors.New("Object is not a stack") 61 } 62 return stack, nil 63 } 64 65 // StackTransform is a transformation used in UpdateStack 66 type StackTransform func(ctx context.Context, newObj *iv.Stack, oldObj *iv.Stack) (transformedNewObj *iv.Stack, err error) 67 68 // UpdateStack wraps the Update method in a more strictly typed way 69 func (s *StackREST) UpdateStack(ctx context.Context, name string, transform StackTransform, 70 createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (*iv.Stack, bool, error) { 71 updateObjectInfo := rest.DefaultUpdatedObjectInfo(nil, 72 func(ctx context.Context, newObj runtime.Object, oldObj runtime.Object) (transformedNewObj runtime.Object, err error) { 73 if newObj == nil { 74 newObj = oldObj.DeepCopyObject() 75 } 76 oldStack, ok := oldObj.(*iv.Stack) 77 if !ok { 78 return nil, errors.New("oldObj is not a stack") 79 } 80 newStack, ok := newObj.(*iv.Stack) 81 if !ok { 82 return nil, errors.New("newObj is not a stack") 83 } 84 return transform(ctx, newStack, oldStack) 85 }) 86 obj, created, err := s.Update(ctx, name, updateObjectInfo, createValidation, updateValidation, forceAllowCreate, options) 87 if err != nil { 88 return nil, false, err 89 } 90 stack, ok := obj.(*iv.Stack) 91 if !ok { 92 return nil, false, errors.New("result is not a stack") 93 } 94 return stack, created, err 95 } 96 97 // NewStackREST return a rest store 98 func NewStackREST(version APIVersion, scheme rest.RESTDeleteStrategy, optsGetter generic.RESTOptionsGetter, config *restclient.Config) (*StackREST, error) { 99 coreClient, err := corev1.NewForConfig(config) 100 if err != nil { 101 return nil, err 102 } 103 appsClient, err := appsv1.NewForConfig(config) 104 if err != nil { 105 return nil, err 106 } 107 strategy := newStackStrategy(version, scheme, coreClient, appsClient) 108 109 store := &StackREST{ 110 genericregistry.Store{ 111 NewFunc: func() runtime.Object { return &iv.Stack{} }, 112 NewListFunc: func() runtime.Object { return &iv.StackList{} }, 113 PredicateFunc: matchStack, 114 DefaultQualifiedResource: iv.InternalSchemeGroupVersion.WithResource("stacks").GroupResource(), 115 116 CreateStrategy: strategy, 117 UpdateStrategy: strategy, 118 DeleteStrategy: strategy, 119 TableConvertor: stackTableConvertor{}, 120 }, 121 } 122 options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: getStackAttrs} 123 if err := store.CompleteWithOptions(options); err != nil { 124 return nil, err 125 } 126 return store, nil 127 } 128 129 func getStackAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { 130 stack, ok := obj.(*iv.Stack) 131 if !ok { 132 return nil, nil, errors.New("given object is not a Stack") 133 } 134 return labels.Set(stack.ObjectMeta.Labels), stackToSelectableFields(stack), nil 135 } 136 137 func matchStack(label labels.Selector, field fields.Selector) storage.SelectionPredicate { 138 return storage.SelectionPredicate{ 139 Label: label, 140 Field: field, 141 GetAttrs: getStackAttrs, 142 } 143 } 144 145 func stackToSelectableFields(obj *iv.Stack) fields.Set { 146 return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, true) 147 }