11package  kubernetes
22
33import  (
4- 	"context" 
5- 	"errors" 
6- 	"strings" 
7- 
84	"k8s.io/apimachinery/pkg/runtime" 
95
10- 	"github.com/fsnotify/fsnotify" 
11- 
12- 	"k8s.io/apimachinery/pkg/api/meta" 
13- 	"k8s.io/client-go/discovery" 
14- 	"k8s.io/client-go/discovery/cached/memory" 
15- 	"k8s.io/client-go/dynamic" 
16- 	"k8s.io/client-go/kubernetes/scheme" 
17- 	"k8s.io/client-go/rest" 
18- 	"k8s.io/client-go/restmapper" 
19- 	"k8s.io/client-go/tools/clientcmd" 
20- 	clientcmdapi "k8s.io/client-go/tools/clientcmd/api" 
21- 	"k8s.io/klog/v2" 
22- 
23- 	"github.com/containers/kubernetes-mcp-server/pkg/config" 
246	"github.com/containers/kubernetes-mcp-server/pkg/helm" 
7+ 	"k8s.io/client-go/kubernetes/scheme" 
258
269	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc" 
2710)
@@ -47,174 +30,9 @@ func (k *Kubernetes) AccessControlClientset() *AccessControlClientset {
4730	return  k .manager .accessControlClientSet 
4831}
4932
50- type  Manager  struct  {
51- 	cfg                      * rest.Config 
52- 	clientCmdConfig          clientcmd.ClientConfig 
53- 	discoveryClient          discovery.CachedDiscoveryInterface 
54- 	accessControlClientSet   * AccessControlClientset 
55- 	accessControlRESTMapper  * AccessControlRESTMapper 
56- 	dynamicClient            * dynamic.DynamicClient 
57- 
58- 	staticConfig          * config.StaticConfig 
59- 	CloseWatchKubeConfig  CloseWatchKubeConfig 
60- }
61- 
62- var  _  helm.Kubernetes  =  (* Manager )(nil )
63- var  _  Openshift  =  (* Manager )(nil )
64- 
6533var  Scheme  =  scheme .Scheme 
6634var  ParameterCodec  =  runtime .NewParameterCodec (Scheme )
6735
68- func  NewManager (config  * config.StaticConfig ) (* Manager , error ) {
69- 	k8s  :=  & Manager {
70- 		staticConfig : config ,
71- 	}
72- 	if  err  :=  resolveKubernetesConfigurations (k8s ); err  !=  nil  {
73- 		return  nil , err 
74- 	}
75- 	// TODO: Won't work because not all client-go clients use the shared context (e.g. discovery client uses context.TODO()) 
76- 	//k8s.cfg.Wrap(func(original http.RoundTripper) http.RoundTripper { 
77- 	//	return &impersonateRoundTripper{original} 
78- 	//}) 
79- 	var  err  error 
80- 	k8s .accessControlClientSet , err  =  NewAccessControlClientset (k8s .cfg , k8s .staticConfig )
81- 	if  err  !=  nil  {
82- 		return  nil , err 
83- 	}
84- 	k8s .discoveryClient  =  memory .NewMemCacheClient (k8s .accessControlClientSet .DiscoveryClient ())
85- 	k8s .accessControlRESTMapper  =  NewAccessControlRESTMapper (
86- 		restmapper .NewDeferredDiscoveryRESTMapper (k8s .discoveryClient ),
87- 		k8s .staticConfig ,
88- 	)
89- 	k8s .dynamicClient , err  =  dynamic .NewForConfig (k8s .cfg )
90- 	if  err  !=  nil  {
91- 		return  nil , err 
92- 	}
93- 	return  k8s , nil 
94- }
95- 
96- func  (m  * Manager ) WatchKubeConfig (onKubeConfigChange  func () error ) {
97- 	if  m .clientCmdConfig  ==  nil  {
98- 		return 
99- 	}
100- 	kubeConfigFiles  :=  m .clientCmdConfig .ConfigAccess ().GetLoadingPrecedence ()
101- 	if  len (kubeConfigFiles ) ==  0  {
102- 		return 
103- 	}
104- 	watcher , err  :=  fsnotify .NewWatcher ()
105- 	if  err  !=  nil  {
106- 		return 
107- 	}
108- 	for  _ , file  :=  range  kubeConfigFiles  {
109- 		_  =  watcher .Add (file )
110- 	}
111- 	go  func () {
112- 		for  {
113- 			select  {
114- 			case  _ , ok  :=  <- watcher .Events :
115- 				if  ! ok  {
116- 					return 
117- 				}
118- 				_  =  onKubeConfigChange ()
119- 			case  _ , ok  :=  <- watcher .Errors :
120- 				if  ! ok  {
121- 					return 
122- 				}
123- 			}
124- 		}
125- 	}()
126- 	if  m .CloseWatchKubeConfig  !=  nil  {
127- 		_  =  m .CloseWatchKubeConfig ()
128- 	}
129- 	m .CloseWatchKubeConfig  =  watcher .Close 
130- }
131- 
132- func  (m  * Manager ) Close () {
133- 	if  m .CloseWatchKubeConfig  !=  nil  {
134- 		_  =  m .CloseWatchKubeConfig ()
135- 	}
136- }
137- 
138- func  (m  * Manager ) GetAPIServerHost () string  {
139- 	if  m .cfg  ==  nil  {
140- 		return  "" 
141- 	}
142- 	return  m .cfg .Host 
143- }
144- 
145- func  (m  * Manager ) ToDiscoveryClient () (discovery.CachedDiscoveryInterface , error ) {
146- 	return  m .discoveryClient , nil 
147- }
148- 
149- func  (m  * Manager ) ToRESTMapper () (meta.RESTMapper , error ) {
150- 	return  m .accessControlRESTMapper , nil 
151- }
152- 
153- func  (m  * Manager ) Derived (ctx  context.Context ) (* Kubernetes , error ) {
154- 	authorization , ok  :=  ctx .Value (OAuthAuthorizationHeader ).(string )
155- 	if  ! ok  ||  ! strings .HasPrefix (authorization , "Bearer " ) {
156- 		if  m .staticConfig .RequireOAuth  {
157- 			return  nil , errors .New ("oauth token required" )
158- 		}
159- 		return  & Kubernetes {manager : m }, nil 
160- 	}
161- 	klog .V (5 ).Infof ("%s header found (Bearer), using provided bearer token" , OAuthAuthorizationHeader )
162- 	derivedCfg  :=  & rest.Config {
163- 		Host :    m .cfg .Host ,
164- 		APIPath : m .cfg .APIPath ,
165- 		// Copy only server verification TLS settings (CA bundle and server name) 
166- 		TLSClientConfig : rest.TLSClientConfig {
167- 			Insecure :   m .cfg .Insecure ,
168- 			ServerName : m .cfg .ServerName ,
169- 			CAFile :     m .cfg .CAFile ,
170- 			CAData :     m .cfg .CAData ,
171- 		},
172- 		BearerToken : strings .TrimPrefix (authorization , "Bearer " ),
173- 		// pass custom UserAgent to identify the client 
174- 		UserAgent :   CustomUserAgent ,
175- 		QPS :         m .cfg .QPS ,
176- 		Burst :       m .cfg .Burst ,
177- 		Timeout :     m .cfg .Timeout ,
178- 		Impersonate : rest.ImpersonationConfig {},
179- 	}
180- 	clientCmdApiConfig , err  :=  m .clientCmdConfig .RawConfig ()
181- 	if  err  !=  nil  {
182- 		if  m .staticConfig .RequireOAuth  {
183- 			klog .Errorf ("failed to get kubeconfig: %v" , err )
184- 			return  nil , errors .New ("failed to get kubeconfig" )
185- 		}
186- 		return  & Kubernetes {manager : m }, nil 
187- 	}
188- 	clientCmdApiConfig .AuthInfos  =  make (map [string ]* clientcmdapi.AuthInfo )
189- 	derived  :=  & Kubernetes {manager : & Manager {
190- 		clientCmdConfig : clientcmd .NewDefaultClientConfig (clientCmdApiConfig , nil ),
191- 		cfg :             derivedCfg ,
192- 		staticConfig :    m .staticConfig ,
193- 	}}
194- 	derived .manager .accessControlClientSet , err  =  NewAccessControlClientset (derived .manager .cfg , derived .manager .staticConfig )
195- 	if  err  !=  nil  {
196- 		if  m .staticConfig .RequireOAuth  {
197- 			klog .Errorf ("failed to get kubeconfig: %v" , err )
198- 			return  nil , errors .New ("failed to get kubeconfig" )
199- 		}
200- 		return  & Kubernetes {manager : m }, nil 
201- 	}
202- 	derived .manager .discoveryClient  =  memory .NewMemCacheClient (derived .manager .accessControlClientSet .DiscoveryClient ())
203- 	derived .manager .accessControlRESTMapper  =  NewAccessControlRESTMapper (
204- 		restmapper .NewDeferredDiscoveryRESTMapper (derived .manager .discoveryClient ),
205- 		derived .manager .staticConfig ,
206- 	)
207- 	derived .manager .dynamicClient , err  =  dynamic .NewForConfig (derived .manager .cfg )
208- 	if  err  !=  nil  {
209- 		if  m .staticConfig .RequireOAuth  {
210- 			klog .Errorf ("failed to initialize dynamic client: %v" , err )
211- 			return  nil , errors .New ("failed to initialize dynamic client" )
212- 		}
213- 		return  & Kubernetes {manager : m }, nil 
214- 	}
215- 	return  derived , nil 
216- }
217- 
21836func  (k  * Kubernetes ) NewHelm () * helm.Helm  {
21937	// This is a derived Kubernetes, so it already has the Helm initialized 
22038	return  helm .NewHelm (k .manager )
0 commit comments