...

Source file src/k8s.io/kube-aggregator/pkg/apiserver/handler_apis.go

Documentation: k8s.io/kube-aggregator/pkg/apiserver

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package apiserver
    18  
    19  import (
    20  	"net/http"
    21  
    22  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/labels"
    25  	"k8s.io/apimachinery/pkg/runtime/schema"
    26  	"k8s.io/apimachinery/pkg/runtime/serializer"
    27  	"k8s.io/apimachinery/pkg/util/sets"
    28  	"k8s.io/apiserver/pkg/endpoints/handlers/negotiation"
    29  	"k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
    30  
    31  	apiregistrationv1api "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
    32  	apiregistrationv1apihelper "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1/helper"
    33  	apiregistrationv1beta1api "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1"
    34  	listers "k8s.io/kube-aggregator/pkg/client/listers/apiregistration/v1"
    35  )
    36  
    37  // apisHandler serves the `/apis` endpoint.
    38  // This is registered as a filter so that it never collides with any explicitly registered endpoints
    39  type apisHandler struct {
    40  	codecs         serializer.CodecFactory
    41  	lister         listers.APIServiceLister
    42  	discoveryGroup metav1.APIGroup
    43  }
    44  
    45  func discoveryGroup(enabledVersions sets.String) metav1.APIGroup {
    46  	retval := metav1.APIGroup{
    47  		Name: apiregistrationv1api.GroupName,
    48  		Versions: []metav1.GroupVersionForDiscovery{
    49  			{
    50  				GroupVersion: apiregistrationv1api.SchemeGroupVersion.String(),
    51  				Version:      apiregistrationv1api.SchemeGroupVersion.Version,
    52  			},
    53  		},
    54  		PreferredVersion: metav1.GroupVersionForDiscovery{
    55  			GroupVersion: apiregistrationv1api.SchemeGroupVersion.String(),
    56  			Version:      apiregistrationv1api.SchemeGroupVersion.Version,
    57  		},
    58  	}
    59  
    60  	if enabledVersions.Has(apiregistrationv1beta1api.SchemeGroupVersion.Version) {
    61  		retval.Versions = append(retval.Versions, metav1.GroupVersionForDiscovery{
    62  			GroupVersion: apiregistrationv1beta1api.SchemeGroupVersion.String(),
    63  			Version:      apiregistrationv1beta1api.SchemeGroupVersion.Version,
    64  		})
    65  	}
    66  
    67  	return retval
    68  }
    69  
    70  func (r *apisHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    71  	discoveryGroupList := &metav1.APIGroupList{
    72  		// always add OUR api group to the list first.  Since we'll never have a registered APIService for it
    73  		// and since this is the crux of the API, having this first will give our names priority.  It's good to be king.
    74  		Groups: []metav1.APIGroup{r.discoveryGroup},
    75  	}
    76  
    77  	apiServices, err := r.lister.List(labels.Everything())
    78  	if err != nil {
    79  		http.Error(w, err.Error(), http.StatusInternalServerError)
    80  		return
    81  	}
    82  	apiServicesByGroup := apiregistrationv1apihelper.SortedByGroupAndVersion(apiServices)
    83  	for _, apiGroupServers := range apiServicesByGroup {
    84  		// skip the legacy group
    85  		if len(apiGroupServers[0].Spec.Group) == 0 {
    86  			continue
    87  		}
    88  		discoveryGroup := convertToDiscoveryAPIGroup(apiGroupServers)
    89  		if discoveryGroup != nil {
    90  			discoveryGroupList.Groups = append(discoveryGroupList.Groups, *discoveryGroup)
    91  		}
    92  	}
    93  
    94  	responsewriters.WriteObjectNegotiated(r.codecs, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, w, req, http.StatusOK, discoveryGroupList, false)
    95  }
    96  
    97  // convertToDiscoveryAPIGroup takes apiservices in a single group and returns a discovery compatible object.
    98  // if none of the services are available, it will return nil.
    99  func convertToDiscoveryAPIGroup(apiServices []*apiregistrationv1api.APIService) *metav1.APIGroup {
   100  	apiServicesByGroup := apiregistrationv1apihelper.SortedByGroupAndVersion(apiServices)[0]
   101  
   102  	var discoveryGroup *metav1.APIGroup
   103  
   104  	for _, apiService := range apiServicesByGroup {
   105  		// the first APIService which is valid becomes the default
   106  		if discoveryGroup == nil {
   107  			discoveryGroup = &metav1.APIGroup{
   108  				Name: apiService.Spec.Group,
   109  				PreferredVersion: metav1.GroupVersionForDiscovery{
   110  					GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
   111  					Version:      apiService.Spec.Version,
   112  				},
   113  			}
   114  		}
   115  
   116  		discoveryGroup.Versions = append(discoveryGroup.Versions,
   117  			metav1.GroupVersionForDiscovery{
   118  				GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
   119  				Version:      apiService.Spec.Version,
   120  			},
   121  		)
   122  	}
   123  
   124  	return discoveryGroup
   125  }
   126  
   127  // apiGroupHandler serves the `/apis/<group>` endpoint.
   128  type apiGroupHandler struct {
   129  	codecs    serializer.CodecFactory
   130  	groupName string
   131  
   132  	lister listers.APIServiceLister
   133  
   134  	delegate http.Handler
   135  }
   136  
   137  func (r *apiGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   138  	apiServices, err := r.lister.List(labels.Everything())
   139  	if statusErr, ok := err.(*apierrors.StatusError); ok {
   140  		responsewriters.WriteRawJSON(int(statusErr.Status().Code), statusErr.Status(), w)
   141  		return
   142  	}
   143  	if err != nil {
   144  		http.Error(w, err.Error(), http.StatusInternalServerError)
   145  		return
   146  	}
   147  
   148  	apiServicesForGroup := []*apiregistrationv1api.APIService{}
   149  	for _, apiService := range apiServices {
   150  		if apiService.Spec.Group == r.groupName {
   151  			apiServicesForGroup = append(apiServicesForGroup, apiService)
   152  		}
   153  	}
   154  
   155  	if len(apiServicesForGroup) == 0 {
   156  		r.delegate.ServeHTTP(w, req)
   157  		return
   158  	}
   159  
   160  	discoveryGroup := convertToDiscoveryAPIGroup(apiServicesForGroup)
   161  	if discoveryGroup == nil {
   162  		http.Error(w, "", http.StatusNotFound)
   163  		return
   164  	}
   165  	responsewriters.WriteObjectNegotiated(r.codecs, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, w, req, http.StatusOK, discoveryGroup, false)
   166  }
   167  

View as plain text