github.com/docker/compose-on-kubernetes@v0.5.0/internal/apiserver/apiserver.go (about) 1 package apiserver 2 3 import ( 4 "net/http" 5 "reflect" 6 "unsafe" 7 8 "github.com/docker/compose-on-kubernetes/api/compose/v1alpha3" 9 "github.com/docker/compose-on-kubernetes/api/compose/v1beta1" 10 "github.com/docker/compose-on-kubernetes/api/compose/v1beta2" 11 "github.com/docker/compose-on-kubernetes/internal/conversions" 12 "github.com/docker/compose-on-kubernetes/internal/internalversion" 13 composeregistry "github.com/docker/compose-on-kubernetes/internal/registry" 14 "github.com/docker/compose-on-kubernetes/internal/requestaddons" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 "k8s.io/apimachinery/pkg/runtime" 17 "k8s.io/apimachinery/pkg/runtime/schema" 18 "k8s.io/apimachinery/pkg/runtime/serializer" 19 "k8s.io/apimachinery/pkg/util/sets" 20 "k8s.io/apimachinery/pkg/version" 21 "k8s.io/apiserver/pkg/registry/rest" 22 genericapiserver "k8s.io/apiserver/pkg/server" 23 genericfilters "k8s.io/apiserver/pkg/server/filters" 24 "k8s.io/client-go/tools/clientcmd" 25 ) 26 27 // Internal variables 28 var ( 29 Scheme = runtime.NewScheme() 30 Codecs = serializer.NewCodecFactory(Scheme) 31 ) 32 33 func init() { 34 metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) 35 unversioned := schema.GroupVersion{Group: "", Version: "v1"} 36 Scheme.AddUnversionedTypes(unversioned, 37 &metav1.Status{}, 38 &metav1.APIVersions{}, 39 &metav1.APIGroupList{}, 40 &metav1.APIGroup{}, 41 &metav1.APIResourceList{}, 42 ) 43 v1beta1.AddToScheme(Scheme) 44 v1beta2.AddToScheme(Scheme) 45 v1alpha3.AddToScheme(Scheme) 46 Scheme.SetVersionPriority(v1alpha3.SchemeGroupVersion, v1beta2.SchemeGroupVersion, v1beta1.SchemeGroupVersion) 47 internalversion.AddStorageToScheme(Scheme) 48 internalversion.AddInternalToScheme(Scheme) 49 if err := conversions.RegisterV1beta1Conversions(Scheme); err != nil { 50 panic(err) 51 } 52 if err := conversions.RegisterV1alpha3Conversions(Scheme); err != nil { 53 panic(err) 54 } 55 if err := conversions.RegisterV1beta2Conversions(Scheme); err != nil { 56 panic(err) 57 } 58 // We do not support protobuf serialization as the `Stack` struct has 59 // fields with unsupported types (e.g.: map[string]*string). This causes 60 // issues like https://github.com/docker/compose-on-kubernetes/issues/150. 61 // The workaround is to remove protobuf from the advertised supported codecs. 62 removeProtobufMediaType(&Codecs) 63 } 64 65 // removeProtobufMediaType removes protobuf from the list of accepted media 66 // types for the given CodecFactory. 67 func removeProtobufMediaType(c *serializer.CodecFactory) { 68 codecsPtr := reflect.Indirect(reflect.ValueOf(c)) 69 accepts := codecsPtr.FieldByName("accepts") 70 acceptsPtr := (*[]runtime.SerializerInfo)(unsafe.Pointer(accepts.UnsafeAddr())) 71 for i, v := range *acceptsPtr { 72 if v.MediaType == runtime.ContentTypeProtobuf { 73 *acceptsPtr = append((*acceptsPtr)[0:i], (*acceptsPtr)[i+1:]...) 74 break 75 } 76 } 77 } 78 79 // Config is the API server config 80 type Config struct { 81 GenericConfig *genericapiserver.RecommendedConfig 82 } 83 84 type completedConfig struct { 85 GenericConfig genericapiserver.CompletedConfig 86 } 87 88 // CompletedConfig is the complete API server config 89 type CompletedConfig struct { 90 // Embed a private pointer that cannot be instantiated outside of this package. 91 *completedConfig 92 } 93 94 // Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. 95 func (cfg *Config) Complete() CompletedConfig { 96 cfg.GenericConfig.BuildHandlerChainFunc = func(apiHandler http.Handler, c *genericapiserver.Config) (secure http.Handler) { 97 handler := requestaddons.WithSkipValidationHandler(apiHandler) 98 return genericapiserver.DefaultBuildHandlerChain(handler, c) 99 } 100 c := completedConfig{ 101 GenericConfig: cfg.GenericConfig.Complete(), 102 } 103 104 c.GenericConfig.Version = &version.Info{ 105 Major: "1", 106 Minor: "0", 107 } 108 109 c.GenericConfig.LongRunningFunc = genericfilters.BasicLongRunningRequestCheck(sets.NewString("watch"), sets.NewString("log")) 110 111 return CompletedConfig{&c} 112 } 113 114 // ComposeServer is the compose api server 115 type ComposeServer struct { 116 *genericapiserver.GenericAPIServer 117 } 118 119 // New returns a new instance of ComposeServer from the given config. 120 func (c completedConfig) New(kubeconfig string) (*ComposeServer, error) { 121 config, err := clientcmd.BuildConfigFromFlags("", kubeconfig) 122 if err != nil { 123 return nil, err 124 } 125 genericServer, err := c.GenericConfig.New("compose-apiserver", genericapiserver.NewEmptyDelegate()) 126 if err != nil { 127 return nil, err 128 } 129 130 s := &ComposeServer{ 131 GenericAPIServer: genericServer, 132 } 133 apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(v1beta2.GroupName, Scheme, metav1.ParameterCodec, Codecs) 134 135 stackRegistry1, err := composeregistry.NewStackREST(composeregistry.APIV1beta1, Scheme, c.GenericConfig.RESTOptionsGetter, config) 136 if err != nil { 137 return nil, err 138 } 139 140 stackRegistry2, err := composeregistry.NewStackREST(composeregistry.APIV1beta2, Scheme, c.GenericConfig.RESTOptionsGetter, config) 141 if err != nil { 142 return nil, err 143 } 144 stackOwnerRegistry1 := composeregistry.NewStackOwnerRest(stackRegistry1, composeregistry.APIV1beta1) 145 v1beta1storage := map[string]rest.Storage{} 146 v1beta1storage["stacks"] = stackRegistry1 147 v1beta1storage["stacks/owner"] = stackOwnerRegistry1 148 apiGroupInfo.VersionedResourcesStorageMap["v1beta1"] = v1beta1storage 149 150 stackOwnerRegistry2 := composeregistry.NewStackOwnerRest(stackRegistry2, composeregistry.APIV1beta2) 151 stackComposeFileRegistry := composeregistry.NewStackComposeFileRest(stackRegistry1) 152 stackScaleRegistry := composeregistry.NewStackScaleRest(stackRegistry2, config) 153 stackLogRegistry := composeregistry.NewStackLogRest(config) 154 v1beta2storage := map[string]rest.Storage{} 155 v1beta2storage["stacks"] = stackRegistry2 156 v1beta2storage["stacks/owner"] = stackOwnerRegistry2 157 v1beta2storage["stacks/composeFile"] = stackComposeFileRegistry 158 v1beta2storage["stacks/scale"] = stackScaleRegistry 159 v1beta2storage["stacks/log"] = stackLogRegistry 160 apiGroupInfo.VersionedResourcesStorageMap["v1beta2"] = v1beta2storage 161 162 // v1alpha3 has exactly the same implementation as v1beta2 163 apiGroupInfo.VersionedResourcesStorageMap["v1alpha3"] = v1beta2storage 164 165 if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { 166 return nil, err 167 } 168 169 return s, nil 170 }