mirror of https://github.com/k3s-io/k3s
add service status detection to kubernetes-discovery
parent
d6046aab0e
commit
8f1677b7c8
|
@ -17,6 +17,24 @@ spec:
|
|||
- name: kubernetes-discovery
|
||||
image: kubernetes-discovery:latest
|
||||
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:
|
||||
- "--proxy-client-cert-file=/var/run/auth-proxy-client/tls.crt"
|
||||
- "--proxy-client-key-file=/var/run/auth-proxy-client/tls.key"
|
||||
|
|
|
@ -34,6 +34,9 @@ go_library(
|
|||
"//pkg/apiserver/filters:go_default_library",
|
||||
"//pkg/auth/handlers: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/transport: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/client/listers/apiregistration/internalversion:go_default_library",
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1:go_default_library",
|
||||
"//pkg/apis/meta/v1:go_default_library",
|
||||
"//pkg/apiserver/request:go_default_library",
|
||||
"//pkg/auth/user:go_default_library",
|
||||
"//pkg/client/cache:go_default_library",
|
||||
"//pkg/client/listers/core/v1:go_default_library",
|
||||
"//pkg/runtime:go_default_library",
|
||||
"//pkg/util/diff:go_default_library",
|
||||
"//pkg/util/sets:go_default_library",
|
||||
|
|
|
@ -25,6 +25,9 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/rest"
|
||||
apiserverfilters "k8s.io/kubernetes/pkg/apiserver/filters"
|
||||
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"
|
||||
genericfilters "k8s.io/kubernetes/pkg/genericapiserver/filters"
|
||||
"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/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/informers"
|
||||
listers "k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/client/listers/apiregistration/internalversion"
|
||||
|
@ -44,7 +47,8 @@ import (
|
|||
const legacyAPIServiceName = "v1."
|
||||
|
||||
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
|
||||
// this to confirm the proxy's identity
|
||||
|
@ -73,6 +77,11 @@ type APIDiscoveryServer struct {
|
|||
// controller state
|
||||
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 *http.ServeMux
|
||||
}
|
||||
|
@ -100,16 +109,19 @@ func (c *Config) SkipComplete() completedConfig {
|
|||
func (c completedConfig) New() (*APIDiscoveryServer, error) {
|
||||
informerFactory := informers.NewSharedInformerFactory(
|
||||
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.
|
||||
)
|
||||
kubeInformers := kubeinformers.NewSharedInformerFactory(nil, c.CoreAPIServerClient, 5*time.Minute)
|
||||
|
||||
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
|
||||
c.Config.GenericConfig.BuildHandlerChainsFunc = (&handlerChainConfig{
|
||||
informers: informerFactory,
|
||||
proxyMux: proxyMux,
|
||||
informers: informerFactory,
|
||||
proxyMux: proxyMux,
|
||||
serviceLister: kubeInformers.Core().V1().Services().Lister(),
|
||||
endpointsLister: kubeInformers.Core().V1().Endpoints().Lister(),
|
||||
}).handlerChain
|
||||
|
||||
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,
|
||||
proxyHandlers: map[string]*proxyHandler{},
|
||||
lister: informerFactory.Apiregistration().InternalVersion().APIServices().Lister(),
|
||||
serviceLister: kubeInformers.Core().V1().Services().Lister(),
|
||||
endpointsLister: kubeInformers.Core().V1().Endpoints().Lister(),
|
||||
proxyMux: proxyMux,
|
||||
}
|
||||
|
||||
|
@ -141,6 +155,7 @@ func (c completedConfig) New() (*APIDiscoveryServer, error) {
|
|||
|
||||
s.GenericAPIServer.AddPostStartHook("start-informers", func(context genericapiserver.PostStartHookContext) error {
|
||||
informerFactory.Start(wait.NeverStop)
|
||||
kubeInformers.Start(wait.NeverStop)
|
||||
return nil
|
||||
})
|
||||
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
|
||||
type handlerChainConfig struct {
|
||||
informers informers.SharedInformerFactory
|
||||
proxyMux *http.ServeMux
|
||||
informers informers.SharedInformerFactory
|
||||
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
|
||||
|
@ -162,7 +179,7 @@ type handlerChainConfig struct {
|
|||
// 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) {
|
||||
// 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)
|
||||
|
||||
|
@ -223,8 +240,10 @@ func (s *APIDiscoveryServer) AddAPIService(apiService *apiregistration.APIServic
|
|||
// it's time to register the group discovery endpoint
|
||||
groupPath := "/apis/" + apiService.Spec.Group
|
||||
groupDiscoveryHandler := &apiGroupHandler{
|
||||
groupName: apiService.Spec.Group,
|
||||
lister: s.lister,
|
||||
groupName: apiService.Spec.Group,
|
||||
lister: s.lister,
|
||||
serviceLister: s.serviceLister,
|
||||
endpointsLister: s.endpointsLister,
|
||||
}
|
||||
// discovery is protected
|
||||
s.GenericAPIServer.HandlerContainer.UnlistedRoutes.Handle(groupPath, groupDiscoveryHandler)
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
apierrors "k8s.io/kubernetes/pkg/api/errors"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/apiserver"
|
||||
v1listers "k8s.io/kubernetes/pkg/client/listers/core/v1"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
|
||||
|
@ -34,10 +35,12 @@ import (
|
|||
)
|
||||
|
||||
// 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{
|
||||
lister: informer.Lister(),
|
||||
delegate: handler,
|
||||
lister: informer.Lister(),
|
||||
delegate: handler,
|
||||
serviceLister: serviceLister,
|
||||
endpointsLister: endpointsLister,
|
||||
}
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
apisHandler.ServeHTTP(w, req)
|
||||
|
@ -49,6 +52,9 @@ func WithAPIs(handler http.Handler, informer informers.APIServiceInformer) http.
|
|||
type apisHandler struct {
|
||||
lister listers.APIServiceLister
|
||||
|
||||
serviceLister v1listers.ServiceLister
|
||||
endpointsLister v1listers.EndpointsLister
|
||||
|
||||
delegate http.Handler
|
||||
}
|
||||
|
||||
|
@ -95,7 +101,10 @@ func (r *apisHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
if len(apiGroupServers[0].Spec.Group) == 0 {
|
||||
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)
|
||||
|
@ -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]
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
var discoveryGroup *metav1.APIGroup
|
||||
|
||||
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,
|
||||
metav1.GroupVersionForDiscovery{
|
||||
GroupVersion: apiService.Spec.Group + "/" + apiService.Spec.Version,
|
||||
|
@ -136,6 +173,9 @@ type apiGroupHandler struct {
|
|||
groupName string
|
||||
|
||||
lister listers.APIServiceLister
|
||||
|
||||
serviceLister v1listers.ServiceLister
|
||||
endpointsLister v1listers.EndpointsLister
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
|
|
@ -24,8 +24,10 @@ import (
|
|||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
corev1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
|
||||
"k8s.io/kubernetes/pkg/client/cache"
|
||||
v1listers "k8s.io/kubernetes/pkg/client/listers/core/v1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/diff"
|
||||
|
||||
|
@ -111,6 +113,10 @@ func TestAPIs(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "foo",
|
||||
Version: "v1",
|
||||
Priority: 10,
|
||||
|
@ -119,6 +125,10 @@ func TestAPIs(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "bar",
|
||||
Version: "v1",
|
||||
Priority: 11,
|
||||
|
@ -164,6 +174,10 @@ func TestAPIs(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "foo",
|
||||
Version: "v1",
|
||||
Priority: 20,
|
||||
|
@ -172,6 +186,10 @@ func TestAPIs(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v2.bar"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "bar",
|
||||
Version: "v2",
|
||||
Priority: 11,
|
||||
|
@ -180,6 +198,10 @@ func TestAPIs(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v2.foo"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "foo",
|
||||
Version: "v2",
|
||||
Priority: 1,
|
||||
|
@ -188,6 +210,10 @@ func TestAPIs(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "bar",
|
||||
Version: "v1",
|
||||
Priority: 11,
|
||||
|
@ -239,14 +265,26 @@ func TestAPIs(t *testing.T) {
|
|||
|
||||
for _, tc := range tests {
|
||||
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{}
|
||||
handler := &apisHandler{
|
||||
lister: listers.NewAPIServiceLister(indexer),
|
||||
delegate: delegate,
|
||||
serviceLister: v1listers.NewServiceLister(serviceIndexer),
|
||||
endpointsLister: v1listers.NewEndpointsLister(endpointsIndexer),
|
||||
lister: listers.NewAPIServiceLister(indexer),
|
||||
delegate: delegate,
|
||||
}
|
||||
for _, o := range tc.apiservices {
|
||||
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)
|
||||
defer server.Close()
|
||||
|
@ -316,6 +354,10 @@ func TestAPIGroup(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v1.foo"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "foo",
|
||||
Version: "v1",
|
||||
Priority: 20,
|
||||
|
@ -324,6 +366,10 @@ func TestAPIGroup(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v2.bar"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "bar",
|
||||
Version: "v2",
|
||||
Priority: 11,
|
||||
|
@ -332,6 +378,10 @@ func TestAPIGroup(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v2.foo"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "foo",
|
||||
Version: "v2",
|
||||
Priority: 1,
|
||||
|
@ -340,6 +390,10 @@ func TestAPIGroup(t *testing.T) {
|
|||
{
|
||||
ObjectMeta: api.ObjectMeta{Name: "v1.bar"},
|
||||
Spec: apiregistration.APIServiceSpec{
|
||||
Service: apiregistration.ServiceReference{
|
||||
Namespace: "ns",
|
||||
Name: "api",
|
||||
},
|
||||
Group: "bar",
|
||||
Version: "v1",
|
||||
Priority: 11,
|
||||
|
@ -369,13 +423,25 @@ func TestAPIGroup(t *testing.T) {
|
|||
|
||||
for _, tc := range tests {
|
||||
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{
|
||||
lister: listers.NewAPIServiceLister(indexer),
|
||||
groupName: "foo",
|
||||
lister: listers.NewAPIServiceLister(indexer),
|
||||
serviceLister: v1listers.NewServiceLister(serviceIndexer),
|
||||
endpointsLister: v1listers.NewEndpointsLister(endpointsIndexer),
|
||||
groupName: "foo",
|
||||
}
|
||||
for _, o := range tc.apiservices {
|
||||
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)
|
||||
defer server.Close()
|
||||
|
@ -386,8 +452,8 @@ func TestAPIGroup(t *testing.T) {
|
|||
continue
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
httputil.DumpResponse(resp, true)
|
||||
t.Errorf("%s", tc.name)
|
||||
response, _ := httputil.DumpResponse(resp, true)
|
||||
t.Errorf("%s: %v", tc.name, string(response))
|
||||
continue
|
||||
}
|
||||
bytes, err := ioutil.ReadAll(resp.Body)
|
||||
|
|
|
@ -16,6 +16,8 @@ go_library(
|
|||
"//cmd/kubernetes-discovery/pkg/apiserver:go_default_library",
|
||||
"//cmd/kubernetes-discovery/pkg/legacy: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/filters: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/legacy"
|
||||
"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/filters"
|
||||
genericoptions "k8s.io/kubernetes/pkg/genericapiserver/options"
|
||||
|
@ -135,9 +137,19 @@ func (o DiscoveryServerOptions) RunDiscoveryServer() error {
|
|||
return err
|
||||
}
|
||||
|
||||
kubeconfig, err := restclient.InClusterConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
coreAPIServerClient, err := kubeclientset.NewForConfig(kubeconfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config := apiserver.Config{
|
||||
GenericConfig: genericAPIServerConfig,
|
||||
RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.Etcd.StorageConfig},
|
||||
GenericConfig: genericAPIServerConfig,
|
||||
RESTOptionsGetter: &restOptionsFactory{storageConfig: &o.Etcd.StorageConfig},
|
||||
CoreAPIServerClient: coreAPIServerClient,
|
||||
}
|
||||
|
||||
config.ProxyClientCert, err = ioutil.ReadFile(o.ProxyClientCertFile)
|
||||
|
|
|
@ -59,7 +59,9 @@ function start_discovery {
|
|||
|
||||
# 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: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:kubernetes-discovery --clusterrole=system:kubernetes-discovery --serviceaccount=kube-public:kubernetes-discovery
|
||||
|
||||
# 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
|
||||
|
|
|
@ -230,6 +230,14 @@ func ClusterRoles() []rbac.ClusterRole {
|
|||
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
|
||||
// service accounts, and secrets that we need to create separate identities for other controllers
|
||||
|
|
|
@ -469,6 +469,24 @@ items:
|
|||
verbs:
|
||||
- list
|
||||
- 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
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
|
|
Loading…
Reference in New Issue