mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +00:00
add service status detection to kubernetes-discovery
This commit is contained in:
parent
d6046aab0e
commit
8f1677b7c8
@ -17,6 +17,24 @@ spec:
|
|||||||
- name: kubernetes-discovery
|
- name: kubernetes-discovery
|
||||||
image: kubernetes-discovery:latest
|
image: kubernetes-discovery:latest
|
||||||
imagePullPolicy: Never
|
imagePullPolicy: Never
|
||||||
|
livenessProbe:
|
||||||
|
failureThreshold: 3
|
||||||
|
httpGet:
|
||||||
|
path: /version
|
||||||
|
port: 443
|
||||||
|
scheme: HTTPS
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 1
|
||||||
|
readinessProbe:
|
||||||
|
failureThreshold: 3
|
||||||
|
httpGet:
|
||||||
|
path: /version
|
||||||
|
port: 443
|
||||||
|
scheme: HTTPS
|
||||||
|
periodSeconds: 10
|
||||||
|
successThreshold: 1
|
||||||
|
timeoutSeconds: 1
|
||||||
args:
|
args:
|
||||||
- "--proxy-client-cert-file=/var/run/auth-proxy-client/tls.crt"
|
- "--proxy-client-cert-file=/var/run/auth-proxy-client/tls.crt"
|
||||||
- "--proxy-client-key-file=/var/run/auth-proxy-client/tls.key"
|
- "--proxy-client-key-file=/var/run/auth-proxy-client/tls.key"
|
||||||
|
@ -34,6 +34,9 @@ go_library(
|
|||||||
"//pkg/apiserver/filters:go_default_library",
|
"//pkg/apiserver/filters:go_default_library",
|
||||||
"//pkg/auth/handlers:go_default_library",
|
"//pkg/auth/handlers:go_default_library",
|
||||||
"//pkg/client/cache:go_default_library",
|
"//pkg/client/cache:go_default_library",
|
||||||
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
|
"//pkg/client/informers/informers_generated:go_default_library",
|
||||||
|
"//pkg/client/listers/core/v1:go_default_library",
|
||||||
"//pkg/client/restclient:go_default_library",
|
"//pkg/client/restclient:go_default_library",
|
||||||
"//pkg/client/transport:go_default_library",
|
"//pkg/client/transport:go_default_library",
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
@ -64,10 +67,12 @@ go_test(
|
|||||||
"//cmd/kubernetes-discovery/pkg/apis/apiregistration:go_default_library",
|
"//cmd/kubernetes-discovery/pkg/apis/apiregistration:go_default_library",
|
||||||
"//cmd/kubernetes-discovery/pkg/client/listers/apiregistration/internalversion:go_default_library",
|
"//cmd/kubernetes-discovery/pkg/client/listers/apiregistration/internalversion:go_default_library",
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
|
"//pkg/api/v1:go_default_library",
|
||||||
"//pkg/apis/meta/v1:go_default_library",
|
"//pkg/apis/meta/v1:go_default_library",
|
||||||
"//pkg/apiserver/request:go_default_library",
|
"//pkg/apiserver/request:go_default_library",
|
||||||
"//pkg/auth/user:go_default_library",
|
"//pkg/auth/user:go_default_library",
|
||||||
"//pkg/client/cache:go_default_library",
|
"//pkg/client/cache:go_default_library",
|
||||||
|
"//pkg/client/listers/core/v1:go_default_library",
|
||||||
"//pkg/runtime:go_default_library",
|
"//pkg/runtime:go_default_library",
|
||||||
"//pkg/util/diff:go_default_library",
|
"//pkg/util/diff:go_default_library",
|
||||||
"//pkg/util/sets:go_default_library",
|
"//pkg/util/sets:go_default_library",
|
||||||
|
@ -25,6 +25,9 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/api/rest"
|
"k8s.io/kubernetes/pkg/api/rest"
|
||||||
apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
|
apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
|
||||||
authhandlers "k8s.io/kubernetes/pkg/auth/handlers"
|
authhandlers "k8s.io/kubernetes/pkg/auth/handlers"
|
||||||
|
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
|
kubeinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated"
|
||||||
|
v1listers "k8s.io/kubernetes/pkg/client/listers/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
|
genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
|
||||||
"k8s.io/kubernetes/pkg/registry/generic"
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
@ -33,7 +36,7 @@ import (
|
|||||||
|
|
||||||
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apis/apiregistration"
|
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apis/apiregistration"
|
||||||
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apis/apiregistration/v1alpha1"
|
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apis/apiregistration/v1alpha1"
|
||||||
clientset "k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/clientset_generated/clientset"
|
discoveryclientset "k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/clientset_generated/clientset"
|
||||||
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/informers"
|
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/informers"
|
||||||
listers "k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/listers/apiregistration/internalversion"
|
listers "k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/listers/apiregistration/internalversion"
|
||||||
@ -44,7 +47,8 @@ import (
|
|||||||
const legacyAPIServiceName = "v1."
|
const legacyAPIServiceName = "v1."
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
GenericConfig *genericapiserver.Config
|
GenericConfig *genericapiserver.Config
|
||||||
|
CoreAPIServerClient kubeclientset.Interface
|
||||||
|
|
||||||
// ProxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
|
// ProxyClientCert/Key are the client cert used to identify this proxy. Backing APIServices use
|
||||||
// this to confirm the proxy's identity
|
// this to confirm the proxy's identity
|
||||||
@ -73,6 +77,11 @@ type APIDiscoveryServer struct {
|
|||||||
// controller state
|
// controller state
|
||||||
lister listers.APIServiceLister
|
lister listers.APIServiceLister
|
||||||
|
|
||||||
|
// serviceLister is used by the discovery handler to determine whether or not to try to expose the group
|
||||||
|
serviceLister v1listers.ServiceLister
|
||||||
|
// endpointsLister is used by the discovery handler to determine whether or not to try to expose the group
|
||||||
|
endpointsLister v1listers.EndpointsLister
|
||||||
|
|
||||||
// proxyMux intercepts requests that need to be proxied to backing API servers
|
// proxyMux intercepts requests that need to be proxied to backing API servers
|
||||||
proxyMux *http.ServeMux
|
proxyMux *http.ServeMux
|
||||||
}
|
}
|
||||||
@ -100,16 +109,19 @@ func (c *Config) SkipComplete() completedConfig {
|
|||||||
func (c completedConfig) New() (*APIDiscoveryServer, error) {
|
func (c completedConfig) New() (*APIDiscoveryServer, error) {
|
||||||
informerFactory := informers.NewSharedInformerFactory(
|
informerFactory := informers.NewSharedInformerFactory(
|
||||||
internalclientset.NewForConfigOrDie(c.Config.GenericConfig.LoopbackClientConfig),
|
internalclientset.NewForConfigOrDie(c.Config.GenericConfig.LoopbackClientConfig),
|
||||||
clientset.NewForConfigOrDie(c.Config.GenericConfig.LoopbackClientConfig),
|
discoveryclientset.NewForConfigOrDie(c.Config.GenericConfig.LoopbackClientConfig),
|
||||||
5*time.Minute, // this is effectively used as a refresh interval right now. Might want to do something nicer later on.
|
5*time.Minute, // this is effectively used as a refresh interval right now. Might want to do something nicer later on.
|
||||||
)
|
)
|
||||||
|
kubeInformers := kubeinformers.NewSharedInformerFactory(nil, c.CoreAPIServerClient, 5*time.Minute)
|
||||||
|
|
||||||
proxyMux := http.NewServeMux()
|
proxyMux := http.NewServeMux()
|
||||||
|
|
||||||
// most API servers don't need to do this, but we need a custom handler chain to handle the special /apis handling here
|
// most API servers don't need to do this, but we need a custom handler chain to handle the special /apis handling here
|
||||||
c.Config.GenericConfig.BuildHandlerChainsFunc = (&handlerChainConfig{
|
c.Config.GenericConfig.BuildHandlerChainsFunc = (&handlerChainConfig{
|
||||||
informers: informerFactory,
|
informers: informerFactory,
|
||||||
proxyMux: proxyMux,
|
proxyMux: proxyMux,
|
||||||
|
serviceLister: kubeInformers.Core().V1().Services().Lister(),
|
||||||
|
endpointsLister: kubeInformers.Core().V1().Endpoints().Lister(),
|
||||||
}).handlerChain
|
}).handlerChain
|
||||||
|
|
||||||
genericServer, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time
|
genericServer, err := c.Config.GenericConfig.SkipComplete().New() // completion is done in Complete, no need for a second time
|
||||||
@ -124,6 +136,8 @@ func (c completedConfig) New() (*APIDiscoveryServer, error) {
|
|||||||
proxyClientKey: c.ProxyClientKey,
|
proxyClientKey: c.ProxyClientKey,
|
||||||
proxyHandlers: map[string]*proxyHandler{},
|
proxyHandlers: map[string]*proxyHandler{},
|
||||||
lister: informerFactory.Apiregistration().InternalVersion().APIServices().Lister(),
|
lister: informerFactory.Apiregistration().InternalVersion().APIServices().Lister(),
|
||||||
|
serviceLister: kubeInformers.Core().V1().Services().Lister(),
|
||||||
|
endpointsLister: kubeInformers.Core().V1().Endpoints().Lister(),
|
||||||
proxyMux: proxyMux,
|
proxyMux: proxyMux,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,6 +155,7 @@ func (c completedConfig) New() (*APIDiscoveryServer, error) {
|
|||||||
|
|
||||||
s.GenericAPIServer.AddPostStartHook("start-informers", func(context genericapiserver.PostStartHookContext) error {
|
s.GenericAPIServer.AddPostStartHook("start-informers", func(context genericapiserver.PostStartHookContext) error {
|
||||||
informerFactory.Start(wait.NeverStop)
|
informerFactory.Start(wait.NeverStop)
|
||||||
|
kubeInformers.Start(wait.NeverStop)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
s.GenericAPIServer.AddPostStartHook("apiservice-registration-controller", func(context genericapiserver.PostStartHookContext) error {
|
s.GenericAPIServer.AddPostStartHook("apiservice-registration-controller", func(context genericapiserver.PostStartHookContext) error {
|
||||||
@ -153,8 +168,10 @@ func (c completedConfig) New() (*APIDiscoveryServer, error) {
|
|||||||
|
|
||||||
// handlerChainConfig is the config used to build the custom handler chain for this api server
|
// handlerChainConfig is the config used to build the custom handler chain for this api server
|
||||||
type handlerChainConfig struct {
|
type handlerChainConfig struct {
|
||||||
informers informers.SharedInformerFactory
|
informers informers.SharedInformerFactory
|
||||||
proxyMux *http.ServeMux
|
proxyMux *http.ServeMux
|
||||||
|
serviceLister v1listers.ServiceLister
|
||||||
|
endpointsLister v1listers.EndpointsLister
|
||||||
}
|
}
|
||||||
|
|
||||||
// handlerChain is a method to build the handler chain for this API server. We need a custom handler chain so that we
|
// handlerChain is a method to build the handler chain for this API server. We need a custom handler chain so that we
|
||||||
@ -162,7 +179,7 @@ type handlerChainConfig struct {
|
|||||||
// the endpoints differently, since we're proxying all groups except for apiregistration.k8s.io.
|
// the endpoints differently, since we're proxying all groups except for apiregistration.k8s.io.
|
||||||
func (h *handlerChainConfig) handlerChain(apiHandler http.Handler, c *genericapiserver.Config) (secure, insecure http.Handler) {
|
func (h *handlerChainConfig) handlerChain(apiHandler http.Handler, c *genericapiserver.Config) (secure, insecure http.Handler) {
|
||||||
// add this as a filter so that we never collide with "already registered" failures on `/apis`
|
// add this as a filter so that we never collide with "already registered" failures on `/apis`
|
||||||
handler := WithAPIs(apiHandler, h.informers.Apiregistration().InternalVersion().APIServices())
|
handler := WithAPIs(apiHandler, h.informers.Apiregistration().InternalVersion().APIServices(), h.serviceLister, h.endpointsLister)
|
||||||
|
|
||||||
handler = apiserverfilters.WithAuthorization(handler, c.RequestContextMapper, c.Authorizer)
|
handler = apiserverfilters.WithAuthorization(handler, c.RequestContextMapper, c.Authorizer)
|
||||||
|
|
||||||
@ -223,8 +240,10 @@ func (s *APIDiscoveryServer) AddAPIService(apiService *apiregistration.APIServic
|
|||||||
// it's time to register the group discovery endpoint
|
// it's time to register the group discovery endpoint
|
||||||
groupPath := "/apis/" + apiService.Spec.Group
|
groupPath := "/apis/" + apiService.Spec.Group
|
||||||
groupDiscoveryHandler := &apiGroupHandler{
|
groupDiscoveryHandler := &apiGroupHandler{
|
||||||
groupName: apiService.Spec.Group,
|
groupName: apiService.Spec.Group,
|
||||||
lister: s.lister,
|
lister: s.lister,
|
||||||
|
serviceLister: s.serviceLister,
|
||||||
|
endpointsLister: s.endpointsLister,
|
||||||
}
|
}
|
||||||
// discovery is protected
|
// discovery is protected
|
||||||
s.GenericAPIServer.HandlerContainer.UnlistedRoutes.Handle(groupPath, groupDiscoveryHandler)
|
s.GenericAPIServer.HandlerContainer.UnlistedRoutes.Handle(groupPath, groupDiscoveryHandler)
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||||
"k8s.io/kubernetes/pkg/apiserver"
|
"k8s.io/kubernetes/pkg/apiserver"
|
||||||
|
v1listers "k8s.io/kubernetes/pkg/client/listers/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/labels"
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
|
||||||
@ -34,10 +35,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// WithAPIs adds the handling for /apis and /apis/<group: -apiregistration.k8s.io>.
|
// WithAPIs adds the handling for /apis and /apis/<group: -apiregistration.k8s.io>.
|
||||||
func WithAPIs(handler http.Handler, informer informers.APIServiceInformer) http.Handler {
|
func WithAPIs(handler http.Handler, informer informers.APIServiceInformer, serviceLister v1listers.ServiceLister, endpointsLister v1listers.EndpointsLister) http.Handler {
|
||||||
apisHandler := &apisHandler{
|
apisHandler := &apisHandler{
|
||||||
lister: informer.Lister(),
|
lister: informer.Lister(),
|
||||||
delegate: handler,
|
delegate: handler,
|
||||||
|
serviceLister: serviceLister,
|
||||||
|
endpointsLister: endpointsLister,
|
||||||
}
|
}
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||||
apisHandler.ServeHTTP(w, req)
|
apisHandler.ServeHTTP(w, req)
|
||||||
@ -49,6 +52,9 @@ func WithAPIs(handler http.Handler, informer informers.APIServiceInformer) http.
|
|||||||
type apisHandler struct {
|
type apisHandler struct {
|
||||||
lister listers.APIServiceLister
|
lister listers.APIServiceLister
|
||||||
|
|
||||||
|
serviceLister v1listers.ServiceLister
|
||||||
|
endpointsLister v1listers.EndpointsLister
|
||||||
|
|
||||||
delegate http.Handler
|
delegate http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +101,10 @@ func (r *apisHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
if len(apiGroupServers[0].Spec.Group) == 0 {
|
if len(apiGroupServers[0].Spec.Group) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
discoveryGroupList.Groups = append(discoveryGroupList.Groups, *newDiscoveryAPIGroup(apiGroupServers))
|
discoveryGroup := convertToDiscoveryAPIGroup(apiGroupServers, r.serviceLister, r.endpointsLister)
|
||||||
|
if discoveryGroup != nil {
|
||||||
|
discoveryGroupList.Groups = append(discoveryGroupList.Groups, *discoveryGroup)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
json, err := runtime.Encode(api.Codecs.LegacyCodec(), discoveryGroupList)
|
json, err := runtime.Encode(api.Codecs.LegacyCodec(), discoveryGroupList)
|
||||||
@ -108,18 +117,46 @@ func (r *apisHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDiscoveryAPIGroup(apiServices []*apiregistrationapi.APIService) *metav1.APIGroup {
|
// convertToDiscoveryAPIGroup takes apiservices in a single group and returns a discovery compatible object.
|
||||||
|
// if none of the services are available, it will return nil.
|
||||||
|
func convertToDiscoveryAPIGroup(apiServices []*apiregistrationapi.APIService, serviceLister v1listers.ServiceLister, endpointsLister v1listers.EndpointsLister) *metav1.APIGroup {
|
||||||
apiServicesByGroup := apiregistrationapi.SortedByGroup(apiServices)[0]
|
apiServicesByGroup := apiregistrationapi.SortedByGroup(apiServices)[0]
|
||||||
|
|
||||||
discoveryGroup := &metav1.APIGroup{
|
var discoveryGroup *metav1.APIGroup
|
||||||
Name: apiServicesByGroup[0].Spec.Group,
|
|
||||||
PreferredVersion: metav1.GroupVersionForDiscovery{
|
|
||||||
GroupVersion: apiServicesByGroup[0].Spec.Group + "/" + apiServicesByGroup[0].Spec.Version,
|
|
||||||
Version: apiServicesByGroup[0].Spec.Version,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, apiService := range apiServicesByGroup {
|
for _, apiService := range apiServicesByGroup {
|
||||||
|
// skip any API services without actual services
|
||||||
|
if _, err := serviceLister.Services(apiService.Spec.Service.Namespace).Get(apiService.Spec.Service.Name); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hasActiveEndpoints := false
|
||||||
|
endpoints, err := endpointsLister.Endpoints(apiService.Spec.Service.Namespace).Get(apiService.Spec.Service.Name)
|
||||||
|
// skip any API services without endpoints
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, subset := range endpoints.Subsets {
|
||||||
|
if len(subset.Addresses) > 0 {
|
||||||
|
hasActiveEndpoints = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasActiveEndpoints {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// the first APIService which is valid becomes the default
|
||||||
|
if discoveryGroup == nil {
|
||||||
|
discoveryGroup = &metav1.APIGroup{
|
||||||
|
Name: apiService.Spec.Group,
|
||||||
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
|
||||||
|
Version: apiService.Spec.Version,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
discoveryGroup.Versions = append(discoveryGroup.Versions,
|
discoveryGroup.Versions = append(discoveryGroup.Versions,
|
||||||
metav1.GroupVersionForDiscovery{
|
metav1.GroupVersionForDiscovery{
|
||||||
GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
|
GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
|
||||||
@ -136,6 +173,9 @@ type apiGroupHandler struct {
|
|||||||
groupName string
|
groupName string
|
||||||
|
|
||||||
lister listers.APIServiceLister
|
lister listers.APIServiceLister
|
||||||
|
|
||||||
|
serviceLister v1listers.ServiceLister
|
||||||
|
endpointsLister v1listers.EndpointsLister
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *apiGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (r *apiGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
@ -167,7 +207,12 @@ func (r *apiGroupHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
json, err := runtime.Encode(api.Codecs.LegacyCodec(), newDiscoveryAPIGroup(apiServicesForGroup))
|
discoveryGroup := convertToDiscoveryAPIGroup(apiServicesForGroup, r.serviceLister, r.endpointsLister)
|
||||||
|
if discoveryGroup == nil {
|
||||||
|
http.Error(w, "", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
json, err := runtime.Encode(api.Codecs.LegacyCodec(), discoveryGroup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
@ -24,8 +24,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
corev1 "k8s.io/kubernetes/pkg/api/v1"
|
||||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/cache"
|
"k8s.io/kubernetes/pkg/client/cache"
|
||||||
|
v1listers "k8s.io/kubernetes/pkg/client/listers/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/diff"
|
"k8s.io/kubernetes/pkg/util/diff"
|
||||||
|
|
||||||
@ -111,6 +113,10 @@ func TestAPIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "foo",
|
Group: "foo",
|
||||||
Version: "v1",
|
Version: "v1",
|
||||||
Priority: 10,
|
Priority: 10,
|
||||||
@ -119,6 +125,10 @@ func TestAPIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "bar",
|
Group: "bar",
|
||||||
Version: "v1",
|
Version: "v1",
|
||||||
Priority: 11,
|
Priority: 11,
|
||||||
@ -164,6 +174,10 @@ func TestAPIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "foo",
|
Group: "foo",
|
||||||
Version: "v1",
|
Version: "v1",
|
||||||
Priority: 20,
|
Priority: 20,
|
||||||
@ -172,6 +186,10 @@ func TestAPIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v2.bar"},
|
ObjectMeta: api.ObjectMeta{Name: "v2.bar"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "bar",
|
Group: "bar",
|
||||||
Version: "v2",
|
Version: "v2",
|
||||||
Priority: 11,
|
Priority: 11,
|
||||||
@ -180,6 +198,10 @@ func TestAPIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v2.foo"},
|
ObjectMeta: api.ObjectMeta{Name: "v2.foo"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "foo",
|
Group: "foo",
|
||||||
Version: "v2",
|
Version: "v2",
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
@ -188,6 +210,10 @@ func TestAPIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "bar",
|
Group: "bar",
|
||||||
Version: "v1",
|
Version: "v1",
|
||||||
Priority: 11,
|
Priority: 11,
|
||||||
@ -239,14 +265,26 @@ func TestAPIs(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||||
|
serviceIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||||
|
endpointsIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||||
delegate := &delegationHTTPHandler{}
|
delegate := &delegationHTTPHandler{}
|
||||||
handler := &apisHandler{
|
handler := &apisHandler{
|
||||||
lister: listers.NewAPIServiceLister(indexer),
|
serviceLister: v1listers.NewServiceLister(serviceIndexer),
|
||||||
delegate: delegate,
|
endpointsLister: v1listers.NewEndpointsLister(endpointsIndexer),
|
||||||
|
lister: listers.NewAPIServiceLister(indexer),
|
||||||
|
delegate: delegate,
|
||||||
}
|
}
|
||||||
for _, o := range tc.apiservices {
|
for _, o := range tc.apiservices {
|
||||||
indexer.Add(o)
|
indexer.Add(o)
|
||||||
}
|
}
|
||||||
|
serviceIndexer.Add(&corev1.Service{ObjectMeta: corev1.ObjectMeta{Namespace: "ns", Name: "api"}})
|
||||||
|
endpointsIndexer.Add(&corev1.Endpoints{
|
||||||
|
ObjectMeta: corev1.ObjectMeta{Namespace: "ns", Name: "api"},
|
||||||
|
Subsets: []corev1.EndpointSubset{
|
||||||
|
{Addresses: []corev1.EndpointAddress{{}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
@ -316,6 +354,10 @@ func TestAPIGroup(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "foo",
|
Group: "foo",
|
||||||
Version: "v1",
|
Version: "v1",
|
||||||
Priority: 20,
|
Priority: 20,
|
||||||
@ -324,6 +366,10 @@ func TestAPIGroup(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v2.bar"},
|
ObjectMeta: api.ObjectMeta{Name: "v2.bar"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "bar",
|
Group: "bar",
|
||||||
Version: "v2",
|
Version: "v2",
|
||||||
Priority: 11,
|
Priority: 11,
|
||||||
@ -332,6 +378,10 @@ func TestAPIGroup(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v2.foo"},
|
ObjectMeta: api.ObjectMeta{Name: "v2.foo"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "foo",
|
Group: "foo",
|
||||||
Version: "v2",
|
Version: "v2",
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
@ -340,6 +390,10 @@ func TestAPIGroup(t *testing.T) {
|
|||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
||||||
Spec: apiregistration.APIServiceSpec{
|
Spec: apiregistration.APIServiceSpec{
|
||||||
|
Service: apiregistration.ServiceReference{
|
||||||
|
Namespace: "ns",
|
||||||
|
Name: "api",
|
||||||
|
},
|
||||||
Group: "bar",
|
Group: "bar",
|
||||||
Version: "v1",
|
Version: "v1",
|
||||||
Priority: 11,
|
Priority: 11,
|
||||||
@ -369,13 +423,25 @@ func TestAPIGroup(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||||
|
serviceIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||||
|
endpointsIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc})
|
||||||
handler := &apiGroupHandler{
|
handler := &apiGroupHandler{
|
||||||
lister: listers.NewAPIServiceLister(indexer),
|
lister: listers.NewAPIServiceLister(indexer),
|
||||||
groupName: "foo",
|
serviceLister: v1listers.NewServiceLister(serviceIndexer),
|
||||||
|
endpointsLister: v1listers.NewEndpointsLister(endpointsIndexer),
|
||||||
|
groupName: "foo",
|
||||||
}
|
}
|
||||||
for _, o := range tc.apiservices {
|
for _, o := range tc.apiservices {
|
||||||
indexer.Add(o)
|
indexer.Add(o)
|
||||||
}
|
}
|
||||||
|
serviceIndexer.Add(&corev1.Service{ObjectMeta: corev1.ObjectMeta{Namespace: "ns", Name: "api"}})
|
||||||
|
endpointsIndexer.Add(&corev1.Endpoints{
|
||||||
|
ObjectMeta: corev1.ObjectMeta{Namespace: "ns", Name: "api"},
|
||||||
|
Subsets: []corev1.EndpointSubset{
|
||||||
|
{Addresses: []corev1.EndpointAddress{{}}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
server := httptest.NewServer(handler)
|
server := httptest.NewServer(handler)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
@ -386,8 +452,8 @@ func TestAPIGroup(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
httputil.DumpResponse(resp, true)
|
response, _ := httputil.DumpResponse(resp, true)
|
||||||
t.Errorf("%s", tc.name)
|
t.Errorf("%s: %v", tc.name, string(response))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
bytes, err := ioutil.ReadAll(resp.Body)
|
bytes, err := ioutil.ReadAll(resp.Body)
|
||||||
|
@ -16,6 +16,8 @@ go_library(
|
|||||||
"//cmd/kubernetes-discovery/pkg/apiserver:go_default_library",
|
"//cmd/kubernetes-discovery/pkg/apiserver:go_default_library",
|
||||||
"//cmd/kubernetes-discovery/pkg/legacy:go_default_library",
|
"//cmd/kubernetes-discovery/pkg/legacy:go_default_library",
|
||||||
"//pkg/api:go_default_library",
|
"//pkg/api:go_default_library",
|
||||||
|
"//pkg/client/clientset_generated/clientset:go_default_library",
|
||||||
|
"//pkg/client/restclient:go_default_library",
|
||||||
"//pkg/genericapiserver:go_default_library",
|
"//pkg/genericapiserver:go_default_library",
|
||||||
"//pkg/genericapiserver/filters:go_default_library",
|
"//pkg/genericapiserver/filters:go_default_library",
|
||||||
"//pkg/genericapiserver/options:go_default_library",
|
"//pkg/genericapiserver/options:go_default_library",
|
||||||
|
@ -27,6 +27,8 @@ import (
|
|||||||
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apiserver"
|
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apiserver"
|
||||||
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/legacy"
|
"k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/legacy"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
kubeclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
|
||||||
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver"
|
"k8s.io/kubernetes/pkg/genericapiserver"
|
||||||
"k8s.io/kubernetes/pkg/genericapiserver/filters"
|
"k8s.io/kubernetes/pkg/genericapiserver/filters"
|
||||||
genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
|
genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
|
||||||
@ -135,9 +137,19 @@ func (o DiscoveryServerOptions) RunDiscoveryServer() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kubeconfig, err := restclient.InClusterConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
coreAPIServerClient, err := kubeclientset.NewForConfig(kubeconfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
config := apiserver.Config{
|
config := apiserver.Config{
|
||||||
GenericConfig: genericAPIServerConfig,
|
GenericConfig: genericAPIServerConfig,
|
||||||
RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.Etcd.StorageConfig},
|
RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.Etcd.StorageConfig},
|
||||||
|
CoreAPIServerClient: coreAPIServerClient,
|
||||||
}
|
}
|
||||||
|
|
||||||
config.ProxyClientCert, err = ioutil.ReadFile(o.ProxyClientCertFile)
|
config.ProxyClientCert, err = ioutil.ReadFile(o.ProxyClientCertFile)
|
||||||
|
@ -59,7 +59,9 @@ function start_discovery {
|
|||||||
|
|
||||||
# grant permission to run delegated authentication and authorization checks
|
# grant permission to run delegated authentication and authorization checks
|
||||||
kubectl_core delete clusterrolebinding discovery:system:auth-delegator > /dev/null 2>&1 || true
|
kubectl_core delete clusterrolebinding discovery:system:auth-delegator > /dev/null 2>&1 || true
|
||||||
|
kubectl_core delete clusterrolebinding discovery:system:kubernetes-discovery > /dev/null 2>&1 || true
|
||||||
kubectl_core create clusterrolebinding discovery:system:auth-delegator --clusterrole=system:auth-delegator --serviceaccount=kube-public:kubernetes-discovery
|
kubectl_core create clusterrolebinding discovery:system:auth-delegator --clusterrole=system:auth-delegator --serviceaccount=kube-public:kubernetes-discovery
|
||||||
|
kubectl_core create clusterrolebinding discovery:system:kubernetes-discovery --clusterrole=system:kubernetes-discovery --serviceaccount=kube-public:kubernetes-discovery
|
||||||
|
|
||||||
# make sure the resources we're about to create don't exist
|
# make sure the resources we're about to create don't exist
|
||||||
kubectl_core -n kube-public delete secret auth-proxy-client serving-etcd serving-discovery discovery-etcd > /dev/null 2>&1 || true
|
kubectl_core -n kube-public delete secret auth-proxy-client serving-etcd serving-discovery discovery-etcd > /dev/null 2>&1 || true
|
||||||
|
@ -230,6 +230,14 @@ func ClusterRoles() []rbac.ClusterRole {
|
|||||||
rbac.NewRule("create").Groups(authorizationGroup).Resources("subjectaccessreviews").RuleOrDie(),
|
rbac.NewRule("create").Groups(authorizationGroup).Resources("subjectaccessreviews").RuleOrDie(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// a role to use for the API registry, summarization, and proxy handling
|
||||||
|
ObjectMeta: api.ObjectMeta{Name: "system:kubernetes-discovery"},
|
||||||
|
Rules: []rbac.PolicyRule{
|
||||||
|
// it needs to see all services so that it knows whether the ones it points to exist or not
|
||||||
|
rbac.NewRule(Read...).Groups(legacyGroup).Resources("services", "endpoints").RuleOrDie(),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
// a role to use for bootstrapping the kube-controller-manager so it can create the shared informers
|
// a role to use for bootstrapping the kube-controller-manager so it can create the shared informers
|
||||||
// service accounts, and secrets that we need to create separate identities for other controllers
|
// service accounts, and secrets that we need to create separate identities for other controllers
|
||||||
|
@ -469,6 +469,24 @@ items:
|
|||||||
verbs:
|
verbs:
|
||||||
- list
|
- list
|
||||||
- watch
|
- watch
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1alpha1
|
||||||
|
kind: ClusterRole
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
kubernetes.io/bootstrapping: rbac-defaults
|
||||||
|
name: system:kubernetes-discovery
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
attributeRestrictions: null
|
||||||
|
resources:
|
||||||
|
- endpoints
|
||||||
|
- services
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
- apiVersion: rbac.authorization.k8s.io/v1alpha1
|
- apiVersion: rbac.authorization.k8s.io/v1alpha1
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
metadata:
|
metadata:
|
||||||
|
Loading…
Reference in New Issue
Block a user