// New creates a new WebhookAuthorizer from the provided kubeconfig file. // // The config's cluster field is used to refer to the remote service, user refers to the returned authorizer. // // # clusters refers to the remote service. // clusters: // - name: name-of-remote-authz-service // cluster: // certificate-authority: /path/to/ca.pem # CA for verifying the remote service. // server: https://authz.example.com/authorize # URL of remote service to query. Must use 'https'. // // # users refers to the API server's webhook configuration. // users: // - name: name-of-api-server // user: // client-certificate: /path/to/cert.pem # cert for the webhook plugin to use // client-key: /path/to/key.pem # key matching the cert // // For additional HTTP configuration, refer to the kubeconfig documentation // http://kubernetes.io/v1.1/docs/user-guide/kubeconfig-file.html. func New(kubeConfigFile string) (*WebhookAuthorizer, error) { for _, groupVersion := range requireEnabled { if !registered.IsEnabledVersion(groupVersion) { return nil, fmt.Errorf("webhook authz plugin requires enabling extension resource: %s", groupVersion) } } loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() loadingRules.ExplicitPath = kubeConfigFile loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) clientConfig, err := loader.ClientConfig() if err != nil { return nil, err } serializer := json.NewSerializer(json.DefaultMetaFactory, api.Scheme, runtime.ObjectTyperToTyper(api.Scheme), false) clientConfig.ContentConfig.Codec = versioning.NewCodecForScheme(api.Scheme, serializer, serializer, encodeVersions, decodeVersions) restClient, err := restclient.UnversionedRESTClientFor(clientConfig) if err != nil { return nil, err } // TODO(ericchiang): Can we ensure remote service is reachable? return &WebhookAuthorizer{restClient}, nil }
// NewGenericWebhook creates a new GenericWebhook from the provided kubeconfig file. func NewGenericWebhook(kubeConfigFile string, groupVersions []unversioned.GroupVersion, initialBackoff time.Duration) (*GenericWebhook, error) { for _, groupVersion := range groupVersions { if !registered.IsEnabledVersion(groupVersion) { return nil, fmt.Errorf("webhook plugin requires enabling extension resource: %s", groupVersion) } } loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() loadingRules.ExplicitPath = kubeConfigFile loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{}) clientConfig, err := loader.ClientConfig() if err != nil { return nil, err } codec := api.Codecs.LegacyCodec(groupVersions...) clientConfig.ContentConfig.NegotiatedSerializer = runtimeserializer.NegotiatedSerializerWrapper( runtime.SerializerInfo{Serializer: codec}, runtime.StreamSerializerInfo{}, ) restClient, err := restclient.UnversionedRESTClientFor(clientConfig) if err != nil { return nil, err } // TODO(ericchiang): Can we ensure remote service is reachable? return &GenericWebhook{restClient, initialBackoff}, nil }
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) { // add the internal version to Scheme core.AddToScheme(core.Scheme) // add the enabled external versions to Scheme for _, v := range externalVersions { if !registered.IsEnabledVersion(v) { glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v) continue } switch v { case core_v1.SchemeGroupVersion: core_v1.AddToScheme(core.Scheme) } } // This is a "fast-path" that avoids reflection for common types. It focuses on the objects that are // converted the most in the cluster. // TODO: generate one of these for every external API group - this is to prove the impact core.Scheme.AddGenericConversionFunc(func(objA, objB interface{}, s conversion.Scope) (bool, error) { switch a := objA.(type) { case *v1.Service: switch b := objB.(type) { case *api.Service: return true, v1.Convert_v1_Service_To_api_Service(a, b, s) } case *api.Service: switch b := objB.(type) { case *v1.Service: return true, v1.Convert_api_Service_To_v1_Service(a, b, s) } } return false, nil }) }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := json.DefaultMetaFactory.Interpret(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.EnabledVersions()) } if registered.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { // Don't attempt to validate third party objects return nil } switch gvk.Group { case federation.GroupName: if c.fedc == nil { return errors.New("unable to validate: no federation client") } return getSchemaAndValidate(c.fedc, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) case api.GroupName: return getSchemaAndValidate(c.c, data, "api", gvk.GroupVersion().String(), c.cacheDir, c) default: return getSchemaAndValidate(c.c, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } }
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) { // add the internal version to Scheme if err := batch.AddToScheme(api.Scheme); err != nil { // Programmer error, detect immediately panic(err) } // add the enabled external versions to Scheme for _, v := range externalVersions { if !registered.IsEnabledVersion(v) { glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v) continue } switch v { case v1.SchemeGroupVersion: if err := v1.AddToScheme(api.Scheme); err != nil { // Programmer error, detect immediately panic(err) } case v2alpha1.SchemeGroupVersion: if err := v2alpha1.AddToScheme(api.Scheme); err != nil { // Programmer error, detect immediately panic(err) } } } }
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) { // add the internal version to Scheme api.AddToScheme(kapi.Scheme) // add the enabled external versions to Scheme for _, v := range externalVersions { if !registered.IsEnabledVersion(v) { glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v) continue } switch v { case v1.SchemeGroupVersion: v1.AddToScheme(kapi.Scheme) case v1beta3.SchemeGroupVersion: v1beta3.AddToScheme(kapi.Scheme) case docker10.SchemeGroupVersion: docker10.AddToScheme(kapi.Scheme) case dockerpre012.SchemeGroupVersion: dockerpre012.AddToScheme(kapi.Scheme) default: glog.Errorf("Version %s is not known, so it will not be added to the Scheme.", v) continue } } }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := json.DefaultMetaFactory.Interpret(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.EnabledVersions()) } if gvk.Group == autoscaling.GroupName { if c.c.AutoscalingClient == nil { return errors.New("unable to validate: no autoscaling client") } return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } if gvk.Group == batch.GroupName { if c.c.BatchClient == nil { return errors.New("unable to validate: no batch client") } return getSchemaAndValidate(c.c.BatchClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } if gvk.Group == extensions.GroupName { if c.c.ExtensionsClient == nil { return errors.New("unable to validate: no experimental client") } return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } return getSchemaAndValidate(c.c.RESTClient, data, "api", gvk.GroupVersion().String(), c.cacheDir) }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := json.DefaultMetaFactory.Interpret(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.EnabledVersions()) } if gvk.Group == autoscaling.GroupName { if c.c.AutoscalingClient == nil { return errors.New("unable to validate: no autoscaling client") } return getSchemaAndValidate(c.c.AutoscalingClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == policy.GroupName { if c.c.PolicyClient == nil { return errors.New("unable to validate: no policy client") } return getSchemaAndValidate(c.c.PolicyClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == apps.GroupName { if c.c.AppsClient == nil { return errors.New("unable to validate: no autoscaling client") } return getSchemaAndValidate(c.c.AppsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == batch.GroupName { if c.c.BatchClient == nil { return errors.New("unable to validate: no batch client") } return getSchemaAndValidate(c.c.BatchClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == rbac.GroupName { if c.c.RbacClient == nil { return errors.New("unable to validate: no rbac client") } return getSchemaAndValidate(c.c.RbacClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if registered.IsThirdPartyAPIGroupVersion(gvk.GroupVersion()) { // Don't attempt to validate third party objects return nil } if gvk.Group == extensions.GroupName { if c.c.ExtensionsClient == nil { return errors.New("unable to validate: no experimental client") } return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } if gvk.Group == federation.GroupName { if c.fedc == nil { return errors.New("unable to validate: no federation client") } return getSchemaAndValidate(c.fedc, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } return getSchemaAndValidate(c.c.RESTClient, data, "api", gvk.GroupVersion().String(), c.cacheDir, c) }
// Complete collects information required to run Convert command from command line. func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) { o.outputVersion, err = cmdutil.OutputVersion(cmd, ®istered.EnabledVersionsForGroup(api.GroupName)[0]) if err != nil { return err } if !registered.IsEnabledVersion(o.outputVersion) { cmdutil.UsageError(cmd, "'%s' is not a registered version.", o.outputVersion) } // build the builder mapper, typer := f.Object(cmdutil.GetIncludeThirdPartyAPIs(cmd)) clientMapper := resource.ClientMapperFunc(f.ClientForMapping) if o.local { fmt.Fprintln(os.Stderr, "running in local mode...") o.builder = resource.NewBuilder(mapper, typer, resource.DisabledClientForMapping{ClientMapper: clientMapper}, f.Decoder(true)) } else { o.builder = resource.NewBuilder(mapper, typer, clientMapper, f.Decoder(true)) schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir")) if err != nil { return err } o.builder = o.builder.Schema(schema) } cmdNamespace, _, err := f.DefaultNamespace() if err != nil { return err } o.builder = o.builder.NamespaceParam(cmdNamespace). ContinueOnError(). FilenameParam(false, o.recursive, o.filenames...). Flatten() // build the printer o.out = out outputFormat := cmdutil.GetFlagString(cmd, "output") templateFile := cmdutil.GetFlagString(cmd, "template") if len(outputFormat) == 0 { if len(templateFile) == 0 { outputFormat = "yaml" } else { outputFormat = "template" } } o.encoder = f.JSONEncoder() o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile, false) if err != nil { return err } return nil }
// InfoForData creates an Info object for the given data. An error is returned // if any of the decoding or client lookup steps fail. Name and namespace will be // set into Info if the mapping's MetadataAccessor can retrieve them. func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) { json, err := yaml.ToJSON(data) if err != nil { return nil, fmt.Errorf("unable to parse %q: %v", source, err) } data = json gvk, err := runtime.UnstructuredJSONScheme.DataKind(data) if err != nil { return nil, fmt.Errorf("unable to get type info from %q: %v", source, err) } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return nil, fmt.Errorf("API version %q in %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), source, registered.EnabledVersions()) } if gvk.Kind == "" { return nil, fmt.Errorf("kind not set in %q", source) } mapping, err := m.RESTMapping(gvk.GroupKind(), gvk.Version) if err != nil { return nil, fmt.Errorf("unable to recognize %q: %v", source, err) } obj, err := mapping.Codec.Decode(data) if err != nil { return nil, fmt.Errorf("unable to load %q: %v", source, err) } client, err := m.ClientForMapping(mapping) if err != nil { return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err) } name, _ := mapping.MetadataAccessor.Name(obj) namespace, _ := mapping.MetadataAccessor.Namespace(obj) resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj) var versionedObject interface{} if vo, _, err := api.Scheme.Raw().DecodeToVersionedObject(data); err == nil { versionedObject = vo } return &Info{ Mapping: mapping, Client: client, Namespace: namespace, Name: name, Source: source, VersionedObject: versionedObject, Object: obj, ResourceVersion: resourceVersion, }, nil }
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) { // add the internal version to Scheme authentication.AddToScheme(api.Scheme) // add the enabled external versions to Scheme for _, v := range externalVersions { if !registered.IsEnabledVersion(v) { glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v) continue } switch v { case v1beta1.SchemeGroupVersion: v1beta1.AddToScheme(api.Scheme) } } }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := runtime.UnstructuredJSONScheme.DataKind(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.EnabledVersions()) } if gvk.Group == extensions.GroupName { if c.c.ExtensionsClient == nil { return errors.New("unable to validate: no experimental client") } return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir) } return getSchemaAndValidate(c.c.RESTClient, data, "api", gvk.GroupVersion().String(), c.cacheDir) }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { gvk, err := json.DefaultMetaFactory.Interpret(data) if err != nil { return err } if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok { // if we don't have this in our scheme, just skip validation because its an object we don't recognize return nil } switch gvk.Group { case api.GroupName: return getSchemaAndValidate(c.c, data, "api", gvk.GroupVersion().String(), c.cacheDir, c) default: return getSchemaAndValidate(c.c, data, "apis/", gvk.GroupVersion().String(), c.cacheDir, c) } }
func setConfigDefaults(config *restclient.Config) error { gv, err := schema.ParseGroupVersion("policy/v1beta1") if err != nil { return err } // if policy/v1beta1 is not enabled, return an error if !registered.IsEnabledVersion(gv) { return fmt.Errorf("policy/v1beta1 is not enabled") } config.APIPath = "/apis" if config.UserAgent == "" { config.UserAgent = restclient.DefaultKubernetesUserAgent() } copyGroupVersion := gv config.GroupVersion = ©GroupVersion config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: api.Codecs} return nil }
func (c LegacyRESTStorageProvider) NewLegacyRESTStorage(restOptionsGetter genericapiserver.RESTOptionsGetter) (LegacyRESTStorage, genericapiserver.APIGroupInfo, error) { apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{}, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{}, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale") } var podDisruptionClient policyclient.PodDisruptionBudgetsGetter if policyGroupVersion := (unversioned.GroupVersion{Group: "policy", Version: "v1beta1"}); registered.IsEnabledVersion(policyGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind["pods/eviction"] = policyGroupVersion.WithKind("Eviction") var err error podDisruptionClient, err = policyclient.NewForConfig(c.LoopbackClientConfig) if err != nil { return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err } } restStorage := LegacyRESTStorage{} podTemplateStorage := podtemplateetcd.NewREST(restOptionsGetter(api.Resource("podTemplates"))) eventStorage := eventetcd.NewREST(restOptionsGetter(api.Resource("events")), uint64(c.EventTTL.Seconds())) limitRangeStorage := limitrangeetcd.NewREST(restOptionsGetter(api.Resource("limitRanges"))) resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewREST(restOptionsGetter(api.Resource("resourceQuotas"))) secretStorage := secretetcd.NewREST(restOptionsGetter(api.Resource("secrets"))) serviceAccountStorage := serviceaccountetcd.NewREST(restOptionsGetter(api.Resource("serviceAccounts"))) persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewREST(restOptionsGetter(api.Resource("persistentVolumes"))) persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewREST(restOptionsGetter(api.Resource("persistentVolumeClaims"))) configMapStorage := configmapetcd.NewREST(restOptionsGetter(api.Resource("configMaps"))) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewREST(restOptionsGetter(api.Resource("namespaces"))) restStorage.NamespaceRegistry = namespace.NewRegistry(namespaceStorage) endpointsStorage := endpointsetcd.NewREST(restOptionsGetter(api.Resource("endpoints"))) restStorage.EndpointRegistry = endpoint.NewRegistry(endpointsStorage) nodeStorage, err := nodeetcd.NewStorage(restOptionsGetter(api.Resource("nodes")), c.KubeletClientConfig, c.ProxyTransport) if err != nil { return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err } restStorage.NodeRegistry = node.NewRegistry(nodeStorage.Node) securityContextConstraintsStorage := sccetcd.NewStorage(restOptionsGetter(api.Resource("securityContextConstraints"))) podStorage := podetcd.NewStorage( restOptionsGetter(api.Resource("pods")), nodeStorage.KubeletConnectionInfo, c.ProxyTransport, podDisruptionClient, ) serviceRESTStorage, serviceStatusStorage := serviceetcd.NewREST(restOptionsGetter(api.Resource("services"))) restStorage.ServiceRegistry = service.NewRegistry(serviceRESTStorage) var serviceClusterIPRegistry rangeallocation.RangeRegistry serviceClusterIPRange := c.ServiceIPRange if serviceClusterIPRange.IP == nil { return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, fmt.Errorf("service clusterIPRange is missing") } serviceStorageConfig, err := c.StorageFactory.NewConfig(api.Resource("services")) if err != nil { return LegacyRESTStorage{}, genericapiserver.APIGroupInfo{}, err } ServiceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(&serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) // TODO etcdallocator package to return a storage interface via the storageFactory etcd := etcdallocator.NewEtcd(mem, "/ranges/serviceips", api.Resource("serviceipallocations"), serviceStorageConfig) serviceClusterIPRegistry = etcd return etcd }) restStorage.ServiceClusterIPAllocator = serviceClusterIPRegistry var serviceNodePortRegistry rangeallocation.RangeRegistry ServiceNodePortAllocator := portallocator.NewPortAllocatorCustom(c.ServiceNodePortRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) // TODO etcdallocator package to return a storage interface via the storageFactory etcd := etcdallocator.NewEtcd(mem, "/ranges/servicenodeports", api.Resource("servicenodeportallocations"), serviceStorageConfig) serviceNodePortRegistry = etcd return etcd }) restStorage.ServiceNodePortAllocator = serviceNodePortRegistry controllerStorage := controlleretcd.NewStorage(restOptionsGetter(api.Resource("replicationControllers"))) serviceRest := service.NewStorage(restStorage.ServiceRegistry, restStorage.EndpointRegistry, ServiceClusterIPAllocator, ServiceNodePortAllocator, c.ProxyTransport) restStorageMap := map[string]rest.Storage{ "pods": podStorage.Pod, "pods/attach": podStorage.Attach, "pods/status": podStorage.Status, "pods/log": podStorage.Log, "pods/exec": podStorage.Exec, "pods/portforward": podStorage.PortForward, "pods/proxy": podStorage.Proxy, "pods/binding": podStorage.Binding, "bindings": podStorage.Binding, "podTemplates": podTemplateStorage, "replicationControllers": controllerStorage.Controller, "replicationControllers/status": controllerStorage.Status, "services": serviceRest.Service, "services/proxy": serviceRest.Proxy, "services/status": serviceStatusStorage, "endpoints": endpointsStorage, "nodes": nodeStorage.Node, "nodes/status": nodeStorage.Status, "nodes/proxy": nodeStorage.Proxy, "events": eventStorage, "limitRanges": limitRangeStorage, "resourceQuotas": resourceQuotaStorage, "resourceQuotas/status": resourceQuotaStatusStorage, "namespaces": namespaceStorage, "namespaces/status": namespaceStatusStorage, "namespaces/finalize": namespaceFinalizeStorage, "secrets": secretStorage, "serviceAccounts": serviceAccountStorage, "securityContextConstraints": securityContextConstraintsStorage, "persistentVolumes": persistentVolumeStorage, "persistentVolumes/status": persistentVolumeStatusStorage, "persistentVolumeClaims": persistentVolumeClaimStorage, "persistentVolumeClaims/status": persistentVolumeClaimStatusStorage, "configMaps": configMapStorage, "componentStatuses": componentstatus.NewStorage(componentStatusStorage{c.StorageFactory}.serversToValidate), } if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) { restStorageMap["replicationControllers/scale"] = controllerStorage.Scale } if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "policy", Version: "v1beta1"}) { restStorageMap["pods/eviction"] = podStorage.Eviction } apiGroupInfo.VersionedResourcesStorageMap["v1"] = restStorageMap return restStorage, apiGroupInfo, nil }
func (d *discoveryRESTMapper) getDelegate() (meta.RESTMapper, error) { d.initLock.Lock() defer d.initLock.Unlock() if d.delegate != nil { return d.delegate, nil } serverGroups, err := d.discoveryClient.ServerGroups() if err != nil { return nil, err } // always prefer our default group for now. The version should be discovered from discovery, but this will hold us // for quite some time. resourcePriority := []unversioned.GroupVersionResource{ {Group: kapi.GroupName, Version: meta.AnyVersion, Resource: meta.AnyResource}, } kindPriority := []unversioned.GroupVersionKind{ {Group: kapi.GroupName, Version: meta.AnyVersion, Kind: meta.AnyKind}, } groupPriority := []string{} unionMapper := meta.MultiRESTMapper{} for _, group := range serverGroups.Groups { if len(group.Versions) == 0 { continue } groupPriority = append(groupPriority, group.Name) if len(group.PreferredVersion.Version) != 0 { preferredVersion := unversioned.GroupVersion{Group: group.Name, Version: group.PreferredVersion.Version} if registered.IsEnabledVersion(preferredVersion) { resourcePriority = append(resourcePriority, preferredVersion.WithResource(meta.AnyResource)) kindPriority = append(kindPriority, preferredVersion.WithKind(meta.AnyKind)) } } for _, discoveryVersion := range group.Versions { version := unversioned.GroupVersion{Group: group.Name, Version: discoveryVersion.Version} if !registered.IsEnabledVersion(version) { continue } groupMeta, err := registered.Group(group.Name) if err != nil { return nil, err } resources, err := d.discoveryClient.ServerResourcesForGroupVersion(version.String()) if err != nil { return nil, err } versionMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{version}, groupMeta.InterfacesFor) for _, resource := range resources.APIResources { // TODO properly handle resource versus kind gvk := version.WithKind(resource.Kind) scope := meta.RESTScopeNamespace if !resource.Namespaced { scope = meta.RESTScopeRoot } versionMapper.Add(gvk, scope) // TODO formalize this by checking to see if they support listing versionMapper.Add(version.WithKind(resource.Kind+"List"), scope) } // we need to add List. Its a special case of something we need that isn't in the discovery doc if group.Name == kapi.GroupName { versionMapper.Add(version.WithKind("List"), meta.RESTScopeNamespace) } unionMapper = append(unionMapper, versionMapper) } } for _, group := range groupPriority { resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{Group: group, Version: meta.AnyVersion, Resource: meta.AnyResource}) kindPriority = append(kindPriority, unversioned.GroupVersionKind{Group: group, Version: meta.AnyVersion, Kind: meta.AnyKind}) } return meta.PriorityRESTMapper{Delegate: unionMapper, ResourcePriority: resourcePriority, KindPriority: kindPriority}, nil }
func (m *Master) initV1ResourcesStorage(c *Config) { restOptions := func(resource string) generic.RESTOptions { return m.GetRESTOptionsOrDie(c, api.Resource(resource)) } podTemplateStorage := podtemplateetcd.NewREST(restOptions("podTemplates")) eventStorage := eventetcd.NewREST(restOptions("events"), uint64(c.EventTTL.Seconds())) limitRangeStorage := limitrangeetcd.NewREST(restOptions("limitRanges")) resourceQuotaStorage, resourceQuotaStatusStorage := resourcequotaetcd.NewREST(restOptions("resourceQuotas")) secretStorage := secretetcd.NewREST(restOptions("secrets")) serviceAccountStorage := serviceaccountetcd.NewREST(restOptions("serviceAccounts")) persistentVolumeStorage, persistentVolumeStatusStorage := pvetcd.NewREST(restOptions("persistentVolumes")) persistentVolumeClaimStorage, persistentVolumeClaimStatusStorage := pvcetcd.NewREST(restOptions("persistentVolumeClaims")) configMapStorage := configmapetcd.NewREST(restOptions("configMaps")) namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewREST(restOptions("namespaces")) m.namespaceRegistry = namespace.NewRegistry(namespaceStorage) endpointsStorage := endpointsetcd.NewREST(restOptions("endpoints")) m.endpointRegistry = endpoint.NewRegistry(endpointsStorage) nodeStorage := nodeetcd.NewStorage(restOptions("nodes"), c.KubeletClient, m.ProxyTransport) m.nodeRegistry = node.NewRegistry(nodeStorage.Node) podStorage := podetcd.NewStorage( restOptions("pods"), kubeletclient.ConnectionInfoGetter(nodeStorage.Node), m.ProxyTransport, ) serviceRESTStorage, serviceStatusStorage := serviceetcd.NewREST(restOptions("services")) m.serviceRegistry = service.NewRegistry(serviceRESTStorage) var serviceClusterIPRegistry service.RangeRegistry serviceClusterIPRange := m.ServiceClusterIPRange if serviceClusterIPRange == nil { glog.Fatalf("service clusterIPRange is nil") return } serviceStorage, err := c.StorageFactory.New(api.Resource("services")) if err != nil { glog.Fatal(err.Error()) } serviceClusterIPAllocator := ipallocator.NewAllocatorCIDRRange(serviceClusterIPRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) // TODO etcdallocator package to return a storage interface via the storageFactory etcd := etcdallocator.NewEtcd(mem, "/ranges/serviceips", api.Resource("serviceipallocations"), serviceStorage) serviceClusterIPRegistry = etcd return etcd }) m.serviceClusterIPAllocator = serviceClusterIPRegistry var serviceNodePortRegistry service.RangeRegistry serviceNodePortAllocator := portallocator.NewPortAllocatorCustom(m.ServiceNodePortRange, func(max int, rangeSpec string) allocator.Interface { mem := allocator.NewAllocationMap(max, rangeSpec) // TODO etcdallocator package to return a storage interface via the storageFactory etcd := etcdallocator.NewEtcd(mem, "/ranges/servicenodeports", api.Resource("servicenodeportallocations"), serviceStorage) serviceNodePortRegistry = etcd return etcd }) m.serviceNodePortAllocator = serviceNodePortRegistry controllerStorage := controlleretcd.NewStorage(restOptions("replicationControllers")) serviceRest := service.NewStorage(m.serviceRegistry, m.endpointRegistry, serviceClusterIPAllocator, serviceNodePortAllocator, m.ProxyTransport) // TODO: Factor out the core API registration m.v1ResourcesStorage = map[string]rest.Storage{ "pods": podStorage.Pod, "pods/attach": podStorage.Attach, "pods/status": podStorage.Status, "pods/log": podStorage.Log, "pods/exec": podStorage.Exec, "pods/portforward": podStorage.PortForward, "pods/proxy": podStorage.Proxy, "pods/binding": podStorage.Binding, "bindings": podStorage.Binding, "podTemplates": podTemplateStorage, "replicationControllers": controllerStorage.Controller, "replicationControllers/status": controllerStorage.Status, "services": serviceRest.Service, "services/proxy": serviceRest.Proxy, "services/status": serviceStatusStorage, "endpoints": endpointsStorage, "nodes": nodeStorage.Node, "nodes/status": nodeStorage.Status, "nodes/proxy": nodeStorage.Proxy, "events": eventStorage, "limitRanges": limitRangeStorage, "resourceQuotas": resourceQuotaStorage, "resourceQuotas/status": resourceQuotaStatusStorage, "namespaces": namespaceStorage, "namespaces/status": namespaceStatusStorage, "namespaces/finalize": namespaceFinalizeStorage, "secrets": secretStorage, "serviceAccounts": serviceAccountStorage, "persistentVolumes": persistentVolumeStorage, "persistentVolumes/status": persistentVolumeStatusStorage, "persistentVolumeClaims": persistentVolumeClaimStorage, "persistentVolumeClaims/status": persistentVolumeClaimStatusStorage, "configMaps": configMapStorage, "componentStatuses": componentstatus.NewStorage(func() map[string]apiserver.Server { return m.getServersToValidate(c) }), } if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) { m.v1ResourcesStorage["replicationControllers/scale"] = controllerStorage.Scale } }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ "replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"), } } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) prometheus.NewGaugeFunc(prometheus.GaugeOpts{ Name: "apiserver_proxy_tunnel_sync_latency_secs", Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.", }, func() float64 { return float64(m.tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(m.MuxHelper, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/metrics", MetricsWithReset) } else { m.MuxHelper.HandleFunc("/metrics", defaultMetricsHandler) } // Install extensions unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(extensionsapiv1beta1.SchemeGroupVersion) { var err error m.thirdPartyStorage, err = c.StorageFactory.New(extensions.Resource("thirdpartyresources")) if err != nil { glog.Fatalf("Error getting third party storage: %v", err) } m.thirdPartyResources = map[string]thirdPartyEntry{} extensionResources := m.getExtensionResources(c) extensionsGroupMeta := registered.GroupOrDie(extensions.GroupName) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *extensionsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1beta1": extensionResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Install autoscaling unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(autoscalingapiv1.SchemeGroupVersion) { autoscalingResources := m.getAutoscalingResources(c) autoscalingGroupMeta := registered.GroupOrDie(autoscaling.GroupName) // Hard code preferred group version to autoscaling/v1 autoscalingGroupMeta.GroupVersion = autoscalingapiv1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *autoscalingGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": autoscalingResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Install batch unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv1.SchemeGroupVersion) || c.APIResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv2alpha1.SchemeGroupVersion) { batchv1Resources := m.getBatchResources(c, batchapiv1.SchemeGroupVersion) batchGroupMeta := registered.GroupOrDie(batch.GroupName) // Hard code preferred group version to batch/v1 batchGroupMeta.GroupVersion = batchapiv1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *batchGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": batchv1Resources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv2alpha1.SchemeGroupVersion) { batchv2alpha1Resources := m.getBatchResources(c, batchapiv2alpha1.SchemeGroupVersion) apiGroupInfo.VersionedResourcesStorageMap["v2alpha1"] = batchv2alpha1Resources } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(policyapiv1alpha1.SchemeGroupVersion) { policyResources := m.getPolicyResources(c) policyGroupMeta := registered.GroupOrDie(policy.GroupName) // Hard code preferred group version to policy/v1alpha1 policyGroupMeta.GroupVersion = policyapiv1alpha1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *policyGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": policyResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(appsapi.SchemeGroupVersion) { appsResources := m.getAppsResources(c) appsGroupMeta := registered.GroupOrDie(apps.GroupName) // Hard code preferred group version to apps/v1alpha1 appsGroupMeta.GroupVersion = appsapi.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *appsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": appsResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(certificatesapiv1alpha1.SchemeGroupVersion) { certificateResources := m.getCertificateResources(c) certificatesGroupMeta := registered.GroupOrDie(certificates.GroupName) // Hard code preferred group version to certificates/v1alpha1 certificatesGroupMeta.GroupVersion = certificatesapiv1alpha1.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *certificatesGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": certificateResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(rbacapi.SchemeGroupVersion) { rbacResources := m.getRBACResources(c) rbacGroupMeta := registered.GroupOrDie(rbac.GroupName) // Hard code preferred group version to rbac/v1alpha1 rbacGroupMeta.GroupVersion = rbacapi.SchemeGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *rbacGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1alpha1": rbacResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, SubresourceGroupVersionKind: map[string]unversioned.GroupVersionKind{}, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind["replicationcontrollers/scale"] = autoscalingGroupVersion.WithKind("Scale") } if policyGroupVersion := (unversioned.GroupVersion{Group: "policy", Version: "v1alpha1"}); registered.IsEnabledVersion(policyGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind["pods/eviction"] = policyGroupVersion.WithKind("Eviction") } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) prometheus.NewGaugeFunc(prometheus.GaugeOpts{ Name: "apiserver_proxy_tunnel_sync_latency_secs", Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.", }, func() float64 { return float64(m.tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(m.MuxHelper, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/metrics", MetricsWithReset) } else { m.MuxHelper.HandleFunc("/metrics", defaultMetricsHandler) } // Install third party resource support if requested // TODO seems like this bit ought to be unconditional and the REST API is controlled by the config if c.APIResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources")) { var err error m.thirdPartyStorageConfig, err = c.StorageFactory.NewConfig(extensions.Resource("thirdpartyresources")) if err != nil { glog.Fatalf("Error getting third party storage: %v", err) } m.thirdPartyResources = map[string]*thirdPartyEntry{} } restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions { return m.GetRESTOptionsOrDie(c, resource) } // stabilize order. // TODO find a better way to configure priority of groups for _, group := range sets.StringKeySet(c.RESTStorageProviders).List() { if !c.APIResourceConfigSource.AnyResourcesForGroupEnabled(group) { glog.V(1).Infof("Skipping disabled API group %q.", group) continue } restStorageBuilder := c.RESTStorageProviders[group] apiGroupInfo, enabled := restStorageBuilder.NewRESTStorage(c.APIResourceConfigSource, restOptionsGetter) if !enabled { glog.Warningf("Problem initializing API group %q, skipping.", group) continue } glog.V(1).Infof("Enabling API group %q.", group) // This is here so that, if the policy group is present, the eviction // subresource handler wil be able to find poddisruptionbudgets // TODO(lavalamp) find a better way for groups to discover and interact // with each other if group == "policy" { storage := apiGroupsInfo[0].VersionedResourcesStorageMap["v1"]["pods/eviction"] evictionStorage := storage.(*podetcd.EvictionREST) storage = apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"]["poddisruptionbudgets"] evictionStorage.PodDisruptionBudgetLister = storage.(rest.Lister) evictionStorage.PodDisruptionBudgetUpdater = storage.(rest.Updater) } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if c.APIResourceConfigSource.AnyResourcesForVersionEnabled(apiv1.SchemeGroupVersion) { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ "replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"), } } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) prometheus.NewGaugeFunc(prometheus.GaugeOpts{ Name: "apiserver_proxy_tunnel_sync_latency_secs", Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.", }, func() float64 { return float64(m.tunneler.SecondsSinceSync()) }) } healthz.InstallHandler(m.MuxHelper, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/metrics", MetricsWithReset) } else { m.MuxHelper.HandleFunc("/metrics", defaultMetricsHandler) } // Install third party resource support if requested // TODO seems like this bit ought to be unconditional and the REST API is controlled by the config if c.APIResourceConfigSource.ResourceEnabled(extensionsapiv1beta1.SchemeGroupVersion.WithResource("thirdpartyresources")) { var err error m.thirdPartyStorage, err = c.StorageFactory.New(extensions.Resource("thirdpartyresources")) if err != nil { glog.Fatalf("Error getting third party storage: %v", err) } m.thirdPartyResources = map[string]thirdPartyEntry{} } restOptionsGetter := func(resource unversioned.GroupResource) generic.RESTOptions { return m.GetRESTOptionsOrDie(c, resource) } // stabilize order. // TODO find a better way to configure priority of groups for _, group := range sets.StringKeySet(c.RESTStorageProviders).List() { if !c.APIResourceConfigSource.AnyResourcesForGroupEnabled(group) { continue } restStorageBuilder := c.RESTStorageProviders[group] apiGroupInfo, enabled := restStorageBuilder.NewRESTStorage(c.APIResourceConfigSource, restOptionsGetter) if !enabled { continue } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
func addVersionsToScheme(externalVersions ...unversioned.GroupVersion) { // add the internal version to Scheme api.AddToScheme(api.Scheme) // add the enabled external versions to Scheme for _, v := range externalVersions { if !registered.IsEnabledVersion(v) { glog.Errorf("Version %s is not enabled, so it will not be added to the Scheme.", v) continue } switch v { case v1.SchemeGroupVersion: v1.AddToScheme(api.Scheme) case v1beta3.SchemeGroupVersion: v1beta3.AddToScheme(api.Scheme) } } // This is a "fast-path" that avoids reflection for common types. It focuses on the objects that are // converted the most in the cluster. // TODO: generate one of these for every external API group - this is to prove the impact api.Scheme.AddGenericConversionFunc(func(objA, objB interface{}, s conversion.Scope) (bool, error) { switch a := objA.(type) { case *v1.Pod: switch b := objB.(type) { case *api.Pod: return true, v1.Convert_v1_Pod_To_api_Pod(a, b, s) } case *api.Pod: switch b := objB.(type) { case *v1.Pod: return true, v1.Convert_api_Pod_To_v1_Pod(a, b, s) } case *v1.Event: switch b := objB.(type) { case *api.Event: return true, v1.Convert_v1_Event_To_api_Event(a, b, s) } case *api.Event: switch b := objB.(type) { case *v1.Event: return true, v1.Convert_api_Event_To_v1_Event(a, b, s) } case *v1.ReplicationController: switch b := objB.(type) { case *api.ReplicationController: return true, v1.Convert_v1_ReplicationController_To_api_ReplicationController(a, b, s) } case *api.ReplicationController: switch b := objB.(type) { case *v1.ReplicationController: return true, v1.Convert_api_ReplicationController_To_v1_ReplicationController(a, b, s) } case *v1.Node: switch b := objB.(type) { case *api.Node: return true, v1.Convert_v1_Node_To_api_Node(a, b, s) } case *api.Node: switch b := objB.(type) { case *v1.Node: return true, v1.Convert_api_Node_To_v1_Node(a, b, s) } case *v1.Namespace: switch b := objB.(type) { case *api.Namespace: return true, v1.Convert_v1_Namespace_To_api_Namespace(a, b, s) } case *api.Namespace: switch b := objB.(type) { case *v1.Namespace: return true, v1.Convert_api_Namespace_To_v1_Namespace(a, b, s) } case *v1.Service: switch b := objB.(type) { case *api.Service: return true, v1.Convert_v1_Service_To_api_Service(a, b, s) } case *api.Service: switch b := objB.(type) { case *v1.Service: return true, v1.Convert_api_Service_To_v1_Service(a, b, s) } case *v1.Endpoints: switch b := objB.(type) { case *api.Endpoints: return true, v1.Convert_v1_Endpoints_To_api_Endpoints(a, b, s) } case *api.Endpoints: switch b := objB.(type) { case *v1.Endpoints: return true, v1.Convert_api_Endpoints_To_v1_Endpoints(a, b, s) } } return false, nil }) }
func (m *Master) InstallAPIs(c *Config) { apiGroupsInfo := []genericapiserver.APIGroupInfo{} // Install v1 unless disabled. if !m.ApiGroupVersionOverrides["api/v1"].Disable { // Install v1 API. m.initV1ResourcesStorage(c) apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *registered.GroupOrDie(api.GroupName), VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": m.v1ResourcesStorage, }, IsLegacyGroup: true, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } if autoscalingGroupVersion := (unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}); registered.IsEnabledVersion(autoscalingGroupVersion) { apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ "replicationcontrollers/scale": autoscalingGroupVersion.WithKind("Scale"), } } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) } // Run the tunneler. healthzChecks := []healthz.HealthzChecker{} if m.tunneler != nil { m.tunneler.Run(m.getNodeAddresses) healthzChecks = append(healthzChecks, healthz.NamedCheck("SSH Tunnel Check", m.IsTunnelSyncHealthy)) prometheus.NewGaugeFunc(prometheus.GaugeOpts{ Name: "apiserver_proxy_tunnel_sync_latency_secs", Help: "The time since the last successful synchronization of the SSH tunnels for proxy requests.", }, func() float64 { return float64(m.tunneler.SecondsSinceSync()) }) } // TODO(nikhiljindal): Refactor generic parts of support services (like /versions) to genericapiserver. apiserver.InstallSupport(m.MuxHelper, m.RootWebService, healthzChecks...) if c.EnableProfiling { m.MuxHelper.HandleFunc("/resetMetrics", resetMetrics) } // Install root web services m.HandlerContainer.Add(m.RootWebService) // allGroups records all supported groups at /apis allGroups := []unversioned.APIGroup{} // Install extensions unless disabled. if !m.ApiGroupVersionOverrides["extensions/v1beta1"].Disable { m.thirdPartyStorage = c.StorageDestinations.APIGroups[extensions.GroupName].Default m.thirdPartyResources = map[string]thirdPartyEntry{} extensionResources := m.getExtensionResources(c) extensionsGroupMeta := registered.GroupOrDie(extensions.GroupName) // Update the preferred version as per StorageVersions in the config. storageVersion, found := c.StorageVersions[extensionsGroupMeta.GroupVersion.Group] if !found { glog.Fatalf("Couldn't find storage version of group %v", extensionsGroupMeta.GroupVersion.Group) } preferedGroupVersion, err := unversioned.ParseGroupVersion(storageVersion) if err != nil { glog.Fatalf("Error in parsing group version %s: %v", storageVersion, err) } extensionsGroupMeta.GroupVersion = preferedGroupVersion apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *extensionsGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1beta1": extensionResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) extensionsGVForDiscovery := unversioned.GroupVersionForDiscovery{ GroupVersion: extensionsGroupMeta.GroupVersion.String(), Version: extensionsGroupMeta.GroupVersion.Version, } group := unversioned.APIGroup{ Name: extensionsGroupMeta.GroupVersion.Group, Versions: []unversioned.GroupVersionForDiscovery{extensionsGVForDiscovery}, PreferredVersion: extensionsGVForDiscovery, } allGroups = append(allGroups, group) } // Install autoscaling unless disabled. if !m.ApiGroupVersionOverrides["autoscaling/v1"].Disable { autoscalingResources := m.getAutoscalingResources(c) autoscalingGroupMeta := registered.GroupOrDie(autoscaling.GroupName) // Hard code preferred group version to autoscaling/v1 autoscalingGroupMeta.GroupVersion = unversioned.GroupVersion{Group: "autoscaling", Version: "v1"} apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *autoscalingGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": autoscalingResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) autoscalingGVForDiscovery := unversioned.GroupVersionForDiscovery{ GroupVersion: autoscalingGroupMeta.GroupVersion.String(), Version: autoscalingGroupMeta.GroupVersion.Version, } group := unversioned.APIGroup{ Name: autoscalingGroupMeta.GroupVersion.Group, Versions: []unversioned.GroupVersionForDiscovery{autoscalingGVForDiscovery}, PreferredVersion: autoscalingGVForDiscovery, } allGroups = append(allGroups, group) } // Install batch unless disabled. if !m.ApiGroupVersionOverrides["batch/v1"].Disable { batchResources := m.getBatchResources(c) batchGroupMeta := registered.GroupOrDie(batch.GroupName) // Hard code preferred group version to batch/v1 batchGroupMeta.GroupVersion = unversioned.GroupVersion{Group: "batch", Version: "v1"} apiGroupInfo := genericapiserver.APIGroupInfo{ GroupMeta: *batchGroupMeta, VersionedResourcesStorageMap: map[string]map[string]rest.Storage{ "v1": batchResources, }, OptionsExternalVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion, Scheme: api.Scheme, ParameterCodec: api.ParameterCodec, NegotiatedSerializer: api.Codecs, } apiGroupsInfo = append(apiGroupsInfo, apiGroupInfo) batchGVForDiscovery := unversioned.GroupVersionForDiscovery{ GroupVersion: batchGroupMeta.GroupVersion.String(), Version: batchGroupMeta.GroupVersion.Version, } group := unversioned.APIGroup{ Name: batchGroupMeta.GroupVersion.Group, Versions: []unversioned.GroupVersionForDiscovery{batchGVForDiscovery}, PreferredVersion: batchGVForDiscovery, } allGroups = append(allGroups, group) } if err := m.InstallAPIGroups(apiGroupsInfo); err != nil { glog.Fatalf("Error in registering group versions: %v", err) } }
// getExperimentalResources returns the resources for extensions api func (m *Master) getExtensionResources(c *Config) map[string]rest.Storage { // All resources except these are disabled by default. enabledResources := sets.NewString("daemonsets", "deployments", "horizontalpodautoscalers", "ingresses", "jobs", "replicasets") resourceOverrides := m.ApiGroupVersionOverrides["extensions/v1beta1"].ResourceOverrides isEnabled := func(resource string) bool { // Check if the resource has been overriden. enabled, ok := resourceOverrides[resource] if !ok { return enabledResources.Has(resource) } return enabled } restOptions := func(resource string) generic.RESTOptions { return generic.RESTOptions{ Storage: c.StorageDestinations.Get(extensions.GroupName, resource), Decorator: m.StorageDecorator(), DeleteCollectionWorkers: m.deleteCollectionWorkers, } } storage := map[string]rest.Storage{} if isEnabled("horizontalpodautoscalers") { m.constructHPAResources(c, storage) controllerStorage := expcontrolleretcd.NewStorage( generic.RESTOptions{c.StorageDestinations.Get("", "replicationControllers"), m.StorageDecorator(), m.deleteCollectionWorkers}) storage["replicationcontrollers"] = controllerStorage.ReplicationController storage["replicationcontrollers/scale"] = controllerStorage.Scale } if isEnabled("thirdpartyresources") { thirdPartyResourceStorage := thirdpartyresourceetcd.NewREST(restOptions("thirdpartyresources")) thirdPartyControl := ThirdPartyController{ master: m, thirdPartyResourceRegistry: thirdPartyResourceStorage, } go func() { wait.Forever(func() { if err := thirdPartyControl.SyncResources(); err != nil { glog.Warningf("third party resource sync failed: %v", err) } }, 10*time.Second) }() storage["thirdpartyresources"] = thirdPartyResourceStorage } if isEnabled("daemonsets") { daemonSetStorage, daemonSetStatusStorage := daemonetcd.NewREST(restOptions("daemonsets")) storage["daemonsets"] = daemonSetStorage storage["daemonsets/status"] = daemonSetStatusStorage } if isEnabled("deployments") { deploymentStorage := deploymentetcd.NewStorage(restOptions("deployments")) storage["deployments"] = deploymentStorage.Deployment storage["deployments/status"] = deploymentStorage.Status storage["deployments/rollback"] = deploymentStorage.Rollback if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) { storage["deployments/scale"] = deploymentStorage.Scale } } if isEnabled("jobs") { m.constructJobResources(c, storage) } if isEnabled("ingresses") { ingressStorage, ingressStatusStorage := ingressetcd.NewREST(restOptions("ingresses")) storage["ingresses"] = ingressStorage storage["ingresses/status"] = ingressStatusStorage } if isEnabled("podsecuritypolicy") { podSecurityPolicyStorage := pspetcd.NewREST(restOptions("podsecuritypolicy")) storage["podSecurityPolicies"] = podSecurityPolicyStorage } if isEnabled("replicasets") { replicaSetStorage := replicasetetcd.NewStorage(restOptions("replicasets")) storage["replicasets"] = replicaSetStorage.ReplicaSet storage["replicasets/status"] = replicaSetStorage.Status if registered.IsEnabledVersion(unversioned.GroupVersion{Group: "autoscaling", Version: "v1"}) { storage["replicasets/scale"] = replicaSetStorage.Scale } } return storage }